diff --git a/coverage.svg b/coverage.svg index e460277f21..2a5ae9720a 100644 --- a/coverage.svg +++ b/coverage.svg @@ -1 +1 @@ -coverage: 73.28%coverage73.28% \ No newline at end of file +coverage: 73.38%coverage73.38% \ No newline at end of file diff --git a/doc/.timestamp b/doc/.timestamp index 9e568e61ee..659cb4ecab 100644 --- a/doc/.timestamp +++ b/doc/.timestamp @@ -1 +1 @@ -Wed Jan 10 11:24:25 UTC 2024 +Mon Jan 22 13:02:50 UTC 2024 diff --git a/doc/gotham_restful/struct.Raw.html b/doc/gotham_restful/struct.Raw.html index 4f871635ce..73a31b66bc 100644 --- a/doc/gotham_restful/struct.Raw.html +++ b/doc/gotham_restful/struct.Raw.html @@ -18,15 +18,15 @@ }

Fields§

§raw: T§mime: Mime

Implementations§

source§

impl<T> Raw<T>

source

pub fn new(raw: T, mime: Mime) -> Self

Trait Implementations§

source§

impl<T, U> AsMut<U> for Raw<T>where T: AsMut<U>,

source§

fn as_mut(&mut self) -> &mut U

Converts this type into a mutable reference of the (usually inferred) input type.
source§

impl<T, U> AsRef<U> for Raw<T>where - T: AsRef<U>,

source§

fn as_ref(&self) -> &U

Converts this type into a shared reference of the (usually inferred) input type.
source§

impl<T: Clone> Clone for Raw<T>

source§

fn clone(&self) -> Self

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl<T: Debug> Debug for Raw<T>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<T: for<'a> From<&'a [u8]>> FromBody for Raw<T>

§

type Err = Infallible

The error type returned by the conversion if it was unsuccessfull. When using the derive + T: AsRef<U>,
source§

fn as_ref(&self) -> &U

Converts this type into a shared reference of the (usually inferred) input type.
source§

impl<T: Clone> Clone for Raw<T>

source§

fn clone(&self) -> Self

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl<T: Debug> Debug for Raw<T>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<T: for<'a> From<&'a [u8]>> FromBody for Raw<T>

§

type Err = Infallible

The error type returned by the conversion if it was unsuccessfull. When using the derive macro, there is no way to trigger an error, so std::convert::Infallible is used here. However, this might change in the future.
source§

fn from_body(body: Bytes, mime: Mime) -> Result<Self, Self::Err>

Perform the conversion.
source§

impl<T: Into<Body>> IntoResponse for Raw<T>where - Self: Send,

§

type Err = Error

source§

fn into_response( + Self: Send,

§

type Err = Error

source§

fn into_response( self ) -> Pin<Box<dyn Future<Output = Result<Response, SerdeJsonError>> + Send>>

Turn this into a response that can be returned to the browser. This api will likely -change in the future.
source§

fn accepted_types() -> Option<Vec<Mime>>

Return a list of supported mime types.
source§

impl<T> OpenapiType for Raw<T>

source§

fn visit_type<V: Visitor>(visitor: &mut V)

§

fn schema() -> OpenapiSchema

source§

impl<T> RequestBody for Raw<T>where +change in the future.

source§

fn accepted_types() -> Option<Vec<Mime>>

Return a list of supported mime types.
source§

impl<T> OpenapiType for Raw<T>

source§

fn visit_type<V: Visitor>(visitor: &mut V)

§

fn schema() -> OpenapiSchema

source§

impl<T> RequestBody for Raw<T>where Raw<T>: FromBody + ResourceType,

source§

fn supported_types() -> Option<Vec<Mime>>

Return all types that are supported as content types. Use None if all types are supported.
source§

impl<T: Into<Body>> ResponseSchema for Raw<T>where - Self: Send,

source§

fn schema(code: StatusCode) -> OpenapiSchema

Return the schema of the response for the given status code. The code may + Self: Send,
source§

fn schema(code: StatusCode) -> OpenapiSchema

Return the schema of the response for the given status code. The code may only be one that was previously returned by Self::status_codes. The implementation should panic if that is not the case.
source§

fn status_codes() -> Vec<StatusCode>

All status codes returned by this response. Returns [StatusCode::OK] by default.

Auto Trait Implementations§

§

impl<T> RefUnwindSafe for Raw<T>where T: RefUnwindSafe,

§

impl<T> Send for Raw<T>where diff --git a/doc/search-index.js b/doc/search-index.js index 42f047c297..b077ee04e5 100644 --- a/doc/search-index.js +++ b/doc/search-index.js @@ -1,5 +1,5 @@ var searchIndex = JSON.parse('{\ -"gotham_restful":{"doc":"This crate is an extension to the popular gotham web …","t":"DEIDGEEGGNNQQNCCIIIIIINNQQQNIYINIIINDDNNDNQQQQQQDDIYIYYIDIIDDNNILLLLMLLMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLAXLLLXXLLLKKXLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKLLLLCKKCLLLLLLLLLKKLLLLLLLLLLLLLKLLLLLKLLMLKLMLMLLLLLLLLLLLLLLLKKLLKMXXMKKKKLLLLLLXKKLKLLLLLLMLLLLLLMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLXXKKMMMMLLLLLLKNNDIENNNENNLLLLLLLLLLLLLLLKMLLLLLLLLLFMLLLMLMLLLLLLLLLLLLLLLL","n":["AuthError","AuthErrorOrOther","AuthHandler","AuthMiddleware","AuthResult","AuthSource","AuthStatus","AuthSuccess","AuthValidation","Authenticated","AuthorizationHeader","Body","Body","Cookie","CorsConfig","CorsRoute","DrawResourceRoutes","DrawResourceRoutesWithSchema","DrawResources","DrawResourcesWithSchema","Endpoint","EndpointWithSchema","Err","Err","Err","Err","Err","Forbidden","FromBody","FromBody","GetOpenapi","Header","IntoResponse","IntoResponseError","IntoResponseWithSchema","Invalid","NoContent","NoopExtractor","Ok","Ok","OpenapiInfo","Other","Output","Output","Params","Params","Placeholders","Placeholders","Raw","Redirect","RequestBody","RequestBody","Resource","Resource","ResourceError","ResourceWithSchema","Response","ResponseBody","ResponseSchema","StaticAuthHandler","Success","Unauthenticated","Unknown","WithOpenapi","accepted_types","accepted_types","accepted_types","accepted_types","algorithms","as_mut","as_ref","aud","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow_from","borrow_from","borrow_from","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut_from","borrow_mut_from","borrow_mut_from","call","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","cors","create","default","default","default","delete","delete_all","description","description","deserialize","endpoint","endpoint","endpoint","extend","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","forbidden","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from_array","from_body","from_body","from_body","from_source","from_vec","gotham","handle","handle","handle_cors","has_placeholders","has_placeholders","has_placeholders","has_placeholders","header","header","header","headers_mut","headers_mut","http_method","http_method","into","into","into","into","into","into","into","into","into","into","into","into","into","into_response","into_response","into_response","into_response","into_response","into_response","into_response_error","into_response_error","into_response_error","iss","json","jwt_secret","jwt_secret","leeway","mime","mime","needs_body","needs_body","needs_body","needs_body","needs_params","needs_params","needs_params","needs_params","new","new","new","new","new_middleware","no_content","ok","openapi_doc","openapi_spec","operation_id","operation_id","operation_verb","raw","read","read_all","required_spec_claims","resource","resource","schema","schema","schema","schema","schema","schema","schema","schema","search","setup","setup","status","status_codes","status_codes","status_codes","status_codes","status_codes","status_codes","status_codes","sub","supported_types","supported_types","supported_types","take_from","take_from","take_from","title","to","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","try_borrow_from","try_borrow_from","try_borrow_from","try_borrow_mut_from","try_borrow_mut_from","try_borrow_mut_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_take_from","try_take_from","try_take_from","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","update","update_all","uri","uri","urls","validate_exp","validate_nbf","version","visit_type","visit_type","wants_auth","wants_auth","wants_auth","wants_auth","with_openapi","Copy","Copy","CorsConfig","CorsRoute","Headers","List","None","None","Origin","Single","Star","borrow","borrow","borrow","borrow_from","borrow_mut","borrow_mut","borrow_mut","borrow_mut_from","call","clone","clone","clone","clone_into","clone_into","clone_into","cors","credentials","default","default","default","fmt","fmt","fmt","from","from","from","handle_cors","headers","into","into","into","max_age","new_middleware","origin","take_from","to_owned","to_owned","to_owned","try_borrow_from","try_borrow_mut_from","try_from","try_from","try_from","try_into","try_into","try_into","try_take_from","type_id","type_id","type_id"],"q":[[0,"gotham_restful"],[355,"gotham_restful::cors"],[416,"mime"],[417,"alloc::vec"],[418,"core::option"],[419,"core::convert"],[420,"core::convert"],[421,"gotham::handler"],[422,"alloc::boxed"],[423,"core::pin"],[424,"serde::de"],[425,"core::marker"],[426,"core::ops::function"],[427,"core::clone"],[428,"core::default"],[429,"alloc::string"],[430,"core::result"],[431,"serde::de"],[432,"http::response"],[433,"core::fmt"],[434,"core::fmt"],[435,"core::convert"],[436,"http::header::value"],[437,"http::header::map::into_header_name"],[438,"http::header::name"],[439,"http::header::map"],[440,"http::method"],[441,"core::future::future"],[442,"http::status"],[443,"anyhow"],[444,"openapi_type::visitor::openapi"],[445,"core::any"],[446,"alloc::borrow"],[447,"openapi_type::visitor"]],"d":["This is an error type that always yields a 403 Forbidden …","This is an error type that either yields a 403 Forbidden …","This trait will help the auth middleware to determine the …","This is the auth middleware. To use it, first make sure …","This return type can be used to wrap any type implementing …","The source of the authentication token in the request.","The authentication status returned by the auth middleware …","This return type can be used to wrap any type implementing …","","The request has been performed with a valid …","Take the token from the HTTP Authorization header. This is …","The type to parse the body into. Use () if needs_body() …","The type to parse the body into. Use () if needs_body() …","Take the token from a cookie with the given name.","","","This trait allows to draw routes within an resource. Use …","This trait allows to draw routes within an resource. Use …","This trait adds the resource method to gotham’s routing. …","This trait adds the resource method to gotham’s routing. …","","","Contains the error value","Contains the error value","","","The error type returned by the conversion if it was …","","This trait should be implemented for every type that can …","","This trait adds the openapi_spec and openapi_doc method to …","Take the token from a header with the given name.","This trait needs to be implemented by every type returned …","","A trait provided to convert a resource’s result to json, …","The request has been performed with an invalid …","This is the return type of a resource that doesn’t …","A no-op extractor that can be used as a default type for …","Contains the success value","Contains the success value","","","The output type that provides the response.","The output type that provides the response.","The type that parses the request parameters. Use …","The type that parses the request parameters. Use …","The type that parses the URI placeholders. Use …","The type that parses the URI placeholders. Use …","This type can be used both as a raw request body, as well …","This is the return type of a resource that only returns a …","A type that can be used inside a request body. Implemented …","","This trait must be implemented for every resource. It …","","","This trait must be implemented for every resource. It …","A response, used to create the final gotham response from.","A type that can be used inside a response body. …","Additional details for IntoResponse to be used with an …","An AuthHandler returning always the same secret. See …","This can be returned from a resource when there is no …","The request has been performed without any kind of …","The auth status is unknown. This is likely because no …","This trait adds the with_openapi method to gotham’s …","Return a list of supported mime types.","Return a list of supported mime types.","","","The validation will check that the alg of the header is …","","","If it contains a value, the validation will check that the …","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Add a description to the openapi specification. Usually …","Add a description to the openapi specification. Usually …","","","","","","","","","","","","","","","","","","","Create an empty 403 Forbidden Response.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","","Returns the argument unchanged.","","","Returns the argument unchanged.","","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","","","Returns the argument unchanged.","","Perform the conversion.","","","","","","The handler for this endpoint.","The handler for this endpoint.","","Returns true iff the URI contains placeholders. false by …","Returns true iff the URI contains placeholders. false by …","Returns true iff the URI contains placeholders. false by …","Returns true iff the URI contains placeholders. false by …","Set a custom HTTP header. If a header with this name was …","Set a custom HTTP header. If a header with this name was …","Add an HTTP header to the Response.","Allow manipulating HTTP headers.","Allow manipulating HTTP headers.","The HTTP Verb of this endpoint.","The HTTP Verb of this endpoint.","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Turn this into a response that can be returned to the …","This will always be a 204 No Content together with an …","","","","","","","","If it contains a value, the validation will check that the …","Create a Response with mime type json from already …","Return the SHA256-HMAC secret used to verify the JWT token.","","Add some leeway (in seconds) to the exp and nbf validation …","Return the mime type of this Response.","","Returns true iff the request body should be parsed. false …","Returns true iff the request body should be parsed. false …","Returns true iff the request body should be parsed. false …","Returns true iff the request body should be parsed. false …","Returns true iff the request parameters should be parsed. …","Returns true iff the request parameters should be parsed. …","Returns true iff the request parameters should be parsed. …","Returns true iff the request parameters should be parsed. …","","","","Create a new Response from raw data.","","Create a 204 No Content Response.","","Register a GET route to path that returns the OpenAPI …","Register a GET route to path that returns the OpenAPI …","Replace the automatically generated operation id with a …","Replace the automatically generated operation id with a …","The verb used for generating an operation id if …","","","","Which claims are required to be present before starting …","","","","Return the schema of the response for the given status …","","","Returns the schema of the () type.","","","","","Register all methods handled by this resource with the …","Register all methods handled by this resource with the …","Return the status code of this Response.","","All status codes returned by this response. Returns …","All status codes returned by this response. Returns …","","","","","If it contains a value, the validation will check that the …","Return all types that are supported as content types. Use …","Return all types that are supported as content types. Use …","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","The URI that this endpoint listens on in gotham’s format.","The URI that this endpoint listens on in gotham’s format.","","Whether to validate the exp field.","Whether to validate the nbf field.","","","","Returns true if the request wants to know the auth status …","Returns true if the request wants to know the auth status …","Returns true if the request wants to know the auth status …","Returns true if the request wants to know the auth status …","","Copy the Origin header into the Access-Control-Allow-Origin…","Copy the Access-Control-Request-Headers header into the …","This is the configuration that the CORS handler will …","Add CORS routing for your path. This is required for …","Specify the allowed headers of the request. It is up to …","Set the Access-Control-Allow-Headers header to the …","Do not send any Access-Control-Allow-Origin headers.","Do not send any Access-Control-Allow-Headers headers.","Specify the allowed origins of the request. It is up to …","Set the Access-Control-Allow-Origin header to a single …","Send Access-Control-Allow-Origin: *. Note that browser …","","","","","","","","","","","","","","","","Handle a preflight request on path for method. To …","Whether or not the request may be made with supplying …","","","","","","","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Handle CORS for a non-preflight request. This means …","The allowed headers.","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","The amount of seconds that the preflight request can be …","","The allowed origins.","","","","","","","","","","","","","","","",""],"i":[0,0,0,0,0,0,0,0,0,16,18,66,67,18,0,0,0,0,0,0,0,0,68,69,70,71,72,23,0,0,0,18,0,0,0,16,0,0,68,69,0,23,66,67,66,67,66,67,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,0,71,71,24,26,54,4,4,54,16,18,19,8,20,21,22,23,24,4,25,26,37,16,18,21,16,18,19,8,20,21,22,23,24,4,25,26,37,16,18,21,8,16,18,19,8,20,21,22,23,24,4,25,26,16,18,19,8,20,21,22,23,24,4,25,26,0,0,24,25,26,0,0,67,67,21,58,59,0,21,16,18,19,8,20,21,22,23,24,4,25,26,37,37,16,18,19,8,20,21,22,23,23,23,23,24,24,4,25,26,26,26,37,19,72,21,4,8,19,0,66,67,0,66,66,67,67,24,26,37,24,26,66,67,16,18,19,8,20,21,22,23,24,4,25,26,37,71,24,4,25,26,37,70,22,23,54,37,14,19,54,37,4,66,66,67,67,66,66,67,67,8,22,4,37,8,37,16,73,73,67,67,67,4,0,0,54,74,75,70,76,22,23,24,4,25,26,0,77,78,37,70,76,76,22,23,24,25,54,79,79,21,16,18,21,20,25,16,18,19,8,20,21,22,23,24,4,25,26,16,18,21,16,18,21,16,18,19,8,20,21,22,23,24,4,25,26,37,16,18,19,8,20,21,22,23,24,4,25,26,37,16,18,21,16,18,19,8,20,21,22,23,24,4,25,26,37,0,0,66,67,20,54,54,20,21,4,66,66,67,67,80,64,65,0,0,0,65,64,65,0,64,64,64,65,63,63,64,65,63,63,63,64,65,63,64,65,63,81,63,64,65,63,64,65,63,64,65,63,0,63,64,65,63,63,63,63,63,64,65,63,63,63,64,65,63,64,65,63,63,64,65,63],"f":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,[[],[[3,[[2,[1]]]]]],[[],[[3,[[2,[1]]]]]],[[],[[3,[[2,[1]]]]]],[[],[[3,[[2,[1]]]]]],0,[[[4,[-2]]],-1,[],[[5,[-1]]]],[[[4,[-2]]],-1,[],[[6,[-1]]]],0,[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[7,-1,[]],[7,-1,[]],[7,-1,[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[7,-1,[]],[7,-1,[]],[7,-1,[]],[[[8,[-1,-2]],7,-3],[[11,[[10,[9]]]]],[12,13],[[14,[-1]]],15],[[[16,[-1]]],[[16,[-1]]],[17,13]],[18,18],[19,19],[[[8,[-1,-2]]],[[8,[-1,-2]]],[],17],[20,20],[21,21],[22,22],[[[23,[-1]]],[[23,[-1]]],17],[24,24],[[[4,[-1]]],[[4,[-1]]],17],[25,25],[[[26,[-1]]],[[26,[-1]]],17],[[-1,-2],27,[],[]],[[-1,-2],27,[],[]],[[-1,-2],27,[],[]],[[-1,-2],27,[],[]],[[-1,-2],27,[],[]],[[-1,-2],27,[],[]],[[-1,-2],27,[],[]],[[-1,-2],27,[],[]],[[-1,-2],27,[],[]],[[-1,-2],27,[],[]],[[-1,-2],27,[],[]],[[-1,-2],27,[],[]],0,0,[[],24],[[],25],[[],[[26,[-1]]],28],0,0,[[],[[3,[29]]]],[[],[[3,[29]]]],[-1,[[30,[21]]],31],[-1,27,[]],[-1,27,[]],0,[[7,[33,[32]]],27],[[[16,[-1]],34],35,[36,13]],[[18,34],35],[[19,34],35],[[[8,[-1,-2]],34],35,36,36],[[20,34],35],[[21,34],35],[[22,34],35],[[[23,[-1]],34],35,36],[[24,34],35],[[[4,[-1]],34],35,36],[[25,34],35],[[[26,[-1]],34],35,36],[[37,34],35],[[],37],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-2,[[23,[-1]]],[],[0,[38,[-1]]]],[-1,-1,[]],[39,-1,[]],[22,[[23,[-1]]],[]],[-1,-1,[]],[27,24],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,[[26,[-1]]],[]],[39,-1,[]],[-1,-1,[]],[[[41,[40]]],19],[[42,1],[[30,[-1]]],[]],[[42,1],[[30,[-1]]],[]],[[42,1],[[30,[[4,[-1]]]]],[[43,[[41,[40]]]]]],[18,[[8,[-1,-2]]],[12,13],[[14,[-1]],28]],[[[2,[40]]],19],0,[[7,3],44],[[7,3],44],0,[[],45],[[],45],[[],45],[[],45],[[24,-1,46],27,47],[[[26,[-1]],-2,46],27,[],47],[[37,48,46],27],[24,49],[[[26,[-1]]],49,[]],[[],50],[[],50],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,[[44,[[30,[37]]]]],[]],[24,[[11,[[10,[51]]]]]],[[[4,[-1]]],[[11,[[10,[51]]]]],[[38,[32]]]],[25,[[44,[[30,[37]]]]]],[[[26,[-1]]],[[11,[[10,[51]]]]],52],[37,[[44,[[30,[37]]]]]],[-1,[[30,[37]]],[]],[22,[[30,[37]]]],[[[23,[-1]]],[[30,[37]]],[]],0,[[53,-1],37,[[38,[32]]]],[[-1,7,-2],[[3,[[2,[40]]]]],[],15],[[19,7,-1],[[3,[[2,[40]]]]],15],0,[37,[[3,[1]]]],0,[[],45],[[],45],[[],45],[[],45],[[],45],[[],45],[[],45],[[],45],[[18,54,-2],[[8,[-1,-2]]],[12,13],[[14,[-1]]]],[-1,22,[[38,[29]]]],[[-1,1],[[4,[-1]]],[]],[[53,-1,[3,[1]]],37,[[38,[32]]]],[[[8,[-1,-2]]],[[55,[[8,[-1,-2]]]]],[],[]],[[],37],[[[16,[-1]]],[[30,[-1,22]]],13],[[-1,56],27,[]],[[-1,56],27,[]],[[],[[3,[29]]]],[[],[[3,[29]]]],[[],[[3,[56]]]],0,0,0,0,[[-1,56],27,[]],[[-1,56],27,[]],[53,57],[53,57],[53,57],[53,57],[53,57],[53,57],[53,57],[53,57],0,[-1,27,58],[-1,27,59],[37,53],[[],[[2,[53]]]],[[],[[2,[53]]]],[[],[[2,[53]]]],[[],[[2,[53]]]],[[],[[2,[53]]]],[[],[[2,[53]]]],[[],[[2,[53]]]],0,[[],[[3,[[2,[1]]]]]],[[],[[3,[[2,[1]]]]]],[[],[[3,[[2,[1]]]]]],[7,-1,[]],[7,-1,[]],[7,-1,[]],0,0,[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[7,[[3,[-1]]],[]],[7,[[3,[-1]]],[]],[7,[[3,[-1]]],[]],[7,[[3,[-1]]],[]],[7,[[3,[-1]]],[]],[7,[[3,[-1]]],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[7,[[3,[-1]]],[]],[7,[[3,[-1]]],[]],[7,[[3,[-1]]],[]],[-1,60,[]],[-1,60,[]],[-1,60,[]],[-1,60,[]],[-1,60,[]],[-1,60,[]],[-1,60,[]],[-1,60,[]],[-1,60,[]],[-1,60,[]],[-1,60,[]],[-1,60,[]],[-1,60,[]],0,0,[[],[[61,[56]]]],[[],[[61,[56]]]],0,0,0,0,[-1,27,62],[-1,27,62],[[],45],[[],45],[[],45],[[],45],[[-1,20,-2],27,[],15],0,0,0,0,0,0,0,0,0,0,0,[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[7,-1,[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[7,-1,[]],[[63,7,-1],[[11,[[10,[9]]]]],15],[64,64],[65,65],[63,63],[[-1,-2],27,[],[]],[[-1,-2],27,[],[]],[[-1,-2],27,[],[]],[[-1,56,50],27,[]],0,[[],64],[[],65],[[],63],[[64,34],35],[[65,34],35],[[63,34],35],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[[7,[33,[32]]],27],0,[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],0,[63,[[55,[63]]]],0,[7,-1,[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[7,[[3,[-1]]],[]],[7,[[3,[-1]]],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[7,[[3,[-1]]],[]],[-1,60,[]],[-1,60,[]],[-1,60,[]]],"c":[],"p":[[3,"Mime",416],[3,"Vec",417],[4,"Option",418],[3,"Raw",0],[8,"AsMut",419],[8,"AsRef",419],[3,"State",420],[3,"AuthMiddleware",0],[6,"HandlerFuture",421],[3,"Box",422],[3,"Pin",423],[8,"DeserializeOwned",424],[8,"Send",425],[8,"AuthHandler",0],[8,"FnOnce",426],[4,"AuthStatus",0],[8,"Clone",427],[4,"AuthSource",0],[3,"StaticAuthHandler",0],[3,"OpenapiInfo",0],[3,"NoopExtractor",0],[3,"AuthError",0],[4,"AuthErrorOrOther",0],[3,"NoContent",0],[3,"Redirect",0],[3,"Success",0],[15,"tuple"],[8,"Default",428],[3,"String",429],[4,"Result",430],[8,"Deserializer",424],[3,"Body",431],[3,"Response",432],[3,"Formatter",433],[6,"Result",433],[8,"Debug",433],[3,"Response",0],[8,"Into",419],[15,"never"],[15,"u8"],[15,"slice"],[3,"Bytes",434],[8,"From",419],[6,"BoxFuture",435],[15,"bool"],[3,"HeaderValue",436],[8,"IntoHeaderName",437],[3,"HeaderName",438],[3,"HeaderMap",439],[3,"Method",440],[8,"Future",441],[8,"ResponseBody",0],[3,"StatusCode",442],[6,"AuthValidation",0],[6,"Result",443],[15,"str"],[3,"OpenapiSchema",444],[8,"DrawResourceRoutes",0],[8,"DrawResourceRoutesWithSchema",0],[3,"TypeId",445],[4,"Cow",446],[8,"Visitor",447],[3,"CorsConfig",355],[4,"Origin",355],[4,"Headers",355],[8,"Endpoint",0],[8,"EndpointWithSchema",0],[6,"AuthSuccess",0],[6,"AuthResult",0],[8,"IntoResponseError",0],[8,"IntoResponse",0],[8,"FromBody",0],[8,"GetOpenapi",0],[8,"DrawResources",0],[8,"DrawResourcesWithSchema",0],[8,"ResponseSchema",0],[8,"Resource",0],[8,"ResourceWithSchema",0],[8,"RequestBody",0],[8,"WithOpenapi",0],[8,"CorsRoute",355]],"b":[[164,"impl-From%3CF%3E-for-AuthErrorOrOther%3CE%3E"],[167,"impl-From%3CAuthError%3E-for-AuthErrorOrOther%3CE%3E"]]}\ +"gotham_restful":{"doc":"This crate is an extension to the popular gotham web …","t":"DEIDGEEGGNNQQNCCIIIIIINNQQQNIYINIIINDDNNDNQQQQQQDDIYIYYIDIIDDNNILLLLMLLMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLAXLLLXXLLLKKXLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKLLLLCKKCLLLLLLLLLKKLLLLLLLLLLLLLKLLLLLKLLMLKLMLMLLLLLLLLLLLLLLLKKLLKMXXMKKKKLLLLLLXKKLKLLLLLLMLLLLLLMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLXXKKMMMMLLLLLLKNNDIENNNENNLLLLLLLLLLLLLLLKMLLLLLLLLLFMLLLMLMLLLLLLLLLLLLLLLL","n":["AuthError","AuthErrorOrOther","AuthHandler","AuthMiddleware","AuthResult","AuthSource","AuthStatus","AuthSuccess","AuthValidation","Authenticated","AuthorizationHeader","Body","Body","Cookie","CorsConfig","CorsRoute","DrawResourceRoutes","DrawResourceRoutesWithSchema","DrawResources","DrawResourcesWithSchema","Endpoint","EndpointWithSchema","Err","Err","Err","Err","Err","Forbidden","FromBody","FromBody","GetOpenapi","Header","IntoResponse","IntoResponseError","IntoResponseWithSchema","Invalid","NoContent","NoopExtractor","Ok","Ok","OpenapiInfo","Other","Output","Output","Params","Params","Placeholders","Placeholders","Raw","Redirect","RequestBody","RequestBody","Resource","Resource","ResourceError","ResourceWithSchema","Response","ResponseBody","ResponseSchema","StaticAuthHandler","Success","Unauthenticated","Unknown","WithOpenapi","accepted_types","accepted_types","accepted_types","accepted_types","algorithms","as_mut","as_ref","aud","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow_from","borrow_from","borrow_from","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut_from","borrow_mut_from","borrow_mut_from","call","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","cors","create","default","default","default","delete","delete_all","description","description","deserialize","endpoint","endpoint","endpoint","extend","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","forbidden","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from_array","from_body","from_body","from_body","from_source","from_vec","gotham","handle","handle","handle_cors","has_placeholders","has_placeholders","has_placeholders","has_placeholders","header","header","header","headers_mut","headers_mut","http_method","http_method","into","into","into","into","into","into","into","into","into","into","into","into","into","into_response","into_response","into_response","into_response","into_response","into_response","into_response_error","into_response_error","into_response_error","iss","json","jwt_secret","jwt_secret","leeway","mime","mime","needs_body","needs_body","needs_body","needs_body","needs_params","needs_params","needs_params","needs_params","new","new","new","new","new_middleware","no_content","ok","openapi_doc","openapi_spec","operation_id","operation_id","operation_verb","raw","read","read_all","required_spec_claims","resource","resource","schema","schema","schema","schema","schema","schema","schema","schema","search","setup","setup","status","status_codes","status_codes","status_codes","status_codes","status_codes","status_codes","status_codes","sub","supported_types","supported_types","supported_types","take_from","take_from","take_from","title","to","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","try_borrow_from","try_borrow_from","try_borrow_from","try_borrow_mut_from","try_borrow_mut_from","try_borrow_mut_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_take_from","try_take_from","try_take_from","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","update","update_all","uri","uri","urls","validate_exp","validate_nbf","version","visit_type","visit_type","wants_auth","wants_auth","wants_auth","wants_auth","with_openapi","Copy","Copy","CorsConfig","CorsRoute","Headers","List","None","None","Origin","Single","Star","borrow","borrow","borrow","borrow_from","borrow_mut","borrow_mut","borrow_mut","borrow_mut_from","call","clone","clone","clone","clone_into","clone_into","clone_into","cors","credentials","default","default","default","fmt","fmt","fmt","from","from","from","handle_cors","headers","into","into","into","max_age","new_middleware","origin","take_from","to_owned","to_owned","to_owned","try_borrow_from","try_borrow_mut_from","try_from","try_from","try_from","try_into","try_into","try_into","try_take_from","type_id","type_id","type_id"],"q":[[0,"gotham_restful"],[355,"gotham_restful::cors"],[416,"mime"],[417,"alloc::vec"],[418,"core::option"],[419,"core::convert"],[420,"core::convert"],[421,"gotham::handler"],[422,"alloc::boxed"],[423,"core::pin"],[424,"serde::de"],[425,"core::marker"],[426,"core::ops::function"],[427,"core::clone"],[428,"core::default"],[429,"alloc::string"],[430,"core::result"],[431,"serde::de"],[432,"http::response"],[433,"core::fmt"],[434,"core::fmt"],[435,"core::convert"],[436,"http::header::value"],[437,"http::header::map::into_header_name"],[438,"http::header::name"],[439,"http::header::map"],[440,"http::method"],[441,"core::future::future"],[442,"http::status"],[443,"anyhow"],[444,"openapi_type::visitor::openapi"],[445,"core::any"],[446,"alloc::borrow"],[447,"openapi_type::visitor"]],"d":["This is an error type that always yields a 403 Forbidden …","This is an error type that either yields a 403 Forbidden …","This trait will help the auth middleware to determine the …","This is the auth middleware. To use it, first make sure …","This return type can be used to wrap any type implementing …","The source of the authentication token in the request.","The authentication status returned by the auth middleware …","This return type can be used to wrap any type implementing …","","The request has been performed with a valid …","Take the token from the HTTP Authorization header. This is …","The type to parse the body into. Use () if needs_body() …","The type to parse the body into. Use () if needs_body() …","Take the token from a cookie with the given name.","","","This trait allows to draw routes within an resource. Use …","This trait allows to draw routes within an resource. Use …","This trait adds the resource method to gotham’s routing. …","This trait adds the resource method to gotham’s routing. …","","","Contains the error value","Contains the error value","","","The error type returned by the conversion if it was …","","This trait should be implemented for every type that can …","","This trait adds the openapi_spec and openapi_doc method to …","Take the token from a header with the given name.","This trait needs to be implemented by every type returned …","","A trait provided to convert a resource’s result to json, …","The request has been performed with an invalid …","This is the return type of a resource that doesn’t …","A no-op extractor that can be used as a default type for …","Contains the success value","Contains the success value","","","The output type that provides the response.","The output type that provides the response.","The type that parses the request parameters. Use …","The type that parses the request parameters. Use …","The type that parses the URI placeholders. Use …","The type that parses the URI placeholders. Use …","This type can be used both as a raw request body, as well …","This is the return type of a resource that only returns a …","A type that can be used inside a request body. Implemented …","","This trait must be implemented for every resource. It …","","","This trait must be implemented for every resource. It …","A response, used to create the final gotham response from.","A type that can be used inside a response body. …","Additional details for IntoResponse to be used with an …","An AuthHandler returning always the same secret. See …","This can be returned from a resource when there is no …","The request has been performed without any kind of …","The auth status is unknown. This is likely because no …","This trait adds the with_openapi method to gotham’s …","Return a list of supported mime types.","Return a list of supported mime types.","","","The validation will check that the alg of the header is …","","","If it contains a value, the validation will check that the …","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Add a description to the openapi specification. Usually …","Add a description to the openapi specification. Usually …","","","","","","","","","","","","","","","","","","","Create an empty 403 Forbidden Response.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","","Returns the argument unchanged.","","","Returns the argument unchanged.","","Returns the argument unchanged.","Returns the argument unchanged.","","","Returns the argument unchanged.","Returns the argument unchanged.","","Perform the conversion.","","","","","","The handler for this endpoint.","The handler for this endpoint.","","Returns true iff the URI contains placeholders. false by …","Returns true iff the URI contains placeholders. false by …","Returns true iff the URI contains placeholders. false by …","Returns true iff the URI contains placeholders. false by …","Set a custom HTTP header. If a header with this name was …","Set a custom HTTP header. If a header with this name was …","Add an HTTP header to the Response.","Allow manipulating HTTP headers.","Allow manipulating HTTP headers.","The HTTP Verb of this endpoint.","The HTTP Verb of this endpoint.","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Turn this into a response that can be returned to the …","This will always be a 204 No Content together with an …","","","","","","","","If it contains a value, the validation will check that the …","Create a Response with mime type json from already …","Return the SHA256-HMAC secret used to verify the JWT token.","","Add some leeway (in seconds) to the exp and nbf validation …","Return the mime type of this Response.","","Returns true iff the request body should be parsed. false …","Returns true iff the request body should be parsed. false …","Returns true iff the request body should be parsed. false …","Returns true iff the request body should be parsed. false …","Returns true iff the request parameters should be parsed. …","Returns true iff the request parameters should be parsed. …","Returns true iff the request parameters should be parsed. …","Returns true iff the request parameters should be parsed. …","","","","Create a new Response from raw data.","","Create a 204 No Content Response.","","Register a GET route to path that returns the OpenAPI …","Register a GET route to path that returns the OpenAPI …","Replace the automatically generated operation id with a …","Replace the automatically generated operation id with a …","The verb used for generating an operation id if …","","","","Which claims are required to be present before starting …","","","","Return the schema of the response for the given status …","","","Returns the schema of the () type.","","","","","Register all methods handled by this resource with the …","Register all methods handled by this resource with the …","Return the status code of this Response.","","All status codes returned by this response. Returns …","All status codes returned by this response. Returns …","","","","","If it contains a value, the validation will check that the …","Return all types that are supported as content types. Use …","Return all types that are supported as content types. Use …","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","The URI that this endpoint listens on in gotham’s format.","The URI that this endpoint listens on in gotham’s format.","","Whether to validate the exp field.","Whether to validate the nbf field.","","","","Returns true if the request wants to know the auth status …","Returns true if the request wants to know the auth status …","Returns true if the request wants to know the auth status …","Returns true if the request wants to know the auth status …","","Copy the Origin header into the Access-Control-Allow-Origin…","Copy the Access-Control-Request-Headers header into the …","This is the configuration that the CORS handler will …","Add CORS routing for your path. This is required for …","Specify the allowed headers of the request. It is up to …","Set the Access-Control-Allow-Headers header to the …","Do not send any Access-Control-Allow-Origin headers.","Do not send any Access-Control-Allow-Headers headers.","Specify the allowed origins of the request. It is up to …","Set the Access-Control-Allow-Origin header to a single …","Send Access-Control-Allow-Origin: *. Note that browser …","","","","","","","","","","","","","","","","Handle a preflight request on path for method. To …","Whether or not the request may be made with supplying …","","","","","","","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Handle CORS for a non-preflight request. This means …","The allowed headers.","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","The amount of seconds that the preflight request can be …","","The allowed origins.","","","","","","","","","","","","","","","",""],"i":[0,0,0,0,0,0,0,0,0,16,18,66,67,18,0,0,0,0,0,0,0,0,68,69,70,71,72,23,0,0,0,18,0,0,0,16,0,0,68,69,0,23,66,67,66,67,66,67,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,0,71,71,24,26,54,4,4,54,16,18,19,8,20,21,22,23,24,4,25,26,37,16,18,21,16,18,19,8,20,21,22,23,24,4,25,26,37,16,18,21,8,16,18,19,8,20,21,22,23,24,4,25,26,16,18,19,8,20,21,22,23,24,4,25,26,0,0,24,25,26,0,0,67,67,21,58,59,0,21,16,18,19,8,20,21,22,23,24,4,25,26,37,37,16,18,19,8,20,21,22,23,23,23,23,24,24,4,25,26,26,26,37,19,72,21,4,8,19,0,66,67,0,66,66,67,67,24,26,37,24,26,66,67,16,18,19,8,20,21,22,23,24,4,25,26,37,71,24,4,25,26,37,70,22,23,54,37,14,19,54,37,4,66,66,67,67,66,66,67,67,8,22,4,37,8,37,16,73,73,67,67,67,4,0,0,54,74,75,70,76,22,23,24,4,25,26,0,77,78,37,70,76,76,22,23,24,25,54,79,79,21,16,18,21,20,25,16,18,19,8,20,21,22,23,24,4,25,26,16,18,21,16,18,21,16,18,19,8,20,21,22,23,24,4,25,26,37,16,18,19,8,20,21,22,23,24,4,25,26,37,16,18,21,16,18,19,8,20,21,22,23,24,4,25,26,37,0,0,66,67,20,54,54,20,21,4,66,66,67,67,80,64,65,0,0,0,65,64,65,0,64,64,64,65,63,63,64,65,63,63,63,64,65,63,64,65,63,81,63,64,65,63,64,65,63,64,65,63,0,63,64,65,63,63,63,63,63,64,65,63,63,63,64,65,63,64,65,63,63,64,65,63],"f":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,[[],[[3,[[2,[1]]]]]],[[],[[3,[[2,[1]]]]]],[[],[[3,[[2,[1]]]]]],[[],[[3,[[2,[1]]]]]],0,[[[4,[-2]]],-1,[],[[5,[-1]]]],[[[4,[-2]]],-1,[],[[6,[-1]]]],0,[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[7,-1,[]],[7,-1,[]],[7,-1,[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[7,-1,[]],[7,-1,[]],[7,-1,[]],[[[8,[-1,-2]],7,-3],[[11,[[10,[9]]]]],[12,13],[[14,[-1]]],15],[[[16,[-1]]],[[16,[-1]]],[17,13]],[18,18],[19,19],[[[8,[-1,-2]]],[[8,[-1,-2]]],[],17],[20,20],[21,21],[22,22],[[[23,[-1]]],[[23,[-1]]],17],[24,24],[[[4,[-1]]],[[4,[-1]]],17],[25,25],[[[26,[-1]]],[[26,[-1]]],17],[[-1,-2],27,[],[]],[[-1,-2],27,[],[]],[[-1,-2],27,[],[]],[[-1,-2],27,[],[]],[[-1,-2],27,[],[]],[[-1,-2],27,[],[]],[[-1,-2],27,[],[]],[[-1,-2],27,[],[]],[[-1,-2],27,[],[]],[[-1,-2],27,[],[]],[[-1,-2],27,[],[]],[[-1,-2],27,[],[]],0,0,[[],24],[[],25],[[],[[26,[-1]]],28],0,0,[[],[[3,[29]]]],[[],[[3,[29]]]],[-1,[[30,[21]]],31],[-1,27,[]],[-1,27,[]],0,[[7,[33,[32]]],27],[[[16,[-1]],34],35,[36,13]],[[18,34],35],[[19,34],35],[[[8,[-1,-2]],34],35,36,36],[[20,34],35],[[21,34],35],[[22,34],35],[[[23,[-1]],34],35,36],[[24,34],35],[[[4,[-1]],34],35,36],[[25,34],35],[[[26,[-1]],34],35,36],[[37,34],35],[[],37],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[-2,[[23,[-1]]],[],[0,[38,[-1]]]],[-1,-1,[]],[22,[[23,[-1]]],[]],[39,-1,[]],[-1,-1,[]],[27,24],[-1,-1,[]],[-1,-1,[]],[-1,[[26,[-1]]],[]],[39,-1,[]],[-1,-1,[]],[-1,-1,[]],[[[41,[40]]],19],[[42,1],[[30,[-1]]],[]],[[42,1],[[30,[-1]]],[]],[[42,1],[[30,[[4,[-1]]]]],[[43,[[41,[40]]]]]],[18,[[8,[-1,-2]]],[12,13],[[14,[-1]],28]],[[[2,[40]]],19],0,[[7,3],44],[[7,3],44],0,[[],45],[[],45],[[],45],[[],45],[[24,-1,46],27,47],[[[26,[-1]],-2,46],27,[],47],[[37,48,46],27],[24,49],[[[26,[-1]]],49,[]],[[],50],[[],50],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,[[44,[[30,[37]]]]],[]],[24,[[11,[[10,[51]]]]]],[[[4,[-1]]],[[11,[[10,[51]]]]],[[38,[32]]]],[25,[[44,[[30,[37]]]]]],[[[26,[-1]]],[[11,[[10,[51]]]]],52],[37,[[44,[[30,[37]]]]]],[-1,[[30,[37]]],[]],[22,[[30,[37]]]],[[[23,[-1]]],[[30,[37]]],[]],0,[[53,-1],37,[[38,[32]]]],[[-1,7,-2],[[3,[[2,[40]]]]],[],15],[[19,7,-1],[[3,[[2,[40]]]]],15],0,[37,[[3,[1]]]],0,[[],45],[[],45],[[],45],[[],45],[[],45],[[],45],[[],45],[[],45],[[18,54,-2],[[8,[-1,-2]]],[12,13],[[14,[-1]]]],[-1,22,[[38,[29]]]],[[-1,1],[[4,[-1]]],[]],[[53,-1,[3,[1]]],37,[[38,[32]]]],[[[8,[-1,-2]]],[[55,[[8,[-1,-2]]]]],[],[]],[[],37],[[[16,[-1]]],[[30,[-1,22]]],13],[[-1,56],27,[]],[[-1,56],27,[]],[[],[[3,[29]]]],[[],[[3,[29]]]],[[],[[3,[56]]]],0,0,0,0,[[-1,56],27,[]],[[-1,56],27,[]],[53,57],[53,57],[53,57],[53,57],[53,57],[53,57],[53,57],[53,57],0,[-1,27,58],[-1,27,59],[37,53],[[],[[2,[53]]]],[[],[[2,[53]]]],[[],[[2,[53]]]],[[],[[2,[53]]]],[[],[[2,[53]]]],[[],[[2,[53]]]],[[],[[2,[53]]]],0,[[],[[3,[[2,[1]]]]]],[[],[[3,[[2,[1]]]]]],[[],[[3,[[2,[1]]]]]],[7,-1,[]],[7,-1,[]],[7,-1,[]],0,0,[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[7,[[3,[-1]]],[]],[7,[[3,[-1]]],[]],[7,[[3,[-1]]],[]],[7,[[3,[-1]]],[]],[7,[[3,[-1]]],[]],[7,[[3,[-1]]],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[7,[[3,[-1]]],[]],[7,[[3,[-1]]],[]],[7,[[3,[-1]]],[]],[-1,60,[]],[-1,60,[]],[-1,60,[]],[-1,60,[]],[-1,60,[]],[-1,60,[]],[-1,60,[]],[-1,60,[]],[-1,60,[]],[-1,60,[]],[-1,60,[]],[-1,60,[]],[-1,60,[]],0,0,[[],[[61,[56]]]],[[],[[61,[56]]]],0,0,0,0,[-1,27,62],[-1,27,62],[[],45],[[],45],[[],45],[[],45],[[-1,20,-2],27,[],15],0,0,0,0,0,0,0,0,0,0,0,[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[7,-1,[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[7,-1,[]],[[63,7,-1],[[11,[[10,[9]]]]],15],[64,64],[65,65],[63,63],[[-1,-2],27,[],[]],[[-1,-2],27,[],[]],[[-1,-2],27,[],[]],[[-1,56,50],27,[]],0,[[],64],[[],65],[[],63],[[64,34],35],[[65,34],35],[[63,34],35],[-1,-1,[]],[-1,-1,[]],[-1,-1,[]],[[7,[33,[32]]],27],0,[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],0,[63,[[55,[63]]]],0,[7,-1,[]],[-1,-2,[],[]],[-1,-2,[],[]],[-1,-2,[],[]],[7,[[3,[-1]]],[]],[7,[[3,[-1]]],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[-1,[[30,[-2]]],[],[]],[7,[[3,[-1]]],[]],[-1,60,[]],[-1,60,[]],[-1,60,[]]],"c":[],"p":[[3,"Mime",416],[3,"Vec",417],[4,"Option",418],[3,"Raw",0],[8,"AsMut",419],[8,"AsRef",419],[3,"State",420],[3,"AuthMiddleware",0],[6,"HandlerFuture",421],[3,"Box",422],[3,"Pin",423],[8,"DeserializeOwned",424],[8,"Send",425],[8,"AuthHandler",0],[8,"FnOnce",426],[4,"AuthStatus",0],[8,"Clone",427],[4,"AuthSource",0],[3,"StaticAuthHandler",0],[3,"OpenapiInfo",0],[3,"NoopExtractor",0],[3,"AuthError",0],[4,"AuthErrorOrOther",0],[3,"NoContent",0],[3,"Redirect",0],[3,"Success",0],[15,"tuple"],[8,"Default",428],[3,"String",429],[4,"Result",430],[8,"Deserializer",424],[3,"Body",431],[3,"Response",432],[3,"Formatter",433],[6,"Result",433],[8,"Debug",433],[3,"Response",0],[8,"Into",419],[15,"never"],[15,"u8"],[15,"slice"],[3,"Bytes",434],[8,"From",419],[6,"BoxFuture",435],[15,"bool"],[3,"HeaderValue",436],[8,"IntoHeaderName",437],[3,"HeaderName",438],[3,"HeaderMap",439],[3,"Method",440],[8,"Future",441],[8,"ResponseBody",0],[3,"StatusCode",442],[6,"AuthValidation",0],[6,"Result",443],[15,"str"],[3,"OpenapiSchema",444],[8,"DrawResourceRoutes",0],[8,"DrawResourceRoutesWithSchema",0],[3,"TypeId",445],[4,"Cow",446],[8,"Visitor",447],[3,"CorsConfig",355],[4,"Origin",355],[4,"Headers",355],[8,"Endpoint",0],[8,"EndpointWithSchema",0],[6,"AuthSuccess",0],[6,"AuthResult",0],[8,"IntoResponseError",0],[8,"IntoResponse",0],[8,"FromBody",0],[8,"GetOpenapi",0],[8,"DrawResources",0],[8,"DrawResourcesWithSchema",0],[8,"ResponseSchema",0],[8,"Resource",0],[8,"ResourceWithSchema",0],[8,"RequestBody",0],[8,"WithOpenapi",0],[8,"CorsRoute",355]],"b":[[164,"impl-From%3CF%3E-for-AuthErrorOrOther%3CE%3E"],[166,"impl-From%3CAuthError%3E-for-AuthErrorOrOther%3CE%3E"]]}\ }'); if (typeof window !== 'undefined' && window.initSearch) {window.initSearch(searchIndex)}; if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex}; diff --git a/doc/trait.impl/core/clone/trait.Clone.js b/doc/trait.impl/core/clone/trait.Clone.js index faa5252218..d11c7b9f58 100644 --- a/doc/trait.impl/core/clone/trait.Clone.js +++ b/doc/trait.impl/core/clone/trait.Clone.js @@ -1,3 +1,3 @@ (function() {var implementors = { -"gotham_restful":[["impl Clone for Redirect"],["impl<E: Clone> Clone for AuthErrorOrOther<E>"],["impl Clone for OpenapiInfo"],["impl Clone for Origin"],["impl<Data, Handler> Clone for AuthMiddleware<Data, Handler>where\n Handler: Clone,"],["impl Clone for AuthError"],["impl Clone for NoContent"],["impl Clone for AuthSource"],["impl Clone for StaticAuthHandler"],["impl Clone for Headers"],["impl<T: Clone> Clone for Raw<T>"],["impl Clone for CorsConfig"],["impl Clone for NoopExtractor"],["impl<T: Clone> Clone for Success<T>"],["impl<T> Clone for AuthStatus<T>where\n T: Clone + Send + 'static,"]] +"gotham_restful":[["impl Clone for StaticAuthHandler"],["impl Clone for CorsConfig"],["impl<T> Clone for AuthStatus<T>where\n T: Clone + Send + 'static,"],["impl Clone for OpenapiInfo"],["impl Clone for AuthError"],["impl<Data, Handler> Clone for AuthMiddleware<Data, Handler>where\n Handler: Clone,"],["impl Clone for Origin"],["impl Clone for Headers"],["impl<T: Clone> Clone for Raw<T>"],["impl Clone for NoopExtractor"],["impl<E: Clone> Clone for AuthErrorOrOther<E>"],["impl Clone for AuthSource"],["impl Clone for Redirect"],["impl Clone for NoContent"],["impl<T: Clone> Clone for Success<T>"]] };if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/doc/trait.impl/core/default/trait.Default.js b/doc/trait.impl/core/default/trait.Default.js index 06110f919b..f3e7746312 100644 --- a/doc/trait.impl/core/default/trait.Default.js +++ b/doc/trait.impl/core/default/trait.Default.js @@ -1,3 +1,3 @@ (function() {var implementors = { -"gotham_restful":[["impl Default for Redirect"],["impl Default for Headers"],["impl Default for Origin"],["impl<T: Default> Default for Success<T>"],["impl Default for NoContent"],["impl Default for CorsConfig"]] +"gotham_restful":[["impl<T: Default> Default for Success<T>"],["impl Default for Redirect"],["impl Default for Origin"],["impl Default for NoContent"],["impl Default for CorsConfig"],["impl Default for Headers"]] };if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/doc/trait.impl/core/fmt/trait.Debug.js b/doc/trait.impl/core/fmt/trait.Debug.js index 939e70930a..9190c48634 100644 --- a/doc/trait.impl/core/fmt/trait.Debug.js +++ b/doc/trait.impl/core/fmt/trait.Debug.js @@ -1,3 +1,3 @@ (function() {var implementors = { -"gotham_restful":[["impl Debug for Headers"],["impl Debug for AuthSource"],["impl<Data: Debug, Handler: Debug> Debug for AuthMiddleware<Data, Handler>"],["impl<T: Debug> Debug for Success<T>"],["impl Debug for Origin"],["impl Debug for OpenapiInfo"],["impl Debug for Redirect"],["impl<T: Debug + Send + 'static> Debug for AuthStatus<T>"],["impl Debug for StaticAuthHandler"],["impl Debug for NoopExtractor"],["impl<E: Debug> Debug for AuthErrorOrOther<E>"],["impl Debug for AuthError"],["impl Debug for Response"],["impl Debug for NoContent"],["impl Debug for CorsConfig"],["impl<T: Debug> Debug for Raw<T>"]] +"gotham_restful":[["impl Debug for NoopExtractor"],["impl Debug for CorsConfig"],["impl Debug for Response"],["impl Debug for Redirect"],["impl Debug for AuthSource"],["impl Debug for OpenapiInfo"],["impl<T: Debug> Debug for Success<T>"],["impl<E: Debug> Debug for AuthErrorOrOther<E>"],["impl<T: Debug + Send + 'static> Debug for AuthStatus<T>"],["impl<Data: Debug, Handler: Debug> Debug for AuthMiddleware<Data, Handler>"],["impl Debug for AuthError"],["impl<T: Debug> Debug for Raw<T>"],["impl Debug for Origin"],["impl Debug for Headers"],["impl Debug for StaticAuthHandler"],["impl Debug for NoContent"]] };if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/doc/trait.impl/gotham/middleware/trait.Middleware.js b/doc/trait.impl/gotham/middleware/trait.Middleware.js index 0502813495..cbd1dc758d 100644 --- a/doc/trait.impl/gotham/middleware/trait.Middleware.js +++ b/doc/trait.impl/gotham/middleware/trait.Middleware.js @@ -1,3 +1,3 @@ (function() {var implementors = { -"gotham_restful":[["impl Middleware for CorsConfig"],["impl<Data, Handler> Middleware for AuthMiddleware<Data, Handler>where\n Data: DeserializeOwned + Send + 'static,\n Handler: AuthHandler<Data>,"]] +"gotham_restful":[["impl<Data, Handler> Middleware for AuthMiddleware<Data, Handler>where\n Data: DeserializeOwned + Send + 'static,\n Handler: AuthHandler<Data>,"],["impl Middleware for CorsConfig"]] };if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/doc/trait.impl/gotham/middleware/trait.NewMiddleware.js b/doc/trait.impl/gotham/middleware/trait.NewMiddleware.js index 2a4c70ea51..a0bcdcb1cb 100644 --- a/doc/trait.impl/gotham/middleware/trait.NewMiddleware.js +++ b/doc/trait.impl/gotham/middleware/trait.NewMiddleware.js @@ -1,3 +1,3 @@ (function() {var implementors = { -"gotham_restful":[["impl<Data, Handler> NewMiddleware for AuthMiddleware<Data, Handler>where\n Self: Clone + Middleware + Sync + RefUnwindSafe,"],["impl NewMiddleware for CorsConfig"]] +"gotham_restful":[["impl NewMiddleware for CorsConfig"],["impl<Data, Handler> NewMiddleware for AuthMiddleware<Data, Handler>where\n Self: Clone + Middleware + Sync + RefUnwindSafe,"]] };if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/doc/trait.impl/gotham/state/data/trait.StateData.js b/doc/trait.impl/gotham/state/data/trait.StateData.js index ac1c5cf641..ce5a8b61b9 100644 --- a/doc/trait.impl/gotham/state/data/trait.StateData.js +++ b/doc/trait.impl/gotham/state/data/trait.StateData.js @@ -1,3 +1,3 @@ (function() {var implementors = { -"gotham_restful":[["impl StateData for AuthSource"],["impl<T: Send + 'static> StateData for AuthStatus<T>"],["impl StateData for CorsConfig"],["impl StateData for NoopExtractor"]] +"gotham_restful":[["impl<T: Send + 'static> StateData for AuthStatus<T>"],["impl StateData for CorsConfig"],["impl StateData for AuthSource"],["impl StateData for NoopExtractor"]] };if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/doc/type.impl/core/result/enum.Result.js b/doc/type.impl/core/result/enum.Result.js index 04a5b39fcb..bf2631c610 100644 --- a/doc/type.impl/core/result/enum.Result.js +++ b/doc/type.impl/core/result/enum.Result.js @@ -1,3 +1,3 @@ (function() {var type_impls = { -"gotham_restful":[["
source§

impl<T, E> Result<T, E>

1.0.0 (const: 1.48.0) · source

pub const fn is_ok(&self) -> bool

Returns true if the result is Ok.

\n
Examples
\n
let x: Result<i32, &str> = Ok(-3);\nassert_eq!(x.is_ok(), true);\n\nlet x: Result<i32, &str> = Err("Some error message");\nassert_eq!(x.is_ok(), false);
\n
1.70.0 · source

pub fn is_ok_and(self, f: impl FnOnce(T) -> bool) -> bool

Returns true if the result is Ok and the value inside of it matches a predicate.

\n
Examples
\n
let x: Result<u32, &str> = Ok(2);\nassert_eq!(x.is_ok_and(|x| x > 1), true);\n\nlet x: Result<u32, &str> = Ok(0);\nassert_eq!(x.is_ok_and(|x| x > 1), false);\n\nlet x: Result<u32, &str> = Err("hey");\nassert_eq!(x.is_ok_and(|x| x > 1), false);
\n
1.0.0 (const: 1.48.0) · source

pub const fn is_err(&self) -> bool

Returns true if the result is Err.

\n
Examples
\n
let x: Result<i32, &str> = Ok(-3);\nassert_eq!(x.is_err(), false);\n\nlet x: Result<i32, &str> = Err("Some error message");\nassert_eq!(x.is_err(), true);
\n
1.70.0 · source

pub fn is_err_and(self, f: impl FnOnce(E) -> bool) -> bool

Returns true if the result is Err and the value inside of it matches a predicate.

\n
Examples
\n
use std::io::{Error, ErrorKind};\n\nlet x: Result<u32, Error> = Err(Error::new(ErrorKind::NotFound, "!"));\nassert_eq!(x.is_err_and(|x| x.kind() == ErrorKind::NotFound), true);\n\nlet x: Result<u32, Error> = Err(Error::new(ErrorKind::PermissionDenied, "!"));\nassert_eq!(x.is_err_and(|x| x.kind() == ErrorKind::NotFound), false);\n\nlet x: Result<u32, Error> = Ok(123);\nassert_eq!(x.is_err_and(|x| x.kind() == ErrorKind::NotFound), false);
\n
1.0.0 · source

pub fn ok(self) -> Option<T>

Converts from Result<T, E> to Option<T>.

\n

Converts self into an Option<T>, consuming self,\nand discarding the error, if any.

\n
Examples
\n
let x: Result<u32, &str> = Ok(2);\nassert_eq!(x.ok(), Some(2));\n\nlet x: Result<u32, &str> = Err("Nothing here");\nassert_eq!(x.ok(), None);
\n
1.0.0 · source

pub fn err(self) -> Option<E>

Converts from Result<T, E> to Option<E>.

\n

Converts self into an Option<E>, consuming self,\nand discarding the success value, if any.

\n
Examples
\n
let x: Result<u32, &str> = Ok(2);\nassert_eq!(x.err(), None);\n\nlet x: Result<u32, &str> = Err("Nothing here");\nassert_eq!(x.err(), Some("Nothing here"));
\n
1.0.0 (const: 1.48.0) · source

pub const fn as_ref(&self) -> Result<&T, &E>

Converts from &Result<T, E> to Result<&T, &E>.

\n

Produces a new Result, containing a reference\ninto the original, leaving the original in place.

\n
Examples
\n
let x: Result<u32, &str> = Ok(2);\nassert_eq!(x.as_ref(), Ok(&2));\n\nlet x: Result<u32, &str> = Err("Error");\nassert_eq!(x.as_ref(), Err(&"Error"));
\n
1.0.0 (const: unstable) · source

pub fn as_mut(&mut self) -> Result<&mut T, &mut E>

Converts from &mut Result<T, E> to Result<&mut T, &mut E>.

\n
Examples
\n
fn mutate(r: &mut Result<i32, i32>) {\n    match r.as_mut() {\n        Ok(v) => *v = 42,\n        Err(e) => *e = 0,\n    }\n}\n\nlet mut x: Result<i32, i32> = Ok(2);\nmutate(&mut x);\nassert_eq!(x.unwrap(), 42);\n\nlet mut x: Result<i32, i32> = Err(13);\nmutate(&mut x);\nassert_eq!(x.unwrap_err(), 0);
\n
1.0.0 · source

pub fn map<U, F>(self, op: F) -> Result<U, E>where\n F: FnOnce(T) -> U,

Maps a Result<T, E> to Result<U, E> by applying a function to a\ncontained Ok value, leaving an Err value untouched.

\n

This function can be used to compose the results of two functions.

\n
Examples
\n

Print the numbers on each line of a string multiplied by two.

\n\n
let line = "1\\n2\\n3\\n4\\n";\n\nfor num in line.lines() {\n    match num.parse::<i32>().map(|i| i * 2) {\n        Ok(n) => println!("{n}"),\n        Err(..) => {}\n    }\n}
\n
1.41.0 · source

pub fn map_or<U, F>(self, default: U, f: F) -> Uwhere\n F: FnOnce(T) -> U,

Returns the provided default (if Err), or\napplies a function to the contained value (if Ok).

\n

Arguments passed to map_or are eagerly evaluated; if you are passing\nthe result of a function call, it is recommended to use map_or_else,\nwhich is lazily evaluated.

\n
Examples
\n
let x: Result<_, &str> = Ok("foo");\nassert_eq!(x.map_or(42, |v| v.len()), 3);\n\nlet x: Result<&str, _> = Err("bar");\nassert_eq!(x.map_or(42, |v| v.len()), 42);
\n
1.41.0 · source

pub fn map_or_else<U, D, F>(self, default: D, f: F) -> Uwhere\n D: FnOnce(E) -> U,\n F: FnOnce(T) -> U,

Maps a Result<T, E> to U by applying fallback function default to\na contained Err value, or function f to a contained Ok value.

\n

This function can be used to unpack a successful result\nwhile handling an error.

\n
Examples
\n
let k = 21;\n\nlet x : Result<_, &str> = Ok("foo");\nassert_eq!(x.map_or_else(|e| k * 2, |v| v.len()), 3);\n\nlet x : Result<&str, _> = Err("bar");\nassert_eq!(x.map_or_else(|e| k * 2, |v| v.len()), 42);
\n
1.0.0 · source

pub fn map_err<F, O>(self, op: O) -> Result<T, F>where\n O: FnOnce(E) -> F,

Maps a Result<T, E> to Result<T, F> by applying a function to a\ncontained Err value, leaving an Ok value untouched.

\n

This function can be used to pass through a successful result while handling\nan error.

\n
Examples
\n
fn stringify(x: u32) -> String { format!("error code: {x}") }\n\nlet x: Result<u32, u32> = Ok(2);\nassert_eq!(x.map_err(stringify), Ok(2));\n\nlet x: Result<u32, u32> = Err(13);\nassert_eq!(x.map_err(stringify), Err("error code: 13".to_string()));
\n
source

pub fn inspect<F>(self, f: F) -> Result<T, E>where\n F: FnOnce(&T),

🔬This is a nightly-only experimental API. (result_option_inspect)

Calls the provided closure with a reference to the contained value (if Ok).

\n
Examples
\n
#![feature(result_option_inspect)]\n\nlet x: u8 = "4"\n    .parse::<u8>()\n    .inspect(|x| println!("original: {x}"))\n    .map(|x| x.pow(3))\n    .expect("failed to parse number");
\n
source

pub fn inspect_err<F>(self, f: F) -> Result<T, E>where\n F: FnOnce(&E),

🔬This is a nightly-only experimental API. (result_option_inspect)

Calls the provided closure with a reference to the contained error (if Err).

\n
Examples
\n
#![feature(result_option_inspect)]\n\nuse std::{fs, io};\n\nfn read() -> io::Result<String> {\n    fs::read_to_string("address.txt")\n        .inspect_err(|e| eprintln!("failed to read file: {e}"))\n}
\n
1.47.0 · source

pub fn as_deref(&self) -> Result<&<T as Deref>::Target, &E>where\n T: Deref,

Converts from Result<T, E> (or &Result<T, E>) to Result<&<T as Deref>::Target, &E>.

\n

Coerces the Ok variant of the original Result via Deref\nand returns the new Result.

\n
Examples
\n
let x: Result<String, u32> = Ok("hello".to_string());\nlet y: Result<&str, &u32> = Ok("hello");\nassert_eq!(x.as_deref(), y);\n\nlet x: Result<String, u32> = Err(42);\nlet y: Result<&str, &u32> = Err(&42);\nassert_eq!(x.as_deref(), y);
\n
1.47.0 · source

pub fn as_deref_mut(&mut self) -> Result<&mut <T as Deref>::Target, &mut E>where\n T: DerefMut,

Converts from Result<T, E> (or &mut Result<T, E>) to Result<&mut <T as DerefMut>::Target, &mut E>.

\n

Coerces the Ok variant of the original Result via DerefMut\nand returns the new Result.

\n
Examples
\n
let mut s = "HELLO".to_string();\nlet mut x: Result<String, u32> = Ok("hello".to_string());\nlet y: Result<&mut str, &mut u32> = Ok(&mut s);\nassert_eq!(x.as_deref_mut().map(|x| { x.make_ascii_uppercase(); x }), y);\n\nlet mut i = 42;\nlet mut x: Result<String, u32> = Err(42);\nlet y: Result<&mut str, &mut u32> = Err(&mut i);\nassert_eq!(x.as_deref_mut().map(|x| { x.make_ascii_uppercase(); x }), y);
\n
1.0.0 · source

pub fn iter(&self) -> Iter<'_, T>

Returns an iterator over the possibly contained value.

\n

The iterator yields one value if the result is Result::Ok, otherwise none.

\n
Examples
\n
let x: Result<u32, &str> = Ok(7);\nassert_eq!(x.iter().next(), Some(&7));\n\nlet x: Result<u32, &str> = Err("nothing!");\nassert_eq!(x.iter().next(), None);
\n
1.0.0 · source

pub fn iter_mut(&mut self) -> IterMut<'_, T>

Returns a mutable iterator over the possibly contained value.

\n

The iterator yields one value if the result is Result::Ok, otherwise none.

\n
Examples
\n
let mut x: Result<u32, &str> = Ok(7);\nmatch x.iter_mut().next() {\n    Some(v) => *v = 40,\n    None => {},\n}\nassert_eq!(x, Ok(40));\n\nlet mut x: Result<u32, &str> = Err("nothing!");\nassert_eq!(x.iter_mut().next(), None);
\n
1.4.0 · source

pub fn expect(self, msg: &str) -> Twhere\n E: Debug,

Returns the contained Ok value, consuming the self value.

\n

Because this function may panic, its use is generally discouraged.\nInstead, prefer to use pattern matching and handle the Err\ncase explicitly, or call unwrap_or, unwrap_or_else, or\nunwrap_or_default.

\n
Panics
\n

Panics if the value is an Err, with a panic message including the\npassed message, and the content of the Err.

\n
Examples
\n
let x: Result<u32, &str> = Err("emergency failure");\nx.expect("Testing expect"); // panics with `Testing expect: emergency failure`
\n
Recommended Message Style
\n

We recommend that expect messages are used to describe the reason you\nexpect the Result should be Ok.

\n\n
let path = std::env::var("IMPORTANT_PATH")\n    .expect("env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`");
\n

Hint: If you’re having trouble remembering how to phrase expect\nerror messages remember to focus on the word “should” as in “env\nvariable should be set by blah” or “the given binary should be available\nand executable by the current user”.

\n

For more detail on expect message styles and the reasoning behind our recommendation please\nrefer to the section on “Common Message\nStyles” in the\nstd::error module docs.

\n
1.0.0 · source

pub fn unwrap(self) -> Twhere\n E: Debug,

Returns the contained Ok value, consuming the self value.

\n

Because this function may panic, its use is generally discouraged.\nInstead, prefer to use pattern matching and handle the Err\ncase explicitly, or call unwrap_or, unwrap_or_else, or\nunwrap_or_default.

\n
Panics
\n

Panics if the value is an Err, with a panic message provided by the\nErr’s value.

\n
Examples
\n

Basic usage:

\n\n
let x: Result<u32, &str> = Ok(2);\nassert_eq!(x.unwrap(), 2);
\n\n
let x: Result<u32, &str> = Err("emergency failure");\nx.unwrap(); // panics with `emergency failure`
\n
1.16.0 · source

pub fn unwrap_or_default(self) -> Twhere\n T: Default,

Returns the contained Ok value or a default

\n

Consumes the self argument then, if Ok, returns the contained\nvalue, otherwise if Err, returns the default value for that\ntype.

\n
Examples
\n

Converts a string to an integer, turning poorly-formed strings\ninto 0 (the default value for integers). parse converts\na string to any other type that implements FromStr, returning an\nErr on error.

\n\n
let good_year_from_input = "1909";\nlet bad_year_from_input = "190blarg";\nlet good_year = good_year_from_input.parse().unwrap_or_default();\nlet bad_year = bad_year_from_input.parse().unwrap_or_default();\n\nassert_eq!(1909, good_year);\nassert_eq!(0, bad_year);
\n
1.17.0 · source

pub fn expect_err(self, msg: &str) -> Ewhere\n T: Debug,

Returns the contained Err value, consuming the self value.

\n
Panics
\n

Panics if the value is an Ok, with a panic message including the\npassed message, and the content of the Ok.

\n
Examples
\n
let x: Result<u32, &str> = Ok(10);\nx.expect_err("Testing expect_err"); // panics with `Testing expect_err: 10`
\n
1.0.0 · source

pub fn unwrap_err(self) -> Ewhere\n T: Debug,

Returns the contained Err value, consuming the self value.

\n
Panics
\n

Panics if the value is an Ok, with a custom panic message provided\nby the Ok’s value.

\n
Examples
\n
let x: Result<u32, &str> = Ok(2);\nx.unwrap_err(); // panics with `2`
\n\n
let x: Result<u32, &str> = Err("emergency failure");\nassert_eq!(x.unwrap_err(), "emergency failure");
\n
source

pub fn into_ok(self) -> Twhere\n E: Into<!>,

🔬This is a nightly-only experimental API. (unwrap_infallible)

Returns the contained Ok value, but never panics.

\n

Unlike unwrap, this method is known to never panic on the\nresult types it is implemented for. Therefore, it can be used\ninstead of unwrap as a maintainability safeguard that will fail\nto compile if the error type of the Result is later changed\nto an error that can actually occur.

\n
Examples
\n
\nfn only_good_news() -> Result<String, !> {\n    Ok("this is fine".into())\n}\n\nlet s: String = only_good_news().into_ok();\nprintln!("{s}");
\n
source

pub fn into_err(self) -> Ewhere\n T: Into<!>,

🔬This is a nightly-only experimental API. (unwrap_infallible)

Returns the contained Err value, but never panics.

\n

Unlike unwrap_err, this method is known to never panic on the\nresult types it is implemented for. Therefore, it can be used\ninstead of unwrap_err as a maintainability safeguard that will fail\nto compile if the ok type of the Result is later changed\nto a type that can actually occur.

\n
Examples
\n
\nfn only_bad_news() -> Result<!, String> {\n    Err("Oops, it failed".into())\n}\n\nlet error: String = only_bad_news().into_err();\nprintln!("{error}");
\n
1.0.0 · source

pub fn and<U>(self, res: Result<U, E>) -> Result<U, E>

Returns res if the result is Ok, otherwise returns the Err value of self.

\n

Arguments passed to and are eagerly evaluated; if you are passing the\nresult of a function call, it is recommended to use and_then, which is\nlazily evaluated.

\n
Examples
\n
let x: Result<u32, &str> = Ok(2);\nlet y: Result<&str, &str> = Err("late error");\nassert_eq!(x.and(y), Err("late error"));\n\nlet x: Result<u32, &str> = Err("early error");\nlet y: Result<&str, &str> = Ok("foo");\nassert_eq!(x.and(y), Err("early error"));\n\nlet x: Result<u32, &str> = Err("not a 2");\nlet y: Result<&str, &str> = Err("late error");\nassert_eq!(x.and(y), Err("not a 2"));\n\nlet x: Result<u32, &str> = Ok(2);\nlet y: Result<&str, &str> = Ok("different result type");\nassert_eq!(x.and(y), Ok("different result type"));
\n
1.0.0 · source

pub fn and_then<U, F>(self, op: F) -> Result<U, E>where\n F: FnOnce(T) -> Result<U, E>,

Calls op if the result is Ok, otherwise returns the Err value of self.

\n

This function can be used for control flow based on Result values.

\n
Examples
\n
fn sq_then_to_string(x: u32) -> Result<String, &'static str> {\n    x.checked_mul(x).map(|sq| sq.to_string()).ok_or("overflowed")\n}\n\nassert_eq!(Ok(2).and_then(sq_then_to_string), Ok(4.to_string()));\nassert_eq!(Ok(1_000_000).and_then(sq_then_to_string), Err("overflowed"));\nassert_eq!(Err("not a number").and_then(sq_then_to_string), Err("not a number"));
\n

Often used to chain fallible operations that may return Err.

\n\n
use std::{io::ErrorKind, path::Path};\n\n// Note: on Windows "/" maps to "C:\\"\nlet root_modified_time = Path::new("/").metadata().and_then(|md| md.modified());\nassert!(root_modified_time.is_ok());\n\nlet should_fail = Path::new("/bad/path").metadata().and_then(|md| md.modified());\nassert!(should_fail.is_err());\nassert_eq!(should_fail.unwrap_err().kind(), ErrorKind::NotFound);
\n
1.0.0 · source

pub fn or<F>(self, res: Result<T, F>) -> Result<T, F>

Returns res if the result is Err, otherwise returns the Ok value of self.

\n

Arguments passed to or are eagerly evaluated; if you are passing the\nresult of a function call, it is recommended to use or_else, which is\nlazily evaluated.

\n
Examples
\n
let x: Result<u32, &str> = Ok(2);\nlet y: Result<u32, &str> = Err("late error");\nassert_eq!(x.or(y), Ok(2));\n\nlet x: Result<u32, &str> = Err("early error");\nlet y: Result<u32, &str> = Ok(2);\nassert_eq!(x.or(y), Ok(2));\n\nlet x: Result<u32, &str> = Err("not a 2");\nlet y: Result<u32, &str> = Err("late error");\nassert_eq!(x.or(y), Err("late error"));\n\nlet x: Result<u32, &str> = Ok(2);\nlet y: Result<u32, &str> = Ok(100);\nassert_eq!(x.or(y), Ok(2));
\n
1.0.0 · source

pub fn or_else<F, O>(self, op: O) -> Result<T, F>where\n O: FnOnce(E) -> Result<T, F>,

Calls op if the result is Err, otherwise returns the Ok value of self.

\n

This function can be used for control flow based on result values.

\n
Examples
\n
fn sq(x: u32) -> Result<u32, u32> { Ok(x * x) }\nfn err(x: u32) -> Result<u32, u32> { Err(x) }\n\nassert_eq!(Ok(2).or_else(sq).or_else(sq), Ok(2));\nassert_eq!(Ok(2).or_else(err).or_else(sq), Ok(2));\nassert_eq!(Err(3).or_else(sq).or_else(err), Ok(9));\nassert_eq!(Err(3).or_else(err).or_else(err), Err(3));
\n
1.0.0 · source

pub fn unwrap_or(self, default: T) -> T

Returns the contained Ok value or a provided default.

\n

Arguments passed to unwrap_or are eagerly evaluated; if you are passing\nthe result of a function call, it is recommended to use unwrap_or_else,\nwhich is lazily evaluated.

\n
Examples
\n
let default = 2;\nlet x: Result<u32, &str> = Ok(9);\nassert_eq!(x.unwrap_or(default), 9);\n\nlet x: Result<u32, &str> = Err("error");\nassert_eq!(x.unwrap_or(default), default);
\n
1.0.0 · source

pub fn unwrap_or_else<F>(self, op: F) -> Twhere\n F: FnOnce(E) -> T,

Returns the contained Ok value or computes it from a closure.

\n
Examples
\n
fn count(x: &str) -> usize { x.len() }\n\nassert_eq!(Ok(2).unwrap_or_else(count), 2);\nassert_eq!(Err("foo").unwrap_or_else(count), 3);
\n
1.58.0 · source

pub unsafe fn unwrap_unchecked(self) -> T

Returns the contained Ok value, consuming the self value,\nwithout checking that the value is not an Err.

\n
Safety
\n

Calling this method on an Err is undefined behavior.

\n
Examples
\n
let x: Result<u32, &str> = Ok(2);\nassert_eq!(unsafe { x.unwrap_unchecked() }, 2);
\n\n
let x: Result<u32, &str> = Err("emergency failure");\nunsafe { x.unwrap_unchecked(); } // Undefined behavior!
\n
1.58.0 · source

pub unsafe fn unwrap_err_unchecked(self) -> E

Returns the contained Err value, consuming the self value,\nwithout checking that the value is not an Ok.

\n
Safety
\n

Calling this method on an Ok is undefined behavior.

\n
Examples
\n
let x: Result<u32, &str> = Ok(2);\nunsafe { x.unwrap_err_unchecked() }; // Undefined behavior!
\n\n
let x: Result<u32, &str> = Err("emergency failure");\nassert_eq!(unsafe { x.unwrap_err_unchecked() }, "emergency failure");
\n
",0,"gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<T, E> Result<&T, E>

1.59.0 · source

pub fn copied(self) -> Result<T, E>where\n T: Copy,

Maps a Result<&T, E> to a Result<T, E> by copying the contents of the\nOk part.

\n
Examples
\n
let val = 12;\nlet x: Result<&i32, i32> = Ok(&val);\nassert_eq!(x, Ok(&12));\nlet copied = x.copied();\nassert_eq!(copied, Ok(12));
\n
1.59.0 · source

pub fn cloned(self) -> Result<T, E>where\n T: Clone,

Maps a Result<&T, E> to a Result<T, E> by cloning the contents of the\nOk part.

\n
Examples
\n
let val = 12;\nlet x: Result<&i32, i32> = Ok(&val);\nassert_eq!(x, Ok(&12));\nlet cloned = x.cloned();\nassert_eq!(cloned, Ok(12));
\n
",0,"gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<T, E> Result<&mut T, E>

1.59.0 · source

pub fn copied(self) -> Result<T, E>where\n T: Copy,

Maps a Result<&mut T, E> to a Result<T, E> by copying the contents of the\nOk part.

\n
Examples
\n
let mut val = 12;\nlet x: Result<&mut i32, i32> = Ok(&mut val);\nassert_eq!(x, Ok(&mut 12));\nlet copied = x.copied();\nassert_eq!(copied, Ok(12));
\n
1.59.0 · source

pub fn cloned(self) -> Result<T, E>where\n T: Clone,

Maps a Result<&mut T, E> to a Result<T, E> by cloning the contents of the\nOk part.

\n
Examples
\n
let mut val = 12;\nlet x: Result<&mut i32, i32> = Ok(&mut val);\nassert_eq!(x, Ok(&mut 12));\nlet cloned = x.cloned();\nassert_eq!(cloned, Ok(12));
\n
",0,"gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<T, E> Result<Option<T>, E>

1.33.0 (const: unstable) · source

pub fn transpose(self) -> Option<Result<T, E>>

Transposes a Result of an Option into an Option of a Result.

\n

Ok(None) will be mapped to None.\nOk(Some(_)) and Err(_) will be mapped to Some(Ok(_)) and Some(Err(_)).

\n
Examples
\n
#[derive(Debug, Eq, PartialEq)]\nstruct SomeErr;\n\nlet x: Result<Option<i32>, SomeErr> = Ok(Some(5));\nlet y: Option<Result<i32, SomeErr>> = Some(Ok(5));\nassert_eq!(x.transpose(), y);
\n
",0,"gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<T, E> Result<Result<T, E>, E>

source

pub fn flatten(self) -> Result<T, E>

🔬This is a nightly-only experimental API. (result_flattening)

Converts from Result<Result<T, E>, E> to Result<T, E>

\n
Examples
\n
#![feature(result_flattening)]\nlet x: Result<Result<&'static str, u32>, u32> = Ok(Ok("hello"));\nassert_eq!(Ok("hello"), x.flatten());\n\nlet x: Result<Result<&'static str, u32>, u32> = Ok(Err(6));\nassert_eq!(Err(6), x.flatten());\n\nlet x: Result<Result<&'static str, u32>, u32> = Err(6);\nassert_eq!(Err(6), x.flatten());
\n

Flattening only removes one level of nesting at a time:

\n\n
#![feature(result_flattening)]\nlet x: Result<Result<Result<&'static str, u32>, u32>, u32> = Ok(Ok(Ok("hello")));\nassert_eq!(Ok(Ok("hello")), x.flatten());\nassert_eq!(Ok("hello"), x.flatten().flatten());
\n
",0,"gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
1.61.0 · source§

impl<T, E> Termination for Result<T, E>where\n T: Termination,\n E: Debug,

source§

fn report(self) -> ExitCode

Is called to get the representation of the value as status code.\nThis status code is returned to the operating system.
","Termination","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<T, E, F> FromResidual<Yeet<E>> for Result<T, F>where\n F: From<E>,

source§

fn from_residual(_: Yeet<E>) -> Result<T, F>

🔬This is a nightly-only experimental API. (try_trait_v2)
Constructs the type from a compatible Residual type. Read more
","FromResidual>","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<T, E, F> FromResidual<Result<Infallible, E>> for Result<T, F>where\n F: From<E>,

source§

fn from_residual(residual: Result<Infallible, E>) -> Result<T, F>

🔬This is a nightly-only experimental API. (try_trait_v2)
Constructs the type from a compatible Residual type. Read more
","FromResidual>","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<T, E> Try for Result<T, E>

§

type Output = T

🔬This is a nightly-only experimental API. (try_trait_v2)
The type of the value produced by ? when not short-circuiting.
§

type Residual = Result<Infallible, E>

🔬This is a nightly-only experimental API. (try_trait_v2)
The type of the value passed to FromResidual::from_residual\nas part of ? when short-circuiting. Read more
source§

fn from_output(output: <Result<T, E> as Try>::Output) -> Result<T, E>

🔬This is a nightly-only experimental API. (try_trait_v2)
Constructs the type from its Output type. Read more
source§

fn branch(\n self\n) -> ControlFlow<<Result<T, E> as Try>::Residual, <Result<T, E> as Try>::Output>

🔬This is a nightly-only experimental API. (try_trait_v2)
Used in ? to decide whether the operator should produce a value\n(because this returned ControlFlow::Continue)\nor propagate a value back to the caller\n(because this returned ControlFlow::Break). Read more
","Try","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
1.0.0 · source§

impl<T, E> StructuralEq for Result<T, E>

","StructuralEq","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
1.0.0 · source§

impl<T, E> Eq for Result<T, E>where\n T: Eq,\n E: Eq,

","Eq","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
1.0.0 · source§

impl<A, E, V> FromIterator<Result<A, E>> for Result<V, E>where\n V: FromIterator<A>,

source§

fn from_iter<I>(iter: I) -> Result<V, E>where\n I: IntoIterator<Item = Result<A, E>>,

Takes each element in the Iterator: if it is an Err, no further\nelements are taken, and the Err is returned. Should no Err occur, a\ncontainer with the values of each Result is returned.

\n

Here is an example which increments every integer in a vector,\nchecking for overflow:

\n\n
let v = vec![1, 2];\nlet res: Result<Vec<u32>, &'static str> = v.iter().map(|x: &u32|\n    x.checked_add(1).ok_or("Overflow!")\n).collect();\nassert_eq!(res, Ok(vec![2, 3]));
\n

Here is another example that tries to subtract one from another list\nof integers, this time checking for underflow:

\n\n
let v = vec![1, 2, 0];\nlet res: Result<Vec<u32>, &'static str> = v.iter().map(|x: &u32|\n    x.checked_sub(1).ok_or("Underflow!")\n).collect();\nassert_eq!(res, Err("Underflow!"));
\n

Here is a variation on the previous example, showing that no\nfurther elements are taken from iter after the first Err.

\n\n
let v = vec![3, 2, 1, 10];\nlet mut shared = 0;\nlet res: Result<Vec<u32>, &'static str> = v.iter().map(|x: &u32| {\n    shared += x;\n    x.checked_sub(2).ok_or("Underflow!")\n}).collect();\nassert_eq!(res, Err("Underflow!"));\nassert_eq!(shared, 6);
\n

Since the third element caused an underflow, no further elements were taken,\nso the final value of shared is 6 (= 3 + 2 + 1), not 16.

\n
","FromIterator>","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
1.0.0 · source§

impl<T, E> Ord for Result<T, E>where\n T: Ord,\n E: Ord,

source§

fn cmp(&self, other: &Result<T, E>) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Selfwhere\n Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Selfwhere\n Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Selfwhere\n Self: Sized + PartialOrd,

Restrict a value to a certain interval. Read more
","Ord","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
1.0.0 · source§

impl<T, E> PartialEq for Result<T, E>where\n T: PartialEq,\n E: PartialEq,

source§

fn eq(&self, other: &Result<T, E>) -> bool

This method tests for self and other values to be equal, and is used\nby ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always\nsufficient, and should not be overridden without very good reason.
","PartialEq","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
1.0.0 · source§

impl<T, E> Clone for Result<T, E>where\n T: Clone,\n E: Clone,

source§

fn clone(&self) -> Result<T, E>

Returns a copy of the value. Read more
source§

fn clone_from(&mut self, source: &Result<T, E>)

Performs copy-assignment from source. Read more
","Clone","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
1.0.0 · source§

impl<T, E> Hash for Result<T, E>where\n T: Hash,\n E: Hash,

source§

fn hash<__H>(&self, state: &mut __H)where\n __H: Hasher,

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)where\n H: Hasher,\n Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
","Hash","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
1.0.0 · source§

impl<T, E> IntoIterator for Result<T, E>

source§

fn into_iter(self) -> IntoIter<T>

Returns a consuming iterator over the possibly contained value.

\n

The iterator yields one value if the result is Result::Ok, otherwise none.

\n
Examples
\n
let x: Result<u32, &str> = Ok(5);\nlet v: Vec<u32> = x.into_iter().collect();\nassert_eq!(v, [5]);\n\nlet x: Result<u32, &str> = Err("nothing!");\nlet v: Vec<u32> = x.into_iter().collect();\nassert_eq!(v, []);
\n
§

type Item = T

The type of the elements being iterated over.
§

type IntoIter = IntoIter<T>

Which kind of iterator are we turning this into?
","IntoIterator","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<T, E> Residual<T> for Result<Infallible, E>

§

type TryType = Result<T, E>

🔬This is a nightly-only experimental API. (try_trait_v2_residual)
The “return” type of this meta-function.
","Residual","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
1.0.0 · source§

impl<T, E> StructuralPartialEq for Result<T, E>

","StructuralPartialEq","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
1.16.0 · source§

impl<T, U, E> Sum<Result<U, E>> for Result<T, E>where\n T: Sum<U>,

source§

fn sum<I>(iter: I) -> Result<T, E>where\n I: Iterator<Item = Result<U, E>>,

Takes each element in the Iterator: if it is an Err, no further\nelements are taken, and the Err is returned. Should no Err\noccur, the sum of all elements is returned.

\n
Examples
\n

This sums up every integer in a vector, rejecting the sum if a negative\nelement is encountered:

\n\n
let f = |&x: &i32| if x < 0 { Err("Negative element found") } else { Ok(x) };\nlet v = vec![1, 2];\nlet res: Result<i32, _> = v.iter().map(f).sum();\nassert_eq!(res, Ok(3));\nlet v = vec![1, -2];\nlet res: Result<i32, _> = v.iter().map(f).sum();\nassert_eq!(res, Err("Negative element found"));
\n
","Sum>","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
1.0.0 · source§

impl<T, E> Debug for Result<T, E>where\n T: Debug,\n E: Debug,

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
","Debug","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
1.0.0 · source§

impl<T, E> PartialOrd for Result<T, E>where\n T: PartialOrd,\n E: PartialOrd,

source§

fn partial_cmp(&self, other: &Result<T, E>) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <=\noperator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >=\noperator. Read more
","PartialOrd","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
1.0.0 · source§

impl<T, E> Copy for Result<T, E>where\n T: Copy,\n E: Copy,

","Copy","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
1.16.0 · source§

impl<T, U, E> Product<Result<U, E>> for Result<T, E>where\n T: Product<U>,

source§

fn product<I>(iter: I) -> Result<T, E>where\n I: Iterator<Item = Result<U, E>>,

Takes each element in the Iterator: if it is an Err, no further\nelements are taken, and the Err is returned. Should no Err\noccur, the product of all elements is returned.

\n
Examples
\n

This multiplies each number in a vector of strings,\nif a string could not be parsed the operation returns Err:

\n\n
let nums = vec!["5", "10", "1", "2"];\nlet total: Result<usize, _> = nums.iter().map(|w| w.parse::<usize>()).product();\nassert_eq!(total, Ok(100));\nlet nums = vec!["5", "10", "one", "2"];\nlet total: Result<usize, _> = nums.iter().map(|w| w.parse::<usize>()).product();\nassert!(total.is_err());
\n
","Product>","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<T, E> Serialize for Result<T, E>where\n T: Serialize,\n E: Serialize,

source§

fn serialize<S>(\n &self,\n serializer: S\n) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>where\n S: Serializer,

Serialize this value into the given Serde serializer. Read more
","Serialize","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<'de, T, E> Deserialize<'de> for Result<T, E>where\n T: Deserialize<'de>,\n E: Deserialize<'de>,

source§

fn deserialize<D>(\n deserializer: D\n) -> Result<Result<T, E>, <D as Deserializer<'de>>::Error>where\n D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
","Deserialize<'de>","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<T, E> MapHandlerError<T> for Result<T, E>where\n E: Into<Error> + Display,

source§

fn map_err_with_status(self, status_code: StatusCode) -> Result<T, HandlerError>

Equivalent of map_err(|err| HandlerError::from(err).with_status(status_code)).
","MapHandlerError","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<T, E> IntoResponse for Result<T, E>where\n T: IntoResponse,\n E: IntoResponse,

source§

fn into_response(self, state: &State) -> Response<Body>

Converts this value into a hyper::Response
","IntoResponse","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<T, E> Context<T, E> for Result<T, E>where\n E: StdError + Send + Sync + 'static,

source§

fn context<C>(self, context: C) -> Result<T, Error>where\n C: Display + Send + Sync + 'static,

Wrap the error value with additional context.
source§

fn with_context<C, F>(self, context: F) -> Result<T, Error>where\n C: Display + Send + Sync + 'static,\n F: FnOnce() -> C,

Wrap the error value with additional context that is evaluated lazily\nonly once an error does occur.
","Context","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<E> ResponseSchema for Result<NoContent, E>where\n E: Debug + IntoResponseError<Err = Error>,

source§

fn status_codes() -> Vec<StatusCode>

All status codes returned by this response. Returns [StatusCode::OK] by default.
source§

fn schema(code: StatusCode) -> OpenapiSchema

Return the schema of the response for the given status code. The code may\nonly be one that was previously returned by Self::status_codes. The\nimplementation should panic if that is not the case.
","ResponseSchema","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<E> IntoResponse for Result<NoContent, E>where\n E: Debug + IntoResponseError<Err = Error>,

§

type Err = Error

source§

fn into_response(\n self\n) -> Pin<Box<dyn Future<Output = Result<Response, Error>> + Send>>

Turn this into a response that can be returned to the browser. This api will likely\nchange in the future.
source§

fn accepted_types() -> Option<Vec<Mime>>

Return a list of supported mime types.
","IntoResponse","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<T, E> IntoResponse for Result<Raw<T>, E>where\n Raw<T>: IntoResponse,\n E: Debug + IntoResponseError<Err = <Raw<T> as IntoResponse>::Err>,

§

type Err = <E as IntoResponseError>::Err

source§

fn into_response(\n self\n) -> Pin<Box<dyn Future<Output = Result<Response, E::Err>> + Send>>

Turn this into a response that can be returned to the browser. This api will likely\nchange in the future.
source§

fn accepted_types() -> Option<Vec<Mime>>

Return a list of supported mime types.
","IntoResponse","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<R, E> ResponseSchema for Result<R, E>where\n R: ResponseBody,\n E: Debug + IntoResponseError<Err = Error>,

source§

fn status_codes() -> Vec<StatusCode>

All status codes returned by this response. Returns [StatusCode::OK] by default.
source§

fn schema(code: StatusCode) -> OpenapiSchema

Return the schema of the response for the given status code. The code may\nonly be one that was previously returned by Self::status_codes. The\nimplementation should panic if that is not the case.
","ResponseSchema","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<E> IntoResponse for Result<Redirect, E>where\n E: Debug + IntoResponseError,\n <E as IntoResponseError>::Err: StdError + Sync,

§

type Err = RedirectError<<E as IntoResponseError>::Err>

source§

fn into_response(self) -> BoxFuture<'static, Result<Response, Self::Err>>

Turn this into a response that can be returned to the browser. This api will likely\nchange in the future.
source§

fn accepted_types() -> Option<Vec<Mime>>

Return a list of supported mime types.
","IntoResponse","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<R, E> IntoResponse for Result<R, E>where\n R: ResponseBody,\n E: Debug + IntoResponseError<Err = Error>,

§

type Err = <E as IntoResponseError>::Err

source§

fn into_response(\n self\n) -> Pin<Box<dyn Future<Output = Result<Response, E::Err>> + Send>>

Turn this into a response that can be returned to the browser. This api will likely\nchange in the future.
source§

fn accepted_types() -> Option<Vec<Mime>>

Return a list of supported mime types.
","IntoResponse","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<T, E> ResponseSchema for Result<Raw<T>, E>where\n Raw<T>: IntoResponseWithSchema,\n E: Debug + IntoResponseError<Err = <Raw<T> as IntoResponse>::Err>,

source§

fn status_codes() -> Vec<StatusCode>

All status codes returned by this response. Returns [StatusCode::OK] by default.
source§

fn schema(code: StatusCode) -> OpenapiSchema

Return the schema of the response for the given status code. The code may\nonly be one that was previously returned by Self::status_codes. The\nimplementation should panic if that is not the case.
","ResponseSchema","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<E> ResponseSchema for Result<Redirect, E>where\n E: Debug + IntoResponseError,\n <E as IntoResponseError>::Err: StdError + Sync,

source§

fn status_codes() -> Vec<StatusCode>

All status codes returned by this response. Returns [StatusCode::OK] by default.
source§

fn schema(code: StatusCode) -> OpenapiSchema

Return the schema of the response for the given status code. The code may\nonly be one that was previously returned by Self::status_codes. The\nimplementation should panic if that is not the case.
","ResponseSchema","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"]] +"gotham_restful":[["
source§

impl<T, E> Result<T, E>

1.0.0 (const: 1.48.0) · source

pub const fn is_ok(&self) -> bool

Returns true if the result is Ok.

\n
Examples
\n
let x: Result<i32, &str> = Ok(-3);\nassert_eq!(x.is_ok(), true);\n\nlet x: Result<i32, &str> = Err("Some error message");\nassert_eq!(x.is_ok(), false);
\n
1.70.0 · source

pub fn is_ok_and(self, f: impl FnOnce(T) -> bool) -> bool

Returns true if the result is Ok and the value inside of it matches a predicate.

\n
Examples
\n
let x: Result<u32, &str> = Ok(2);\nassert_eq!(x.is_ok_and(|x| x > 1), true);\n\nlet x: Result<u32, &str> = Ok(0);\nassert_eq!(x.is_ok_and(|x| x > 1), false);\n\nlet x: Result<u32, &str> = Err("hey");\nassert_eq!(x.is_ok_and(|x| x > 1), false);
\n
1.0.0 (const: 1.48.0) · source

pub const fn is_err(&self) -> bool

Returns true if the result is Err.

\n
Examples
\n
let x: Result<i32, &str> = Ok(-3);\nassert_eq!(x.is_err(), false);\n\nlet x: Result<i32, &str> = Err("Some error message");\nassert_eq!(x.is_err(), true);
\n
1.70.0 · source

pub fn is_err_and(self, f: impl FnOnce(E) -> bool) -> bool

Returns true if the result is Err and the value inside of it matches a predicate.

\n
Examples
\n
use std::io::{Error, ErrorKind};\n\nlet x: Result<u32, Error> = Err(Error::new(ErrorKind::NotFound, "!"));\nassert_eq!(x.is_err_and(|x| x.kind() == ErrorKind::NotFound), true);\n\nlet x: Result<u32, Error> = Err(Error::new(ErrorKind::PermissionDenied, "!"));\nassert_eq!(x.is_err_and(|x| x.kind() == ErrorKind::NotFound), false);\n\nlet x: Result<u32, Error> = Ok(123);\nassert_eq!(x.is_err_and(|x| x.kind() == ErrorKind::NotFound), false);
\n
1.0.0 · source

pub fn ok(self) -> Option<T>

Converts from Result<T, E> to Option<T>.

\n

Converts self into an Option<T>, consuming self,\nand discarding the error, if any.

\n
Examples
\n
let x: Result<u32, &str> = Ok(2);\nassert_eq!(x.ok(), Some(2));\n\nlet x: Result<u32, &str> = Err("Nothing here");\nassert_eq!(x.ok(), None);
\n
1.0.0 · source

pub fn err(self) -> Option<E>

Converts from Result<T, E> to Option<E>.

\n

Converts self into an Option<E>, consuming self,\nand discarding the success value, if any.

\n
Examples
\n
let x: Result<u32, &str> = Ok(2);\nassert_eq!(x.err(), None);\n\nlet x: Result<u32, &str> = Err("Nothing here");\nassert_eq!(x.err(), Some("Nothing here"));
\n
1.0.0 (const: 1.48.0) · source

pub const fn as_ref(&self) -> Result<&T, &E>

Converts from &Result<T, E> to Result<&T, &E>.

\n

Produces a new Result, containing a reference\ninto the original, leaving the original in place.

\n
Examples
\n
let x: Result<u32, &str> = Ok(2);\nassert_eq!(x.as_ref(), Ok(&2));\n\nlet x: Result<u32, &str> = Err("Error");\nassert_eq!(x.as_ref(), Err(&"Error"));
\n
1.0.0 (const: unstable) · source

pub fn as_mut(&mut self) -> Result<&mut T, &mut E>

Converts from &mut Result<T, E> to Result<&mut T, &mut E>.

\n
Examples
\n
fn mutate(r: &mut Result<i32, i32>) {\n    match r.as_mut() {\n        Ok(v) => *v = 42,\n        Err(e) => *e = 0,\n    }\n}\n\nlet mut x: Result<i32, i32> = Ok(2);\nmutate(&mut x);\nassert_eq!(x.unwrap(), 42);\n\nlet mut x: Result<i32, i32> = Err(13);\nmutate(&mut x);\nassert_eq!(x.unwrap_err(), 0);
\n
1.0.0 · source

pub fn map<U, F>(self, op: F) -> Result<U, E>where\n F: FnOnce(T) -> U,

Maps a Result<T, E> to Result<U, E> by applying a function to a\ncontained Ok value, leaving an Err value untouched.

\n

This function can be used to compose the results of two functions.

\n
Examples
\n

Print the numbers on each line of a string multiplied by two.

\n\n
let line = "1\\n2\\n3\\n4\\n";\n\nfor num in line.lines() {\n    match num.parse::<i32>().map(|i| i * 2) {\n        Ok(n) => println!("{n}"),\n        Err(..) => {}\n    }\n}
\n
1.41.0 · source

pub fn map_or<U, F>(self, default: U, f: F) -> Uwhere\n F: FnOnce(T) -> U,

Returns the provided default (if Err), or\napplies a function to the contained value (if Ok).

\n

Arguments passed to map_or are eagerly evaluated; if you are passing\nthe result of a function call, it is recommended to use map_or_else,\nwhich is lazily evaluated.

\n
Examples
\n
let x: Result<_, &str> = Ok("foo");\nassert_eq!(x.map_or(42, |v| v.len()), 3);\n\nlet x: Result<&str, _> = Err("bar");\nassert_eq!(x.map_or(42, |v| v.len()), 42);
\n
1.41.0 · source

pub fn map_or_else<U, D, F>(self, default: D, f: F) -> Uwhere\n D: FnOnce(E) -> U,\n F: FnOnce(T) -> U,

Maps a Result<T, E> to U by applying fallback function default to\na contained Err value, or function f to a contained Ok value.

\n

This function can be used to unpack a successful result\nwhile handling an error.

\n
Examples
\n
let k = 21;\n\nlet x : Result<_, &str> = Ok("foo");\nassert_eq!(x.map_or_else(|e| k * 2, |v| v.len()), 3);\n\nlet x : Result<&str, _> = Err("bar");\nassert_eq!(x.map_or_else(|e| k * 2, |v| v.len()), 42);
\n
1.0.0 · source

pub fn map_err<F, O>(self, op: O) -> Result<T, F>where\n O: FnOnce(E) -> F,

Maps a Result<T, E> to Result<T, F> by applying a function to a\ncontained Err value, leaving an Ok value untouched.

\n

This function can be used to pass through a successful result while handling\nan error.

\n
Examples
\n
fn stringify(x: u32) -> String { format!("error code: {x}") }\n\nlet x: Result<u32, u32> = Ok(2);\nassert_eq!(x.map_err(stringify), Ok(2));\n\nlet x: Result<u32, u32> = Err(13);\nassert_eq!(x.map_err(stringify), Err("error code: 13".to_string()));
\n
source

pub fn inspect<F>(self, f: F) -> Result<T, E>where\n F: FnOnce(&T),

🔬This is a nightly-only experimental API. (result_option_inspect)

Calls the provided closure with a reference to the contained value (if Ok).

\n
Examples
\n
#![feature(result_option_inspect)]\n\nlet x: u8 = "4"\n    .parse::<u8>()\n    .inspect(|x| println!("original: {x}"))\n    .map(|x| x.pow(3))\n    .expect("failed to parse number");
\n
source

pub fn inspect_err<F>(self, f: F) -> Result<T, E>where\n F: FnOnce(&E),

🔬This is a nightly-only experimental API. (result_option_inspect)

Calls the provided closure with a reference to the contained error (if Err).

\n
Examples
\n
#![feature(result_option_inspect)]\n\nuse std::{fs, io};\n\nfn read() -> io::Result<String> {\n    fs::read_to_string("address.txt")\n        .inspect_err(|e| eprintln!("failed to read file: {e}"))\n}
\n
1.47.0 · source

pub fn as_deref(&self) -> Result<&<T as Deref>::Target, &E>where\n T: Deref,

Converts from Result<T, E> (or &Result<T, E>) to Result<&<T as Deref>::Target, &E>.

\n

Coerces the Ok variant of the original Result via Deref\nand returns the new Result.

\n
Examples
\n
let x: Result<String, u32> = Ok("hello".to_string());\nlet y: Result<&str, &u32> = Ok("hello");\nassert_eq!(x.as_deref(), y);\n\nlet x: Result<String, u32> = Err(42);\nlet y: Result<&str, &u32> = Err(&42);\nassert_eq!(x.as_deref(), y);
\n
1.47.0 · source

pub fn as_deref_mut(&mut self) -> Result<&mut <T as Deref>::Target, &mut E>where\n T: DerefMut,

Converts from Result<T, E> (or &mut Result<T, E>) to Result<&mut <T as DerefMut>::Target, &mut E>.

\n

Coerces the Ok variant of the original Result via DerefMut\nand returns the new Result.

\n
Examples
\n
let mut s = "HELLO".to_string();\nlet mut x: Result<String, u32> = Ok("hello".to_string());\nlet y: Result<&mut str, &mut u32> = Ok(&mut s);\nassert_eq!(x.as_deref_mut().map(|x| { x.make_ascii_uppercase(); x }), y);\n\nlet mut i = 42;\nlet mut x: Result<String, u32> = Err(42);\nlet y: Result<&mut str, &mut u32> = Err(&mut i);\nassert_eq!(x.as_deref_mut().map(|x| { x.make_ascii_uppercase(); x }), y);
\n
1.0.0 · source

pub fn iter(&self) -> Iter<'_, T>

Returns an iterator over the possibly contained value.

\n

The iterator yields one value if the result is Result::Ok, otherwise none.

\n
Examples
\n
let x: Result<u32, &str> = Ok(7);\nassert_eq!(x.iter().next(), Some(&7));\n\nlet x: Result<u32, &str> = Err("nothing!");\nassert_eq!(x.iter().next(), None);
\n
1.0.0 · source

pub fn iter_mut(&mut self) -> IterMut<'_, T>

Returns a mutable iterator over the possibly contained value.

\n

The iterator yields one value if the result is Result::Ok, otherwise none.

\n
Examples
\n
let mut x: Result<u32, &str> = Ok(7);\nmatch x.iter_mut().next() {\n    Some(v) => *v = 40,\n    None => {},\n}\nassert_eq!(x, Ok(40));\n\nlet mut x: Result<u32, &str> = Err("nothing!");\nassert_eq!(x.iter_mut().next(), None);
\n
1.4.0 · source

pub fn expect(self, msg: &str) -> Twhere\n E: Debug,

Returns the contained Ok value, consuming the self value.

\n

Because this function may panic, its use is generally discouraged.\nInstead, prefer to use pattern matching and handle the Err\ncase explicitly, or call unwrap_or, unwrap_or_else, or\nunwrap_or_default.

\n
Panics
\n

Panics if the value is an Err, with a panic message including the\npassed message, and the content of the Err.

\n
Examples
\n
let x: Result<u32, &str> = Err("emergency failure");\nx.expect("Testing expect"); // panics with `Testing expect: emergency failure`
\n
Recommended Message Style
\n

We recommend that expect messages are used to describe the reason you\nexpect the Result should be Ok.

\n\n
let path = std::env::var("IMPORTANT_PATH")\n    .expect("env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`");
\n

Hint: If you’re having trouble remembering how to phrase expect\nerror messages remember to focus on the word “should” as in “env\nvariable should be set by blah” or “the given binary should be available\nand executable by the current user”.

\n

For more detail on expect message styles and the reasoning behind our recommendation please\nrefer to the section on “Common Message\nStyles” in the\nstd::error module docs.

\n
1.0.0 · source

pub fn unwrap(self) -> Twhere\n E: Debug,

Returns the contained Ok value, consuming the self value.

\n

Because this function may panic, its use is generally discouraged.\nInstead, prefer to use pattern matching and handle the Err\ncase explicitly, or call unwrap_or, unwrap_or_else, or\nunwrap_or_default.

\n
Panics
\n

Panics if the value is an Err, with a panic message provided by the\nErr’s value.

\n
Examples
\n

Basic usage:

\n\n
let x: Result<u32, &str> = Ok(2);\nassert_eq!(x.unwrap(), 2);
\n\n
let x: Result<u32, &str> = Err("emergency failure");\nx.unwrap(); // panics with `emergency failure`
\n
1.16.0 · source

pub fn unwrap_or_default(self) -> Twhere\n T: Default,

Returns the contained Ok value or a default

\n

Consumes the self argument then, if Ok, returns the contained\nvalue, otherwise if Err, returns the default value for that\ntype.

\n
Examples
\n

Converts a string to an integer, turning poorly-formed strings\ninto 0 (the default value for integers). parse converts\na string to any other type that implements FromStr, returning an\nErr on error.

\n\n
let good_year_from_input = "1909";\nlet bad_year_from_input = "190blarg";\nlet good_year = good_year_from_input.parse().unwrap_or_default();\nlet bad_year = bad_year_from_input.parse().unwrap_or_default();\n\nassert_eq!(1909, good_year);\nassert_eq!(0, bad_year);
\n
1.17.0 · source

pub fn expect_err(self, msg: &str) -> Ewhere\n T: Debug,

Returns the contained Err value, consuming the self value.

\n
Panics
\n

Panics if the value is an Ok, with a panic message including the\npassed message, and the content of the Ok.

\n
Examples
\n
let x: Result<u32, &str> = Ok(10);\nx.expect_err("Testing expect_err"); // panics with `Testing expect_err: 10`
\n
1.0.0 · source

pub fn unwrap_err(self) -> Ewhere\n T: Debug,

Returns the contained Err value, consuming the self value.

\n
Panics
\n

Panics if the value is an Ok, with a custom panic message provided\nby the Ok’s value.

\n
Examples
\n
let x: Result<u32, &str> = Ok(2);\nx.unwrap_err(); // panics with `2`
\n\n
let x: Result<u32, &str> = Err("emergency failure");\nassert_eq!(x.unwrap_err(), "emergency failure");
\n
source

pub fn into_ok(self) -> Twhere\n E: Into<!>,

🔬This is a nightly-only experimental API. (unwrap_infallible)

Returns the contained Ok value, but never panics.

\n

Unlike unwrap, this method is known to never panic on the\nresult types it is implemented for. Therefore, it can be used\ninstead of unwrap as a maintainability safeguard that will fail\nto compile if the error type of the Result is later changed\nto an error that can actually occur.

\n
Examples
\n
\nfn only_good_news() -> Result<String, !> {\n    Ok("this is fine".into())\n}\n\nlet s: String = only_good_news().into_ok();\nprintln!("{s}");
\n
source

pub fn into_err(self) -> Ewhere\n T: Into<!>,

🔬This is a nightly-only experimental API. (unwrap_infallible)

Returns the contained Err value, but never panics.

\n

Unlike unwrap_err, this method is known to never panic on the\nresult types it is implemented for. Therefore, it can be used\ninstead of unwrap_err as a maintainability safeguard that will fail\nto compile if the ok type of the Result is later changed\nto a type that can actually occur.

\n
Examples
\n
\nfn only_bad_news() -> Result<!, String> {\n    Err("Oops, it failed".into())\n}\n\nlet error: String = only_bad_news().into_err();\nprintln!("{error}");
\n
1.0.0 · source

pub fn and<U>(self, res: Result<U, E>) -> Result<U, E>

Returns res if the result is Ok, otherwise returns the Err value of self.

\n

Arguments passed to and are eagerly evaluated; if you are passing the\nresult of a function call, it is recommended to use and_then, which is\nlazily evaluated.

\n
Examples
\n
let x: Result<u32, &str> = Ok(2);\nlet y: Result<&str, &str> = Err("late error");\nassert_eq!(x.and(y), Err("late error"));\n\nlet x: Result<u32, &str> = Err("early error");\nlet y: Result<&str, &str> = Ok("foo");\nassert_eq!(x.and(y), Err("early error"));\n\nlet x: Result<u32, &str> = Err("not a 2");\nlet y: Result<&str, &str> = Err("late error");\nassert_eq!(x.and(y), Err("not a 2"));\n\nlet x: Result<u32, &str> = Ok(2);\nlet y: Result<&str, &str> = Ok("different result type");\nassert_eq!(x.and(y), Ok("different result type"));
\n
1.0.0 · source

pub fn and_then<U, F>(self, op: F) -> Result<U, E>where\n F: FnOnce(T) -> Result<U, E>,

Calls op if the result is Ok, otherwise returns the Err value of self.

\n

This function can be used for control flow based on Result values.

\n
Examples
\n
fn sq_then_to_string(x: u32) -> Result<String, &'static str> {\n    x.checked_mul(x).map(|sq| sq.to_string()).ok_or("overflowed")\n}\n\nassert_eq!(Ok(2).and_then(sq_then_to_string), Ok(4.to_string()));\nassert_eq!(Ok(1_000_000).and_then(sq_then_to_string), Err("overflowed"));\nassert_eq!(Err("not a number").and_then(sq_then_to_string), Err("not a number"));
\n

Often used to chain fallible operations that may return Err.

\n\n
use std::{io::ErrorKind, path::Path};\n\n// Note: on Windows "/" maps to "C:\\"\nlet root_modified_time = Path::new("/").metadata().and_then(|md| md.modified());\nassert!(root_modified_time.is_ok());\n\nlet should_fail = Path::new("/bad/path").metadata().and_then(|md| md.modified());\nassert!(should_fail.is_err());\nassert_eq!(should_fail.unwrap_err().kind(), ErrorKind::NotFound);
\n
1.0.0 · source

pub fn or<F>(self, res: Result<T, F>) -> Result<T, F>

Returns res if the result is Err, otherwise returns the Ok value of self.

\n

Arguments passed to or are eagerly evaluated; if you are passing the\nresult of a function call, it is recommended to use or_else, which is\nlazily evaluated.

\n
Examples
\n
let x: Result<u32, &str> = Ok(2);\nlet y: Result<u32, &str> = Err("late error");\nassert_eq!(x.or(y), Ok(2));\n\nlet x: Result<u32, &str> = Err("early error");\nlet y: Result<u32, &str> = Ok(2);\nassert_eq!(x.or(y), Ok(2));\n\nlet x: Result<u32, &str> = Err("not a 2");\nlet y: Result<u32, &str> = Err("late error");\nassert_eq!(x.or(y), Err("late error"));\n\nlet x: Result<u32, &str> = Ok(2);\nlet y: Result<u32, &str> = Ok(100);\nassert_eq!(x.or(y), Ok(2));
\n
1.0.0 · source

pub fn or_else<F, O>(self, op: O) -> Result<T, F>where\n O: FnOnce(E) -> Result<T, F>,

Calls op if the result is Err, otherwise returns the Ok value of self.

\n

This function can be used for control flow based on result values.

\n
Examples
\n
fn sq(x: u32) -> Result<u32, u32> { Ok(x * x) }\nfn err(x: u32) -> Result<u32, u32> { Err(x) }\n\nassert_eq!(Ok(2).or_else(sq).or_else(sq), Ok(2));\nassert_eq!(Ok(2).or_else(err).or_else(sq), Ok(2));\nassert_eq!(Err(3).or_else(sq).or_else(err), Ok(9));\nassert_eq!(Err(3).or_else(err).or_else(err), Err(3));
\n
1.0.0 · source

pub fn unwrap_or(self, default: T) -> T

Returns the contained Ok value or a provided default.

\n

Arguments passed to unwrap_or are eagerly evaluated; if you are passing\nthe result of a function call, it is recommended to use unwrap_or_else,\nwhich is lazily evaluated.

\n
Examples
\n
let default = 2;\nlet x: Result<u32, &str> = Ok(9);\nassert_eq!(x.unwrap_or(default), 9);\n\nlet x: Result<u32, &str> = Err("error");\nassert_eq!(x.unwrap_or(default), default);
\n
1.0.0 · source

pub fn unwrap_or_else<F>(self, op: F) -> Twhere\n F: FnOnce(E) -> T,

Returns the contained Ok value or computes it from a closure.

\n
Examples
\n
fn count(x: &str) -> usize { x.len() }\n\nassert_eq!(Ok(2).unwrap_or_else(count), 2);\nassert_eq!(Err("foo").unwrap_or_else(count), 3);
\n
1.58.0 · source

pub unsafe fn unwrap_unchecked(self) -> T

Returns the contained Ok value, consuming the self value,\nwithout checking that the value is not an Err.

\n
Safety
\n

Calling this method on an Err is undefined behavior.

\n
Examples
\n
let x: Result<u32, &str> = Ok(2);\nassert_eq!(unsafe { x.unwrap_unchecked() }, 2);
\n\n
let x: Result<u32, &str> = Err("emergency failure");\nunsafe { x.unwrap_unchecked(); } // Undefined behavior!
\n
1.58.0 · source

pub unsafe fn unwrap_err_unchecked(self) -> E

Returns the contained Err value, consuming the self value,\nwithout checking that the value is not an Ok.

\n
Safety
\n

Calling this method on an Ok is undefined behavior.

\n
Examples
\n
let x: Result<u32, &str> = Ok(2);\nunsafe { x.unwrap_err_unchecked() }; // Undefined behavior!
\n\n
let x: Result<u32, &str> = Err("emergency failure");\nassert_eq!(unsafe { x.unwrap_err_unchecked() }, "emergency failure");
\n
",0,"gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<T, E> Result<&T, E>

1.59.0 · source

pub fn copied(self) -> Result<T, E>where\n T: Copy,

Maps a Result<&T, E> to a Result<T, E> by copying the contents of the\nOk part.

\n
Examples
\n
let val = 12;\nlet x: Result<&i32, i32> = Ok(&val);\nassert_eq!(x, Ok(&12));\nlet copied = x.copied();\nassert_eq!(copied, Ok(12));
\n
1.59.0 · source

pub fn cloned(self) -> Result<T, E>where\n T: Clone,

Maps a Result<&T, E> to a Result<T, E> by cloning the contents of the\nOk part.

\n
Examples
\n
let val = 12;\nlet x: Result<&i32, i32> = Ok(&val);\nassert_eq!(x, Ok(&12));\nlet cloned = x.cloned();\nassert_eq!(cloned, Ok(12));
\n
",0,"gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<T, E> Result<&mut T, E>

1.59.0 · source

pub fn copied(self) -> Result<T, E>where\n T: Copy,

Maps a Result<&mut T, E> to a Result<T, E> by copying the contents of the\nOk part.

\n
Examples
\n
let mut val = 12;\nlet x: Result<&mut i32, i32> = Ok(&mut val);\nassert_eq!(x, Ok(&mut 12));\nlet copied = x.copied();\nassert_eq!(copied, Ok(12));
\n
1.59.0 · source

pub fn cloned(self) -> Result<T, E>where\n T: Clone,

Maps a Result<&mut T, E> to a Result<T, E> by cloning the contents of the\nOk part.

\n
Examples
\n
let mut val = 12;\nlet x: Result<&mut i32, i32> = Ok(&mut val);\nassert_eq!(x, Ok(&mut 12));\nlet cloned = x.cloned();\nassert_eq!(cloned, Ok(12));
\n
",0,"gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<T, E> Result<Option<T>, E>

1.33.0 (const: unstable) · source

pub fn transpose(self) -> Option<Result<T, E>>

Transposes a Result of an Option into an Option of a Result.

\n

Ok(None) will be mapped to None.\nOk(Some(_)) and Err(_) will be mapped to Some(Ok(_)) and Some(Err(_)).

\n
Examples
\n
#[derive(Debug, Eq, PartialEq)]\nstruct SomeErr;\n\nlet x: Result<Option<i32>, SomeErr> = Ok(Some(5));\nlet y: Option<Result<i32, SomeErr>> = Some(Ok(5));\nassert_eq!(x.transpose(), y);
\n
",0,"gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<T, E> Result<Result<T, E>, E>

source

pub fn flatten(self) -> Result<T, E>

🔬This is a nightly-only experimental API. (result_flattening)

Converts from Result<Result<T, E>, E> to Result<T, E>

\n
Examples
\n
#![feature(result_flattening)]\nlet x: Result<Result<&'static str, u32>, u32> = Ok(Ok("hello"));\nassert_eq!(Ok("hello"), x.flatten());\n\nlet x: Result<Result<&'static str, u32>, u32> = Ok(Err(6));\nassert_eq!(Err(6), x.flatten());\n\nlet x: Result<Result<&'static str, u32>, u32> = Err(6);\nassert_eq!(Err(6), x.flatten());
\n

Flattening only removes one level of nesting at a time:

\n\n
#![feature(result_flattening)]\nlet x: Result<Result<Result<&'static str, u32>, u32>, u32> = Ok(Ok(Ok("hello")));\nassert_eq!(Ok(Ok("hello")), x.flatten());\nassert_eq!(Ok("hello"), x.flatten().flatten());
\n
",0,"gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
1.61.0 · source§

impl<T, E> Termination for Result<T, E>where\n T: Termination,\n E: Debug,

source§

fn report(self) -> ExitCode

Is called to get the representation of the value as status code.\nThis status code is returned to the operating system.
","Termination","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<T, E, F> FromResidual<Yeet<E>> for Result<T, F>where\n F: From<E>,

source§

fn from_residual(_: Yeet<E>) -> Result<T, F>

🔬This is a nightly-only experimental API. (try_trait_v2)
Constructs the type from a compatible Residual type. Read more
","FromResidual>","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<T, E, F> FromResidual<Result<Infallible, E>> for Result<T, F>where\n F: From<E>,

source§

fn from_residual(residual: Result<Infallible, E>) -> Result<T, F>

🔬This is a nightly-only experimental API. (try_trait_v2)
Constructs the type from a compatible Residual type. Read more
","FromResidual>","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<T, E> Try for Result<T, E>

§

type Output = T

🔬This is a nightly-only experimental API. (try_trait_v2)
The type of the value produced by ? when not short-circuiting.
§

type Residual = Result<Infallible, E>

🔬This is a nightly-only experimental API. (try_trait_v2)
The type of the value passed to FromResidual::from_residual\nas part of ? when short-circuiting. Read more
source§

fn from_output(output: <Result<T, E> as Try>::Output) -> Result<T, E>

🔬This is a nightly-only experimental API. (try_trait_v2)
Constructs the type from its Output type. Read more
source§

fn branch(\n self\n) -> ControlFlow<<Result<T, E> as Try>::Residual, <Result<T, E> as Try>::Output>

🔬This is a nightly-only experimental API. (try_trait_v2)
Used in ? to decide whether the operator should produce a value\n(because this returned ControlFlow::Continue)\nor propagate a value back to the caller\n(because this returned ControlFlow::Break). Read more
","Try","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
1.0.0 · source§

impl<T, E> StructuralEq for Result<T, E>

","StructuralEq","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
1.0.0 · source§

impl<T, E> Eq for Result<T, E>where\n T: Eq,\n E: Eq,

","Eq","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
1.0.0 · source§

impl<A, E, V> FromIterator<Result<A, E>> for Result<V, E>where\n V: FromIterator<A>,

source§

fn from_iter<I>(iter: I) -> Result<V, E>where\n I: IntoIterator<Item = Result<A, E>>,

Takes each element in the Iterator: if it is an Err, no further\nelements are taken, and the Err is returned. Should no Err occur, a\ncontainer with the values of each Result is returned.

\n

Here is an example which increments every integer in a vector,\nchecking for overflow:

\n\n
let v = vec![1, 2];\nlet res: Result<Vec<u32>, &'static str> = v.iter().map(|x: &u32|\n    x.checked_add(1).ok_or("Overflow!")\n).collect();\nassert_eq!(res, Ok(vec![2, 3]));
\n

Here is another example that tries to subtract one from another list\nof integers, this time checking for underflow:

\n\n
let v = vec![1, 2, 0];\nlet res: Result<Vec<u32>, &'static str> = v.iter().map(|x: &u32|\n    x.checked_sub(1).ok_or("Underflow!")\n).collect();\nassert_eq!(res, Err("Underflow!"));
\n

Here is a variation on the previous example, showing that no\nfurther elements are taken from iter after the first Err.

\n\n
let v = vec![3, 2, 1, 10];\nlet mut shared = 0;\nlet res: Result<Vec<u32>, &'static str> = v.iter().map(|x: &u32| {\n    shared += x;\n    x.checked_sub(2).ok_or("Underflow!")\n}).collect();\nassert_eq!(res, Err("Underflow!"));\nassert_eq!(shared, 6);
\n

Since the third element caused an underflow, no further elements were taken,\nso the final value of shared is 6 (= 3 + 2 + 1), not 16.

\n
","FromIterator>","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
1.0.0 · source§

impl<T, E> Ord for Result<T, E>where\n T: Ord,\n E: Ord,

source§

fn cmp(&self, other: &Result<T, E>) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · source§

fn max(self, other: Self) -> Selfwhere\n Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · source§

fn min(self, other: Self) -> Selfwhere\n Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Selfwhere\n Self: Sized + PartialOrd,

Restrict a value to a certain interval. Read more
","Ord","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
1.0.0 · source§

impl<T, E> PartialEq for Result<T, E>where\n T: PartialEq,\n E: PartialEq,

source§

fn eq(&self, other: &Result<T, E>) -> bool

This method tests for self and other values to be equal, and is used\nby ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always\nsufficient, and should not be overridden without very good reason.
","PartialEq","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
1.0.0 · source§

impl<T, E> Clone for Result<T, E>where\n T: Clone,\n E: Clone,

source§

fn clone(&self) -> Result<T, E>

Returns a copy of the value. Read more
source§

fn clone_from(&mut self, source: &Result<T, E>)

Performs copy-assignment from source. Read more
","Clone","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
1.0.0 · source§

impl<T, E> Hash for Result<T, E>where\n T: Hash,\n E: Hash,

source§

fn hash<__H>(&self, state: &mut __H)where\n __H: Hasher,

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)where\n H: Hasher,\n Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
","Hash","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
1.0.0 · source§

impl<T, E> IntoIterator for Result<T, E>

source§

fn into_iter(self) -> IntoIter<T>

Returns a consuming iterator over the possibly contained value.

\n

The iterator yields one value if the result is Result::Ok, otherwise none.

\n
Examples
\n
let x: Result<u32, &str> = Ok(5);\nlet v: Vec<u32> = x.into_iter().collect();\nassert_eq!(v, [5]);\n\nlet x: Result<u32, &str> = Err("nothing!");\nlet v: Vec<u32> = x.into_iter().collect();\nassert_eq!(v, []);
\n
§

type Item = T

The type of the elements being iterated over.
§

type IntoIter = IntoIter<T>

Which kind of iterator are we turning this into?
","IntoIterator","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<T, E> Residual<T> for Result<Infallible, E>

§

type TryType = Result<T, E>

🔬This is a nightly-only experimental API. (try_trait_v2_residual)
The “return” type of this meta-function.
","Residual","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
1.0.0 · source§

impl<T, E> StructuralPartialEq for Result<T, E>

","StructuralPartialEq","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
1.16.0 · source§

impl<T, U, E> Sum<Result<U, E>> for Result<T, E>where\n T: Sum<U>,

source§

fn sum<I>(iter: I) -> Result<T, E>where\n I: Iterator<Item = Result<U, E>>,

Takes each element in the Iterator: if it is an Err, no further\nelements are taken, and the Err is returned. Should no Err\noccur, the sum of all elements is returned.

\n
Examples
\n

This sums up every integer in a vector, rejecting the sum if a negative\nelement is encountered:

\n\n
let f = |&x: &i32| if x < 0 { Err("Negative element found") } else { Ok(x) };\nlet v = vec![1, 2];\nlet res: Result<i32, _> = v.iter().map(f).sum();\nassert_eq!(res, Ok(3));\nlet v = vec![1, -2];\nlet res: Result<i32, _> = v.iter().map(f).sum();\nassert_eq!(res, Err("Negative element found"));
\n
","Sum>","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
1.0.0 · source§

impl<T, E> Debug for Result<T, E>where\n T: Debug,\n E: Debug,

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
","Debug","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
1.0.0 · source§

impl<T, E> PartialOrd for Result<T, E>where\n T: PartialOrd,\n E: PartialOrd,

source§

fn partial_cmp(&self, other: &Result<T, E>) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · source§

fn lt(&self, other: &Rhs) -> bool

This method tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · source§

fn le(&self, other: &Rhs) -> bool

This method tests less than or equal to (for self and other) and is used by the <=\noperator. Read more
1.0.0 · source§

fn gt(&self, other: &Rhs) -> bool

This method tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · source§

fn ge(&self, other: &Rhs) -> bool

This method tests greater than or equal to (for self and other) and is used by the >=\noperator. Read more
","PartialOrd","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
1.0.0 · source§

impl<T, E> Copy for Result<T, E>where\n T: Copy,\n E: Copy,

","Copy","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
1.16.0 · source§

impl<T, U, E> Product<Result<U, E>> for Result<T, E>where\n T: Product<U>,

source§

fn product<I>(iter: I) -> Result<T, E>where\n I: Iterator<Item = Result<U, E>>,

Takes each element in the Iterator: if it is an Err, no further\nelements are taken, and the Err is returned. Should no Err\noccur, the product of all elements is returned.

\n
Examples
\n

This multiplies each number in a vector of strings,\nif a string could not be parsed the operation returns Err:

\n\n
let nums = vec!["5", "10", "1", "2"];\nlet total: Result<usize, _> = nums.iter().map(|w| w.parse::<usize>()).product();\nassert_eq!(total, Ok(100));\nlet nums = vec!["5", "10", "one", "2"];\nlet total: Result<usize, _> = nums.iter().map(|w| w.parse::<usize>()).product();\nassert!(total.is_err());
\n
","Product>","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<T, E> Serialize for Result<T, E>where\n T: Serialize,\n E: Serialize,

source§

fn serialize<S>(\n &self,\n serializer: S\n) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>where\n S: Serializer,

Serialize this value into the given Serde serializer. Read more
","Serialize","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<'de, T, E> Deserialize<'de> for Result<T, E>where\n T: Deserialize<'de>,\n E: Deserialize<'de>,

source§

fn deserialize<D>(\n deserializer: D\n) -> Result<Result<T, E>, <D as Deserializer<'de>>::Error>where\n D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
","Deserialize<'de>","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<T, E> MapHandlerError<T> for Result<T, E>where\n E: Into<Error> + Display,

source§

fn map_err_with_status(self, status_code: StatusCode) -> Result<T, HandlerError>

Equivalent of map_err(|err| HandlerError::from(err).with_status(status_code)).
","MapHandlerError","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<T, E> IntoResponse for Result<T, E>where\n T: IntoResponse,\n E: IntoResponse,

source§

fn into_response(self, state: &State) -> Response<Body>

Converts this value into a hyper::Response
","IntoResponse","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<T, E> Context<T, E> for Result<T, E>where\n E: StdError + Send + Sync + 'static,

source§

fn context<C>(self, context: C) -> Result<T, Error>where\n C: Display + Send + Sync + 'static,

Wrap the error value with additional context.
source§

fn with_context<C, F>(self, context: F) -> Result<T, Error>where\n C: Display + Send + Sync + 'static,\n F: FnOnce() -> C,

Wrap the error value with additional context that is evaluated lazily\nonly once an error does occur.
","Context","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<E> IntoResponse for Result<NoContent, E>where\n E: Debug + IntoResponseError<Err = Error>,

§

type Err = Error

source§

fn into_response(\n self\n) -> Pin<Box<dyn Future<Output = Result<Response, Error>> + Send>>

Turn this into a response that can be returned to the browser. This api will likely\nchange in the future.
source§

fn accepted_types() -> Option<Vec<Mime>>

Return a list of supported mime types.
","IntoResponse","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<E> ResponseSchema for Result<Redirect, E>where\n E: Debug + IntoResponseError,\n <E as IntoResponseError>::Err: StdError + Sync,

source§

fn status_codes() -> Vec<StatusCode>

All status codes returned by this response. Returns [StatusCode::OK] by default.
source§

fn schema(code: StatusCode) -> OpenapiSchema

Return the schema of the response for the given status code. The code may\nonly be one that was previously returned by Self::status_codes. The\nimplementation should panic if that is not the case.
","ResponseSchema","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<T, E> ResponseSchema for Result<Raw<T>, E>where\n Raw<T>: IntoResponseWithSchema,\n E: Debug + IntoResponseError<Err = <Raw<T> as IntoResponse>::Err>,

source§

fn status_codes() -> Vec<StatusCode>

All status codes returned by this response. Returns [StatusCode::OK] by default.
source§

fn schema(code: StatusCode) -> OpenapiSchema

Return the schema of the response for the given status code. The code may\nonly be one that was previously returned by Self::status_codes. The\nimplementation should panic if that is not the case.
","ResponseSchema","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<R, E> ResponseSchema for Result<R, E>where\n R: ResponseBody,\n E: Debug + IntoResponseError<Err = Error>,

source§

fn status_codes() -> Vec<StatusCode>

All status codes returned by this response. Returns [StatusCode::OK] by default.
source§

fn schema(code: StatusCode) -> OpenapiSchema

Return the schema of the response for the given status code. The code may\nonly be one that was previously returned by Self::status_codes. The\nimplementation should panic if that is not the case.
","ResponseSchema","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<E> ResponseSchema for Result<NoContent, E>where\n E: Debug + IntoResponseError<Err = Error>,

source§

fn status_codes() -> Vec<StatusCode>

All status codes returned by this response. Returns [StatusCode::OK] by default.
source§

fn schema(code: StatusCode) -> OpenapiSchema

Return the schema of the response for the given status code. The code may\nonly be one that was previously returned by Self::status_codes. The\nimplementation should panic if that is not the case.
","ResponseSchema","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<R, E> IntoResponse for Result<R, E>where\n R: ResponseBody,\n E: Debug + IntoResponseError<Err = Error>,

§

type Err = <E as IntoResponseError>::Err

source§

fn into_response(\n self\n) -> Pin<Box<dyn Future<Output = Result<Response, E::Err>> + Send>>

Turn this into a response that can be returned to the browser. This api will likely\nchange in the future.
source§

fn accepted_types() -> Option<Vec<Mime>>

Return a list of supported mime types.
","IntoResponse","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<E> IntoResponse for Result<Redirect, E>where\n E: Debug + IntoResponseError,\n <E as IntoResponseError>::Err: StdError + Sync,

§

type Err = RedirectError<<E as IntoResponseError>::Err>

source§

fn into_response(self) -> BoxFuture<'static, Result<Response, Self::Err>>

Turn this into a response that can be returned to the browser. This api will likely\nchange in the future.
source§

fn accepted_types() -> Option<Vec<Mime>>

Return a list of supported mime types.
","IntoResponse","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"],["
source§

impl<T, E> IntoResponse for Result<Raw<T>, E>where\n Raw<T>: IntoResponse,\n E: Debug + IntoResponseError<Err = <Raw<T> as IntoResponse>::Err>,

§

type Err = <E as IntoResponseError>::Err

source§

fn into_response(\n self\n) -> Pin<Box<dyn Future<Output = Result<Response, E::Err>> + Send>>

Turn this into a response that can be returned to the browser. This api will likely\nchange in the future.
source§

fn accepted_types() -> Option<Vec<Mime>>

Return a list of supported mime types.
","IntoResponse","gotham_restful::response::auth_result::AuthSuccess","gotham_restful::response::auth_result::AuthResult"]] };if (window.register_type_impls) {window.register_type_impls(type_impls);} else {window.pending_type_impls = type_impls;}})() \ No newline at end of file diff --git a/tarpaulin-report.html b/tarpaulin-report.html index 45da996f44..3b9a0fdab1 100644 --- a/tarpaulin-report.html +++ b/tarpaulin-report.html @@ -62,6 +62,9 @@ display: flex; justify-content: space-between; align-items: center; + position: sticky; + top: 0; + background: white; } .file-header__back { @@ -89,12 +92,20 @@ margin: 10px 0 0; border: 1px solid #999; padding: 10px; + counter-reset: line; + display: flex; + flex-direction: column; } +.code-line::before { + content: counter(line); + margin-right: 10px; +} .code-line { margin: 0; padding: 0.3em; height: 1em; + counter-increment: line; } .code-line_covered { background: #cfc; @@ -107,8 +118,8 @@
\"#,\n\t\t\t\"\",\n\t\t\t\"\"\n\t\t),\n\t\tencoded_spec, script\n\t)\n\t.unwrap();\n\n\tRedoc { html, script_hash }\n}\n","traces":[{"line":20,"address":[6795440,6796510],"length":1,"stats":{"Line":0},"fn_name":"html"},{"line":21,"address":[6795559,6795491],"length":1,"stats":{"Line":0},"fn_name":null},{"line":23,"address":[8777291,8777264],"length":1,"stats":{"Line":0},"fn_name":"{closure#0}"},{"line":24,"address":[6796629],"length":1,"stats":{"Line":0},"fn_name":null},{"line":25,"address":[8777383],"length":1,"stats":{"Line":0},"fn_name":null},{"line":26,"address":[8777417],"length":1,"stats":{"Line":0},"fn_name":null},{"line":27,"address":[8777324],"length":1,"stats":{"Line":0},"fn_name":null},{"line":31,"address":[6795470,6795632],"length":1,"stats":{"Line":0},"fn_name":null},{"line":32,"address":[8776379],"length":1,"stats":{"Line":0},"fn_name":null},{"line":33,"address":[7740474],"length":1,"stats":{"Line":0},"fn_name":null},{"line":34,"address":[6795757],"length":1,"stats":{"Line":0},"fn_name":null},{"line":36,"address":[6795930],"length":1,"stats":{"Line":0},"fn_name":null},{"line":37,"address":[6796225],"length":1,"stats":{"Line":0},"fn_name":null}],"covered":0,"coverable":13},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","auth.rs"],"content":"use crate::AuthError;\n\nuse base64::prelude::*;\nuse futures_util::{\n\tfuture,\n\tfuture::{FutureExt, TryFutureExt}\n};\nuse gotham::{\n\tanyhow,\n\tcookie::CookieJar,\n\thandler::HandlerFuture,\n\thyper::header::{HeaderMap, HeaderName, AUTHORIZATION},\n\tmiddleware::{cookie::CookieParser, Middleware, NewMiddleware},\n\tprelude::*,\n\tstate::State\n};\nuse jsonwebtoken::DecodingKey;\nuse serde::de::DeserializeOwned;\nuse std::{marker::PhantomData, panic::RefUnwindSafe, pin::Pin};\n\npub type AuthValidation = jsonwebtoken::Validation;\n\n/// The authentication status returned by the auth middleware for each request.\n#[derive(Debug, StateData)]\npub enum AuthStatus {\n\t/// The auth status is unknown. This is likely because no secret was provided\n\t/// that could be used to verify the token of the client.\n\tUnknown,\n\n\t/// The request has been performed without any kind of authentication.\n\tUnauthenticated,\n\n\t/// The request has been performed with an invalid authentication. This\n\t/// includes expired tokens. Further details can be obtained from the\n\t/// included error.\n\tInvalid(jsonwebtoken::errors::Error),\n\n\t/// The request has been performed with a valid authentication. The claims\n\t/// that were decoded from the token are attached.\n\tAuthenticated(T)\n}\n\nimpl Clone for AuthStatus\nwhere\n\tT: Clone + Send + 'static\n{\n\tfn clone(&self) -> Self {\n\t\t// TODO why is this manually implemented?\n\t\tmatch self {\n\t\t\tSelf::Unknown => Self::Unknown,\n\t\t\tSelf::Unauthenticated => Self::Unauthenticated,\n\t\t\tSelf::Invalid(err) => Self::Invalid(err.clone()),\n\t\t\tSelf::Authenticated(data) => Self::Authenticated(data.clone())\n\t\t}\n\t}\n}\n\nimpl AuthStatus {\n\tpub fn ok(self) -> Result {\n\t\tmatch self {\n\t\t\tSelf::Unknown => Err(AuthError::new(\"The authentication could not be determined\")),\n\t\t\tSelf::Unauthenticated => Err(AuthError::new(\"Missing token\")),\n\t\t\tSelf::Invalid(err) => Err(AuthError::new(format!(\"Invalid token: {err}\"))),\n\t\t\tSelf::Authenticated(data) => Ok(data)\n\t\t}\n\t}\n}\n\n/// The source of the authentication token in the request.\n#[derive(Clone, Debug, StateData)]\npub enum AuthSource {\n\t/// Take the token from a cookie with the given name.\n\tCookie(String),\n\t/// Take the token from a header with the given name.\n\tHeader(HeaderName),\n\t/// Take the token from the HTTP Authorization header. This is different from `Header(\"Authorization\")`\n\t/// as it will follow the `scheme param` format from the HTTP specification. The `scheme` will\n\t/// be discarded, so its value doesn't matter.\n\tAuthorizationHeader\n}\n\n/// This trait will help the auth middleware to determine the validity of an authentication token.\n///\n/// A very basic implementation could look like this:\n///\n/// ```\n/// # use gotham_restful::{AuthHandler, gotham::state::State};\n/// #\n/// const SECRET: &'static [u8; 32] = b\"zlBsA2QXnkmpe0QTh8uCvtAEa4j33YAc\";\n///\n/// struct CustomAuthHandler;\n/// impl AuthHandler for CustomAuthHandler {\n/// \tfn jwt_secret Option>(\n/// \t\t&self,\n/// \t\t_state: &mut State,\n/// \t\t_decode_data: F\n/// \t) -> Option> {\n/// \t\tSome(SECRET.to_vec())\n/// \t}\n/// }\n/// ```\npub trait AuthHandler {\n\t/// Return the SHA256-HMAC secret used to verify the JWT token.\n\tfn jwt_secret Option>(\n\t\t&self,\n\t\tstate: &mut State,\n\t\tdecode_data: F\n\t) -> Option>;\n}\n\n/// An [AuthHandler] returning always the same secret. See [AuthMiddleware] for a usage example.\n#[derive(Clone, Debug)]\npub struct StaticAuthHandler {\n\tsecret: Vec\n}\n\nimpl StaticAuthHandler {\n\tpub fn from_vec(secret: Vec) -> Self {\n\t\tSelf { secret }\n\t}\n\n\tpub fn from_array(secret: &[u8]) -> Self {\n\t\tSelf::from_vec(secret.to_vec())\n\t}\n}\n\nimpl AuthHandler for StaticAuthHandler {\n\tfn jwt_secret Option>(\n\t\t&self,\n\t\t_state: &mut State,\n\t\t_decode_data: F\n\t) -> Option> {\n\t\tSome(self.secret.clone())\n\t}\n}\n\n/// This is the auth middleware. To use it, first make sure you have the `auth` feature enabled. Then\n/// simply add it to your pipeline and request it inside your handler:\n///\n/// ```rust,no_run\n/// # #[macro_use] extern crate gotham_restful_derive;\n/// # use gotham::{router::builder::*, pipeline::*, state::State};\n/// # use gotham_restful::*;\n/// # use serde::{Deserialize, Serialize};\n/// #\n/// #[derive(Resource)]\n/// #[resource(read_all)]\n/// struct AuthResource;\n///\n/// #[derive(Debug, Deserialize, Clone)]\n/// struct AuthData {\n/// \tsub: String,\n/// \texp: u64\n/// }\n///\n/// #[read_all]\n/// fn read_all(auth: &AuthStatus) -> Success {\n/// \tformat!(\"{auth:?}\").into()\n/// }\n///\n/// fn main() {\n/// \tlet auth: AuthMiddleware = AuthMiddleware::new(\n/// \t\tAuthSource::AuthorizationHeader,\n/// \t\tAuthValidation::default(),\n/// \t\tStaticAuthHandler::from_array(b\"zlBsA2QXnkmpe0QTh8uCvtAEa4j33YAc\")\n/// \t);\n/// \tlet (chain, pipelines) = single_pipeline(new_pipeline().add(auth).build());\n/// \tgotham::start(\n/// \t\t\"127.0.0.1:8080\",\n/// \t\tbuild_router(chain, pipelines, |route| {\n/// \t\t\troute.resource::(\"auth\");\n/// \t\t})\n/// \t);\n/// }\n/// ```\n#[derive(Debug)]\npub struct AuthMiddleware {\n\tsource: AuthSource,\n\tvalidation: AuthValidation,\n\thandler: Handler,\n\t_data: PhantomData\n}\n\nimpl Clone for AuthMiddleware\nwhere\n\tHandler: Clone\n{\n\tfn clone(&self) -> Self {\n\t\tSelf {\n\t\t\tsource: self.source.clone(),\n\t\t\tvalidation: self.validation.clone(),\n\t\t\thandler: self.handler.clone(),\n\t\t\t_data: self._data\n\t\t}\n\t}\n}\n\nimpl AuthMiddleware\nwhere\n\tData: DeserializeOwned + Send,\n\tHandler: AuthHandler + Default\n{\n\tpub fn from_source(source: AuthSource) -> Self {\n\t\tSelf {\n\t\t\tsource,\n\t\t\tvalidation: Default::default(),\n\t\t\thandler: Default::default(),\n\t\t\t_data: Default::default()\n\t\t}\n\t}\n}\n\nimpl AuthMiddleware\nwhere\n\tData: DeserializeOwned + Send,\n\tHandler: AuthHandler\n{\n\tpub fn new(source: AuthSource, validation: AuthValidation, handler: Handler) -> Self {\n\t\tSelf {\n\t\t\tsource,\n\t\t\tvalidation,\n\t\t\thandler,\n\t\t\t_data: Default::default()\n\t\t}\n\t}\n\n\tfn auth_status(&self, state: &mut State) -> AuthStatus {\n\t\t// extract the provided token, if any\n\t\tlet token = match &self.source {\n\t\t\tAuthSource::Cookie(name) => CookieJar::try_borrow_from(&state)\n\t\t\t\t.map(|jar| jar.get(&name).map(|cookie| cookie.value().to_owned()))\n\t\t\t\t.unwrap_or_else(|| {\n\t\t\t\t\tCookieParser::from_state(&state)\n\t\t\t\t\t\t.get(&name)\n\t\t\t\t\t\t.map(|cookie| cookie.value().to_owned())\n\t\t\t\t}),\n\t\t\tAuthSource::Header(name) => HeaderMap::try_borrow_from(&state)\n\t\t\t\t.and_then(|map| map.get(name))\n\t\t\t\t.and_then(|header| header.to_str().ok())\n\t\t\t\t.map(|value| value.to_owned()),\n\t\t\tAuthSource::AuthorizationHeader => HeaderMap::try_borrow_from(&state)\n\t\t\t\t.and_then(|map| map.get(AUTHORIZATION))\n\t\t\t\t.and_then(|header| header.to_str().ok())\n\t\t\t\t.and_then(|value| value.split_whitespace().nth(1))\n\t\t\t\t.map(|value| value.to_owned())\n\t\t};\n\n\t\t// unauthed if no token\n\t\tlet token = match token {\n\t\t\tSome(token) => token,\n\t\t\tNone => return AuthStatus::Unauthenticated\n\t\t};\n\n\t\t// get the secret from the handler, possibly decoding claims ourselves\n\t\tlet secret = self.handler.jwt_secret(state, || {\n\t\t\tlet b64 = token.split('.').nth(1)?;\n\t\t\tlet raw = BASE64_URL_SAFE_NO_PAD.decode(b64).ok()?;\n\t\t\tserde_json::from_slice(&raw).ok()?\n\t\t});\n\n\t\t// unknown if no secret\n\t\tlet secret = match secret {\n\t\t\tSome(secret) => secret,\n\t\t\tNone => return AuthStatus::Unknown\n\t\t};\n\n\t\t// validate the token\n\t\tlet data: Data = match jsonwebtoken::decode(\n\t\t\t&token,\n\t\t\t&DecodingKey::from_secret(&secret),\n\t\t\t&self.validation\n\t\t) {\n\t\t\tOk(data) => data.claims,\n\t\t\tErr(e) => return AuthStatus::Invalid(e)\n\t\t};\n\n\t\t// we found a valid token\n\t\tAuthStatus::Authenticated(data)\n\t}\n}\n\nimpl Middleware for AuthMiddleware\nwhere\n\tData: DeserializeOwned + Send + 'static,\n\tHandler: AuthHandler\n{\n\tfn call(self, mut state: State, chain: Chain) -> Pin>\n\twhere\n\t\tChain: FnOnce(State) -> Pin>\n\t{\n\t\t// put the source in our state, required for e.g. openapi\n\t\tstate.put(self.source.clone());\n\n\t\t// put the status in our state\n\t\tlet status = self.auth_status(&mut state);\n\t\tstate.put(status);\n\n\t\t// call the rest of the chain\n\t\tchain(state)\n\t\t\t.and_then(|(state, res)| future::ok((state, res)))\n\t\t\t.boxed()\n\t}\n}\n\nimpl NewMiddleware for AuthMiddleware\nwhere\n\tSelf: Clone + Middleware + Sync + RefUnwindSafe\n{\n\ttype Instance = Self;\n\n\tfn new_middleware(&self) -> anyhow::Result {\n\t\tlet c: Self = self.clone();\n\t\tOk(c)\n\t}\n}\n\n#[cfg(test)]\nmod test {\n\tuse super::*;\n\tuse gotham::{cookie::Cookie, hyper::header::COOKIE};\n\tuse jsonwebtoken::errors::ErrorKind;\n\tuse std::fmt::Debug;\n\n\t// 256-bit random string\n\tconst JWT_SECRET: &'static [u8; 32] = b\"Lyzsfnta0cdxyF0T9y6VGxp3jpgoMUuW\";\n\n\t// some known tokens\n\tconst VALID_TOKEN: &'static str = \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJtc3JkMCIsInN1YiI6ImdvdGhhbS1yZXN0ZnVsIiwiaWF0IjoxNTc3ODM2ODAwLCJleHAiOjQxMDI0NDQ4MDB9.8h8Ax-nnykqEQ62t7CxmM3ja6NzUQ4L0MLOOzddjLKk\";\n\tconst EXPIRED_TOKEN: &'static str = \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJtc3JkMCIsInN1YiI6ImdvdGhhbS1yZXN0ZnVsIiwiaWF0IjoxNTc3ODM2ODAwLCJleHAiOjE1Nzc4MzcxMDB9.eV1snaGLYrJ7qUoMk74OvBY3WUU9M0Je5HTU2xtX1v0\";\n\tconst INVALID_TOKEN: &'static str = \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJtc3JkMCIsInN1YiI6ImdvdGhhbS1yZXN0ZnVsIiwiaWF0IjoxNTc3ODM2ODAwLCJleHAiOjQxMDI0NDQ4MDB9\";\n\n\t#[derive(Debug, Deserialize, PartialEq)]\n\tstruct TestData {\n\t\tiss: String,\n\t\tsub: String,\n\t\tiat: u64,\n\t\texp: u64\n\t}\n\n\timpl Default for TestData {\n\t\tfn default() -> Self {\n\t\t\tSelf {\n\t\t\t\tiss: \"msrd0\".to_owned(),\n\t\t\t\tsub: \"gotham-restful\".to_owned(),\n\t\t\t\tiat: 1577836800,\n\t\t\t\texp: 4102444800\n\t\t\t}\n\t\t}\n\t}\n\n\t#[derive(Default)]\n\tstruct NoneAuthHandler;\n\timpl AuthHandler for NoneAuthHandler {\n\t\tfn jwt_secret Option>(\n\t\t\t&self,\n\t\t\t_state: &mut State,\n\t\t\t_decode_data: F\n\t\t) -> Option> {\n\t\t\tNone\n\t\t}\n\t}\n\n\t#[test]\n\tfn test_auth_middleware_none_secret() {\n\t\tlet middleware = >::from_source(\n\t\t\tAuthSource::AuthorizationHeader\n\t\t);\n\t\tState::with_new(|mut state| {\n\t\t\tlet mut headers = HeaderMap::new();\n\t\t\theaders.insert(\n\t\t\t\tAUTHORIZATION,\n\t\t\t\tformat!(\"Bearer {VALID_TOKEN}\").parse().unwrap()\n\t\t\t);\n\t\t\tstate.put(headers);\n\t\t\tmiddleware.auth_status(&mut state);\n\t\t});\n\t}\n\n\t#[derive(Default)]\n\tstruct TestAssertingHandler;\n\timpl AuthHandler for TestAssertingHandler\n\twhere\n\t\tT: Debug + Default + PartialEq\n\t{\n\t\tfn jwt_secret Option>(\n\t\t\t&self,\n\t\t\t_state: &mut State,\n\t\t\tdecode_data: F\n\t\t) -> Option> {\n\t\t\tassert_eq!(decode_data(), Some(T::default()));\n\t\t\tSome(JWT_SECRET.to_vec())\n\t\t}\n\t}\n\n\t#[test]\n\tfn test_auth_middleware_decode_data() {\n\t\tlet middleware = >::from_source(\n\t\t\tAuthSource::AuthorizationHeader\n\t\t);\n\t\tState::with_new(|mut state| {\n\t\t\tlet mut headers = HeaderMap::new();\n\t\t\theaders.insert(\n\t\t\t\tAUTHORIZATION,\n\t\t\t\tformat!(\"Bearer {VALID_TOKEN}\").parse().unwrap()\n\t\t\t);\n\t\t\tstate.put(headers);\n\t\t\tmiddleware.auth_status(&mut state);\n\t\t});\n\t}\n\n\tfn new_middleware(source: AuthSource) -> AuthMiddleware\n\twhere\n\t\tT: DeserializeOwned + Send\n\t{\n\t\tAuthMiddleware::new(\n\t\t\tsource,\n\t\t\tDefault::default(),\n\t\t\tStaticAuthHandler::from_array(JWT_SECRET)\n\t\t)\n\t}\n\n\t#[test]\n\tfn test_auth_middleware_no_token() {\n\t\tlet middleware = new_middleware::(AuthSource::AuthorizationHeader);\n\t\tState::with_new(|mut state| {\n\t\t\tlet status = middleware.auth_status(&mut state);\n\t\t\tmatch status {\n\t\t\t\tAuthStatus::Unauthenticated => {},\n\t\t\t\t_ => panic!(\"Expected AuthStatus::Unauthenticated, got {status:?}\")\n\t\t\t};\n\t\t});\n\t}\n\n\t#[test]\n\tfn test_auth_middleware_expired_token() {\n\t\tlet middleware = new_middleware::(AuthSource::AuthorizationHeader);\n\t\tState::with_new(|mut state| {\n\t\t\tlet mut headers = HeaderMap::new();\n\t\t\theaders.insert(\n\t\t\t\tAUTHORIZATION,\n\t\t\t\tformat!(\"Bearer {EXPIRED_TOKEN}\").parse().unwrap()\n\t\t\t);\n\t\t\tstate.put(headers);\n\t\t\tlet status = middleware.auth_status(&mut state);\n\t\t\tmatch status {\n\t\t\t\tAuthStatus::Invalid(err) if *err.kind() == ErrorKind::ExpiredSignature => {},\n\t\t\t\t_ => panic!(\n\t\t\t\t\t\"Expected AuthStatus::Invalid(..) with ErrorKind::ExpiredSignature, got {status:?}\"\n\t\t\t\t)\n\t\t\t};\n\t\t});\n\t}\n\n\t#[test]\n\tfn test_auth_middleware_invalid_token() {\n\t\tlet middleware = new_middleware::(AuthSource::AuthorizationHeader);\n\t\tState::with_new(|mut state| {\n\t\t\tlet mut headers = HeaderMap::new();\n\t\t\theaders.insert(\n\t\t\t\tAUTHORIZATION,\n\t\t\t\tformat!(\"Bearer {INVALID_TOKEN}\").parse().unwrap()\n\t\t\t);\n\t\t\tstate.put(headers);\n\t\t\tlet status = middleware.auth_status(&mut state);\n\t\t\tmatch status {\n\t\t\t\tAuthStatus::Invalid(err) if *err.kind() == ErrorKind::InvalidToken => {},\n\t\t\t\t_ => panic!(\n\t\t\t\t\t\"Expected AuthStatus::Invalid(..) with ErrorKind::InvalidToken, got {status:?}\"\n\t\t\t\t)\n\t\t\t};\n\t\t});\n\t}\n\n\t#[test]\n\tfn test_auth_middleware_auth_header_token() {\n\t\tlet middleware = new_middleware::(AuthSource::AuthorizationHeader);\n\t\tState::with_new(|mut state| {\n\t\t\tlet mut headers = HeaderMap::new();\n\t\t\theaders.insert(\n\t\t\t\tAUTHORIZATION,\n\t\t\t\tformat!(\"Bearer {VALID_TOKEN}\").parse().unwrap()\n\t\t\t);\n\t\t\tstate.put(headers);\n\t\t\tlet status = middleware.auth_status(&mut state);\n\t\t\tmatch status {\n\t\t\t\tAuthStatus::Authenticated(data) => assert_eq!(data, TestData::default()),\n\t\t\t\t_ => panic!(\"Expected AuthStatus::Authenticated, got {status:?}\")\n\t\t\t};\n\t\t})\n\t}\n\n\t#[test]\n\tfn test_auth_middleware_header_token() {\n\t\tlet header_name = \"x-znoiprwmvfexju\";\n\t\tlet middleware =\n\t\t\tnew_middleware::(AuthSource::Header(HeaderName::from_static(header_name)));\n\t\tState::with_new(|mut state| {\n\t\t\tlet mut headers = HeaderMap::new();\n\t\t\theaders.insert(header_name, VALID_TOKEN.parse().unwrap());\n\t\t\tstate.put(headers);\n\t\t\tlet status = middleware.auth_status(&mut state);\n\t\t\tmatch status {\n\t\t\t\tAuthStatus::Authenticated(data) => assert_eq!(data, TestData::default()),\n\t\t\t\t_ => panic!(\"Expected AuthStatus::Authenticated, got {status:?}\")\n\t\t\t};\n\t\t})\n\t}\n\n\t#[test]\n\tfn test_auth_middleware_cookie_token() {\n\t\tlet cookie_name = \"znoiprwmvfexju\";\n\t\tlet middleware = new_middleware::(AuthSource::Cookie(cookie_name.to_owned()));\n\t\tState::with_new(|mut state| {\n\t\t\tlet mut jar = CookieJar::new();\n\t\t\tjar.add_original(Cookie::new(cookie_name, VALID_TOKEN));\n\t\t\tstate.put(jar);\n\t\t\tlet status = middleware.auth_status(&mut state);\n\t\t\tmatch status {\n\t\t\t\tAuthStatus::Authenticated(data) => assert_eq!(data, TestData::default()),\n\t\t\t\t_ => panic!(\"Expected AuthStatus::Authenticated, got {status:?}\")\n\t\t\t};\n\t\t})\n\t}\n\n\t#[test]\n\tfn test_auth_middleware_cookie_no_jar() {\n\t\tlet cookie_name = \"znoiprwmvfexju\";\n\t\tlet middleware = new_middleware::(AuthSource::Cookie(cookie_name.to_owned()));\n\t\tState::with_new(|mut state| {\n\t\t\tlet mut headers = HeaderMap::new();\n\t\t\theaders.insert(\n\t\t\t\tCOOKIE,\n\t\t\t\tformat!(\"{cookie_name}={VALID_TOKEN}\").parse().unwrap()\n\t\t\t);\n\t\t\tstate.put(headers);\n\t\t\tlet status = middleware.auth_status(&mut state);\n\t\t\tmatch status {\n\t\t\t\tAuthStatus::Authenticated(data) => assert_eq!(data, TestData::default()),\n\t\t\t\t_ => panic!(\"Expected AuthStatus::Authenticated, got {status:?}\")\n\t\t\t};\n\t\t})\n\t}\n}\n","traces":[{"line":47,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":49,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":50,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":51,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":52,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":53,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":59,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":60,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":61,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":62,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":63,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":64,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":118,"address":[5966032],"length":1,"stats":{"Line":3},"fn_name":null},{"line":122,"address":[5966064],"length":1,"stats":{"Line":3},"fn_name":null},{"line":123,"address":[5966087],"length":1,"stats":{"Line":2},"fn_name":null},{"line":128,"address":[5966173,5966128],"length":1,"stats":{"Line":1},"fn_name":"jwt_secret>"},{"line":133,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":188,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":190,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":191,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":192,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":193,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":203,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":206,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":207,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":208,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":218,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":223,"address":[],"length":0,"stats":{"Line":3},"fn_name":null},{"line":227,"address":[],"length":0,"stats":{"Line":4},"fn_name":null},{"line":229,"address":[],"length":0,"stats":{"Line":5},"fn_name":null},{"line":230,"address":[],"length":0,"stats":{"Line":5},"fn_name":null},{"line":231,"address":[],"length":0,"stats":{"Line":6},"fn_name":null},{"line":232,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":233,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":234,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":235,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":237,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":238,"address":[],"length":0,"stats":{"Line":3},"fn_name":null},{"line":239,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":240,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":241,"address":[],"length":0,"stats":{"Line":4},"fn_name":null},{"line":242,"address":[],"length":0,"stats":{"Line":8},"fn_name":null},{"line":243,"address":[],"length":0,"stats":{"Line":6},"fn_name":null},{"line":244,"address":[],"length":0,"stats":{"Line":6},"fn_name":null},{"line":245,"address":[],"length":0,"stats":{"Line":6},"fn_name":null},{"line":249,"address":[],"length":0,"stats":{"Line":4},"fn_name":null},{"line":250,"address":[],"length":0,"stats":{"Line":3},"fn_name":null},{"line":251,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":255,"address":[],"length":0,"stats":{"Line":4},"fn_name":null},{"line":256,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":257,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":258,"address":[],"length":0,"stats":{"Line":3},"fn_name":null},{"line":262,"address":[],"length":0,"stats":{"Line":3},"fn_name":null},{"line":263,"address":[],"length":0,"stats":{"Line":3},"fn_name":null},{"line":264,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":268,"address":[],"length":0,"stats":{"Line":5},"fn_name":null},{"line":269,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":270,"address":[],"length":0,"stats":{"Line":3},"fn_name":null},{"line":271,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":273,"address":[],"length":0,"stats":{"Line":3},"fn_name":null},{"line":274,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":278,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":287,"address":[6150528,6149233,6150065,6150471,6150913,6151329,6149264,6151360,6151745,6151776,6149649,6150510,6152161,6148848,6149680,6150096,6148817,6150944,6148432],"length":1,"stats":{"Line":1},"fn_name":"call, gotham_restful::routing::MaybeMatchAcceptHeader>, (borrow_bag::handle::Handle, ())>, borrow_bag::handle::Take>, ()), (gotham::pipeline::Pipeline<(gotham_restful::auth::AuthMiddleware, ())>, ()), gotham_restful::endpoint::NoopExtractor, openapi_specification::SecretQuery, fn(&mut gotham::state::State) -> gotham_restful::routing::endpoint_handler::{async_fn_env#0}>, (borrow_bag::handle::Handle, ())>, borrow_bag::handle::Take>, ()), (gotham::pipeline::Pipeline<(gotham_restful::auth::AuthMiddleware, ())>, ())>>"},{"line":292,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":295,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":296,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":299,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":300,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":311,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":312,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":313,"address":[],"length":0,"stats":{"Line":1},"fn_name":null}],"covered":58,"coverable":71},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","cors.rs"],"content":"use gotham::{\n\thandler::HandlerFuture,\n\thelpers::http::response::create_empty_response,\n\thyper::{\n\t\theader::{\n\t\t\tHeaderMap, HeaderName, HeaderValue, ACCESS_CONTROL_ALLOW_CREDENTIALS,\n\t\t\tACCESS_CONTROL_ALLOW_HEADERS, ACCESS_CONTROL_ALLOW_METHODS,\n\t\t\tACCESS_CONTROL_ALLOW_ORIGIN, ACCESS_CONTROL_MAX_AGE, ACCESS_CONTROL_REQUEST_HEADERS,\n\t\t\tACCESS_CONTROL_REQUEST_METHOD, ORIGIN, VARY\n\t\t},\n\t\tBody, Method, Response, StatusCode\n\t},\n\tmiddleware::Middleware,\n\tpipeline::PipelineHandleChain,\n\tprelude::*,\n\trouter::{builder::ExtendRouteMatcher, route::matcher::AccessControlRequestMethodMatcher},\n\tstate::State\n};\nuse std::{panic::RefUnwindSafe, pin::Pin};\n\n/// Specify the allowed origins of the request. It is up to the browser to check the validity of the\n/// origin. This, when sent to the browser, will indicate whether or not the request's origin was\n/// allowed to make the request.\n#[derive(Clone, Debug)]\npub enum Origin {\n\t/// Do not send any `Access-Control-Allow-Origin` headers.\n\tNone,\n\t/// Send `Access-Control-Allow-Origin: *`. Note that browser will not send credentials.\n\tStar,\n\t/// Set the `Access-Control-Allow-Origin` header to a single origin.\n\tSingle(String),\n\t/// Copy the `Origin` header into the `Access-Control-Allow-Origin` header.\n\tCopy\n}\n\nimpl Default for Origin {\n\tfn default() -> Self {\n\t\tSelf::None\n\t}\n}\n\nimpl Origin {\n\t/// Get the header value for the `Access-Control-Allow-Origin` header.\n\tfn header_value(&self, state: &State) -> Option {\n\t\tmatch self {\n\t\t\tSelf::None => None,\n\t\t\tSelf::Star => Some(\"*\".parse().unwrap()),\n\t\t\tSelf::Single(origin) => Some(origin.parse().unwrap()),\n\t\t\tSelf::Copy => {\n\t\t\t\tlet headers = HeaderMap::borrow_from(state);\n\t\t\t\theaders.get(ORIGIN).map(Clone::clone)\n\t\t\t}\n\t\t}\n\t}\n\n\t/// Returns true if the `Vary` header has to include `Origin`.\n\tfn varies(&self) -> bool {\n\t\tmatches!(self, Self::Copy)\n\t}\n}\n\n/// Specify the allowed headers of the request. It is up to the browser to check that only the allowed\n/// headers are sent with the request.\n#[derive(Clone, Debug)]\npub enum Headers {\n\t/// Do not send any `Access-Control-Allow-Headers` headers.\n\tNone,\n\t/// Set the `Access-Control-Allow-Headers` header to the following header list. If empty, this\n\t/// is treated as if it was [None].\n\tList(Vec),\n\t/// Copy the `Access-Control-Request-Headers` header into the `Access-Control-Allow-Header`\n\t/// header.\n\tCopy\n}\n\nimpl Default for Headers {\n\tfn default() -> Self {\n\t\tSelf::None\n\t}\n}\n\nimpl Headers {\n\t/// Get the header value for the `Access-Control-Allow-Headers` header.\n\tfn header_value(&self, state: &State) -> Option {\n\t\tmatch self {\n\t\t\tSelf::None => None,\n\t\t\tSelf::List(list) => Some(list.join(\",\").parse().unwrap()),\n\t\t\tSelf::Copy => {\n\t\t\t\tlet headers = HeaderMap::borrow_from(state);\n\t\t\t\theaders\n\t\t\t\t\t.get(ACCESS_CONTROL_REQUEST_HEADERS)\n\t\t\t\t\t.map(Clone::clone)\n\t\t\t}\n\t\t}\n\t}\n\n\t/// Returns true if the `Vary` header has to include `Origin`.\n\tfn varies(&self) -> bool {\n\t\tmatches!(self, Self::Copy)\n\t}\n}\n\n/// This is the configuration that the CORS handler will follow. Its default configuration is basically\n/// not to touch any responses, resulting in the browser's default behaviour.\n///\n/// To change settings, you need to put this type into gotham's [State]:\n///\n/// ```rust,no_run\n/// # use gotham::{router::builder::*, pipeline::*, state::State};\n/// # use gotham_restful::{*, cors::Origin};\n/// # #[cfg_attr(feature = \"cargo-clippy\", allow(clippy::needless_doctest_main))]\n/// fn main() {\n/// \tlet cors = CorsConfig {\n/// \t\torigin: Origin::Star,\n/// \t\t..Default::default()\n/// \t};\n/// \tlet (chain, pipelines) = single_pipeline(new_pipeline().add(cors).build());\n/// \tgotham::start(\n/// \t\t\"127.0.0.1:8080\",\n/// \t\tbuild_router(chain, pipelines, |route| {\n/// \t\t\t// your routing logic\n/// \t\t})\n/// \t);\n/// }\n/// ```\n///\n/// This easy approach allows you to have one global cors configuration. If you prefer to have separate\n/// configurations for different scopes, you need to register the middleware inside your routing logic:\n///\n/// ```rust,no_run\n/// # use gotham::{router::builder::*, pipeline::*, state::State};\n/// # use gotham_restful::{*, cors::Origin};\n/// let pipelines = new_pipeline_set();\n///\n/// // The first cors configuration\n/// let cors_a = CorsConfig {\n/// \torigin: Origin::Star,\n/// \t..Default::default()\n/// };\n/// let (pipelines, chain_a) = pipelines.add(new_pipeline().add(cors_a).build());\n///\n/// // The second cors configuration\n/// let cors_b = CorsConfig {\n/// \torigin: Origin::Copy,\n/// \t..Default::default()\n/// };\n/// let (pipelines, chain_b) = pipelines.add(new_pipeline().add(cors_b).build());\n///\n/// let pipeline_set = finalize_pipeline_set(pipelines);\n/// gotham::start(\n/// \t\"127.0.0.1:8080\",\n/// \tbuild_router((), pipeline_set, |route| {\n/// \t\t// routing without any cors config\n/// \t\troute.with_pipeline_chain((chain_a, ()), |route| {\n/// \t\t\t// routing with cors config a\n/// \t\t});\n/// \t\troute.with_pipeline_chain((chain_b, ()), |route| {\n/// \t\t\t// routing with cors config b\n/// \t\t});\n/// \t})\n/// );\n/// ```\n#[derive(Clone, Debug, Default, NewMiddleware, StateData)]\npub struct CorsConfig {\n\t/// The allowed origins.\n\tpub origin: Origin,\n\t/// The allowed headers.\n\tpub headers: Headers,\n\t/// The amount of seconds that the preflight request can be cached.\n\tpub max_age: u64,\n\t/// Whether or not the request may be made with supplying credentials.\n\tpub credentials: bool\n}\n\nimpl Middleware for CorsConfig {\n\tfn call(self, mut state: State, chain: Chain) -> Pin>\n\twhere\n\t\tChain: FnOnce(State) -> Pin>\n\t{\n\t\tstate.put(self);\n\t\tchain(state)\n\t}\n}\n\n/// Handle CORS for a non-preflight request. This means manipulating the `res` HTTP headers so that\n/// the response is aligned with the `state`'s [CorsConfig].\n///\n/// If you are using the [Resource](crate::Resource) type (which is the recommended way), you'll never\n/// have to call this method. However, if you are writing your own handler method, you might want to\n/// call this after your request to add the required CORS headers.\n///\n/// For further information on CORS, read .\npub fn handle_cors(state: &State, res: &mut Response) {\n\tlet config = CorsConfig::try_borrow_from(state);\n\tif let Some(cfg) = config {\n\t\tlet headers = res.headers_mut();\n\n\t\t// non-preflight requests require the Access-Control-Allow-Origin header\n\t\tif let Some(header) = cfg.origin.header_value(state) {\n\t\t\theaders.insert(ACCESS_CONTROL_ALLOW_ORIGIN, header);\n\t\t}\n\n\t\t// if the origin is copied over, we should tell the browser by specifying the Vary header\n\t\tif cfg.origin.varies() {\n\t\t\tlet vary = headers\n\t\t\t\t.get(VARY)\n\t\t\t\t.map(|vary| format!(\"{},origin\", vary.to_str().unwrap()));\n\t\t\theaders.insert(VARY, vary.as_deref().unwrap_or(\"origin\").parse().unwrap());\n\t\t}\n\n\t\t// if we allow credentials, tell the browser\n\t\tif cfg.credentials {\n\t\t\theaders.insert(\n\t\t\t\tACCESS_CONTROL_ALLOW_CREDENTIALS,\n\t\t\t\tHeaderValue::from_static(\"true\")\n\t\t\t);\n\t\t}\n\t}\n}\n\n/// Add CORS routing for your path. This is required for handling preflight requests.\n///\n/// Example:\n///\n/// ```rust,no_run\n/// # use gotham::{hyper::{Body, Method, Response}, router::builder::*};\n/// # use gotham_restful::*;\n/// build_simple_router(|router| {\n/// \t// The handler that needs preflight handling\n/// \trouter.post(\"/foo\").to(|state| {\n/// \t\tlet mut res: Response = unimplemented!();\n/// \t\thandle_cors(&state, &mut res);\n/// \t\t(state, res)\n/// \t});\n/// \t// Add preflight handling\n/// \trouter.cors(\"/foo\", Method::POST);\n/// });\n/// ```\npub trait CorsRoute\nwhere\n\tC: PipelineHandleChain

+ Copy + Send + Sync + 'static,\n\tP: RefUnwindSafe + Send + Sync + 'static\n{\n\t/// Handle a preflight request on `path` for `method`. To configure the behaviour, use\n\t/// [CorsConfig].\n\tfn cors(&mut self, path: &str, method: Method);\n}\n\npub(crate) fn cors_preflight_handler(state: State) -> (State, Response) {\n\tlet config = CorsConfig::try_borrow_from(&state);\n\n\t// prepare the response\n\tlet mut res = create_empty_response(&state, StatusCode::NO_CONTENT);\n\tlet headers = res.headers_mut();\n\tlet mut vary: Vec = Vec::new();\n\n\t// copy the request method over to the response\n\tlet method = HeaderMap::borrow_from(&state)\n\t\t.get(ACCESS_CONTROL_REQUEST_METHOD)\n\t\t.unwrap()\n\t\t.clone();\n\theaders.insert(ACCESS_CONTROL_ALLOW_METHODS, method);\n\tvary.push(ACCESS_CONTROL_REQUEST_METHOD);\n\n\tif let Some(cfg) = config {\n\t\t// if we allow any headers, copy them over\n\t\tif let Some(header) = cfg.headers.header_value(&state) {\n\t\t\theaders.insert(ACCESS_CONTROL_ALLOW_HEADERS, header);\n\t\t}\n\n\t\t// if the headers are copied over, we should tell the browser by specifying the Vary header\n\t\tif cfg.headers.varies() {\n\t\t\tvary.push(ACCESS_CONTROL_REQUEST_HEADERS);\n\t\t}\n\n\t\t// set the max age for the preflight cache\n\t\tif let Some(age) = config.map(|cfg| cfg.max_age) {\n\t\t\theaders.insert(ACCESS_CONTROL_MAX_AGE, age.into());\n\t\t}\n\t}\n\n\t// make sure the browser knows that this request was based on the method\n\theaders.insert(VARY, vary.join(\",\").parse().unwrap());\n\n\thandle_cors(&state, &mut res);\n\t(state, res)\n}\n\nimpl CorsRoute for D\nwhere\n\tD: DrawRoutes,\n\tC: PipelineHandleChain

+ Copy + Send + Sync + 'static,\n\tP: RefUnwindSafe + Send + Sync + 'static\n{\n\tfn cors(&mut self, path: &str, method: Method) {\n\t\tlet matcher = AccessControlRequestMethodMatcher::new(method);\n\t\tself.options(path)\n\t\t\t.extend_route_matcher(matcher)\n\t\t\t.to(cors_preflight_handler);\n\t}\n}\n","traces":[{"line":37,"address":[6396656],"length":1,"stats":{"Line":2},"fn_name":"default"},{"line":38,"address":[6396659],"length":1,"stats":{"Line":2},"fn_name":null},{"line":44,"address":[6396672],"length":1,"stats":{"Line":1},"fn_name":null},{"line":45,"address":[6396714],"length":1,"stats":{"Line":3},"fn_name":null},{"line":46,"address":[6396750],"length":1,"stats":{"Line":1},"fn_name":null},{"line":47,"address":[6396759],"length":1,"stats":{"Line":1},"fn_name":null},{"line":48,"address":[6396835],"length":1,"stats":{"Line":1},"fn_name":null},{"line":50,"address":[6396921],"length":1,"stats":{"Line":1},"fn_name":null},{"line":51,"address":[6396938],"length":1,"stats":{"Line":1},"fn_name":null},{"line":57,"address":[6397040],"length":1,"stats":{"Line":1},"fn_name":null},{"line":58,"address":[6397045],"length":1,"stats":{"Line":3},"fn_name":null},{"line":77,"address":[6397072],"length":1,"stats":{"Line":2},"fn_name":"default"},{"line":78,"address":[6397075],"length":1,"stats":{"Line":2},"fn_name":null},{"line":84,"address":[6397088,6397512],"length":1,"stats":{"Line":1},"fn_name":null},{"line":85,"address":[6397131],"length":1,"stats":{"Line":3},"fn_name":null},{"line":86,"address":[6397168],"length":1,"stats":{"Line":1},"fn_name":null},{"line":87,"address":[6397182,6397378],"length":1,"stats":{"Line":1},"fn_name":null},{"line":89,"address":[6397261],"length":1,"stats":{"Line":1},"fn_name":null},{"line":90,"address":[6397338],"length":1,"stats":{"Line":1},"fn_name":null},{"line":91,"address":[6397278],"length":1,"stats":{"Line":1},"fn_name":null},{"line":98,"address":[6397552],"length":1,"stats":{"Line":1},"fn_name":null},{"line":99,"address":[6397557],"length":1,"stats":{"Line":1},"fn_name":null},{"line":176,"address":[6653500,6653724,6653752,6653528,6653552,6653776,6653328,6653948,6653976],"length":1,"stats":{"Line":3},"fn_name":"call, gotham_restful::routing::MaybeMatchAcceptHeader>, (borrow_bag::handle::Handle, borrow_bag::handle::Take>, ()), (gotham::pipeline::Pipeline<(gotham_restful::cors::CorsConfig, ())>, ()), gotham_restful::endpoint::NoopExtractor, gotham_restful::endpoint::NoopExtractor, fn(&mut gotham::state::State) -> gotham_restful::routing::endpoint_handler::{async_fn_env#0}>, (borrow_bag::handle::Handle, borrow_bag::handle::Take>, ()), (gotham::pipeline::Pipeline<(gotham_restful::cors::CorsConfig, ())>, ())>>"},{"line":180,"address":[],"length":0,"stats":{"Line":3},"fn_name":null},{"line":181,"address":[],"length":0,"stats":{"Line":10},"fn_name":null},{"line":193,"address":[6398641,6397584,6398607],"length":1,"stats":{"Line":7},"fn_name":"handle_cors"},{"line":194,"address":[6397617],"length":1,"stats":{"Line":5},"fn_name":null},{"line":195,"address":[6397651],"length":1,"stats":{"Line":7},"fn_name":null},{"line":196,"address":[6397700],"length":1,"stats":{"Line":1},"fn_name":null},{"line":199,"address":[6397786,6397729],"length":1,"stats":{"Line":4},"fn_name":null},{"line":200,"address":[6397819],"length":1,"stats":{"Line":1},"fn_name":null},{"line":204,"address":[6397965],"length":1,"stats":{"Line":3},"fn_name":null},{"line":205,"address":[6398048],"length":1,"stats":{"Line":1},"fn_name":null},{"line":206,"address":[6398018],"length":1,"stats":{"Line":1},"fn_name":null},{"line":207,"address":[6398688,6398721,6398812],"length":1,"stats":{"Line":3},"fn_name":"{closure#0}"},{"line":208,"address":[6398652,6398091],"length":1,"stats":{"Line":1},"fn_name":null},{"line":212,"address":[6397998],"length":1,"stats":{"Line":1},"fn_name":null},{"line":213,"address":[6398537],"length":1,"stats":{"Line":1},"fn_name":null},{"line":214,"address":[6398433],"length":1,"stats":{"Line":1},"fn_name":null},{"line":215,"address":[6398471],"length":1,"stats":{"Line":1},"fn_name":null},{"line":249,"address":[6400822,6400220,6398896],"length":1,"stats":{"Line":1},"fn_name":"cors_preflight_handler"},{"line":250,"address":[6398932,6399049],"length":1,"stats":{"Line":4},"fn_name":null},{"line":253,"address":[6399057],"length":1,"stats":{"Line":3},"fn_name":null},{"line":254,"address":[6399159,6399089],"length":1,"stats":{"Line":4},"fn_name":null},{"line":255,"address":[6399175],"length":1,"stats":{"Line":1},"fn_name":null},{"line":258,"address":[6399187,6399275],"length":1,"stats":{"Line":6},"fn_name":null},{"line":259,"address":[6399245],"length":1,"stats":{"Line":1},"fn_name":null},{"line":262,"address":[6399348],"length":1,"stats":{"Line":1},"fn_name":null},{"line":263,"address":[6399432],"length":1,"stats":{"Line":3},"fn_name":null},{"line":265,"address":[6399485],"length":1,"stats":{"Line":1},"fn_name":null},{"line":267,"address":[6399548,6399621],"length":1,"stats":{"Line":4},"fn_name":null},{"line":268,"address":[6399807,6399715],"length":1,"stats":{"Line":2},"fn_name":null},{"line":272,"address":[6399883,6399849],"length":1,"stats":{"Line":2},"fn_name":null},{"line":273,"address":[6399914],"length":1,"stats":{"Line":1},"fn_name":null},{"line":277,"address":[6400869,6399979,6400864,6399889],"length":1,"stats":{"Line":7},"fn_name":"{closure#0}"},{"line":278,"address":[6400026],"length":1,"stats":{"Line":1},"fn_name":null},{"line":283,"address":[6400231,6400778,6399555],"length":1,"stats":{"Line":3},"fn_name":null},{"line":285,"address":[6400593],"length":1,"stats":{"Line":1},"fn_name":null},{"line":286,"address":[6400605],"length":1,"stats":{"Line":3},"fn_name":null},{"line":295,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":296,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":297,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":298,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":299,"address":[],"length":0,"stats":{"Line":0},"fn_name":null}],"covered":59,"coverable":64},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","endpoint.rs"],"content":"use crate::{IntoResponse, RequestBody};\nuse futures_util::future::BoxFuture;\nuse gotham::{\n\textractor::{PathExtractor, QueryStringExtractor},\n\thyper::{Body, Method, Response},\n\trouter::response::StaticResponseExtender,\n\tstate::{State, StateData}\n};\n#[cfg(feature = \"openapi\")]\nuse openapi_type::{OpenapiType, Visitor};\nuse serde::{Deserialize, Deserializer};\nuse std::borrow::Cow;\n\n/// A no-op extractor that can be used as a default type for [Endpoint::Placeholders] and\n/// [Endpoint::Params].\n#[derive(Debug, Clone, Copy)]\npub struct NoopExtractor;\n\nimpl<'de> Deserialize<'de> for NoopExtractor {\n\tfn deserialize>(_: D) -> Result {\n\t\tOk(Self)\n\t}\n}\n\n#[cfg(feature = \"openapi\")]\nimpl OpenapiType for NoopExtractor {\n\tfn visit_type(visitor: &mut V) {\n\t\twarn!(\n\t\t\t\"You're asking for the OpenAPI Schema for gotham_restful::NoopExtractor. This is probably not what you want.\"\n\t\t);\n\t\tvisitor.visit_unit();\n\t}\n}\n\nimpl StateData for NoopExtractor {}\n\nimpl StaticResponseExtender for NoopExtractor {\n\ttype ResBody = Body;\n\tfn extend(_: &mut State, _: &mut Response) {}\n}\n\n// TODO: Specify default types once https://github.com/rust-lang/rust/issues/29661 lands.\n#[_private_openapi_trait(EndpointWithSchema)]\npub trait Endpoint {\n\t/// The HTTP Verb of this endpoint.\n\tfn http_method() -> Method;\n\t/// The URI that this endpoint listens on in gotham's format.\n\tfn uri() -> Cow<'static, str>;\n\n\t/// The verb used for generating an operation id if [Self::operation_id] returns [None].\n\t/// For example `read`, `read_all`, `create`, `update` etc.\n\t#[openapi_only]\n\tfn operation_verb() -> Option<&'static str>;\n\n\t/// The output type that provides the response.\n\t#[openapi_bound(Output: crate::ResponseSchema)]\n\ttype Output: IntoResponse + Send;\n\n\t/// Returns `true` _iff_ the URI contains placeholders. `false` by default.\n\tfn has_placeholders() -> bool {\n\t\tfalse\n\t}\n\t/// The type that parses the URI placeholders. Use [NoopExtractor] if `has_placeholders()`\n\t/// returns `false`.\n\t#[openapi_bound(Placeholders: OpenapiType)]\n\ttype Placeholders: PathExtractor + Clone + Sync;\n\n\t/// Returns `true` _iff_ the request parameters should be parsed. `false` by default.\n\tfn needs_params() -> bool {\n\t\tfalse\n\t}\n\t/// The type that parses the request parameters. Use [NoopExtractor] if `needs_params()`\n\t/// returns `false`.\n\t#[openapi_bound(Params: OpenapiType)]\n\ttype Params: QueryStringExtractor + Clone + Sync;\n\n\t/// Returns `true` _iff_ the request body should be parsed. `false` by default.\n\tfn needs_body() -> bool {\n\t\tfalse\n\t}\n\t/// The type to parse the body into. Use `()` if `needs_body()` returns `false`.\n\ttype Body: RequestBody + Send;\n\n\t/// Returns `true` if the request wants to know the auth status of the client. `false` by default.\n\tfn wants_auth() -> bool {\n\t\tfalse\n\t}\n\n\t/// Replace the automatically generated operation id with a custom one. Only relevant for the\n\t/// OpenAPI Specification.\n\t#[openapi_only]\n\tfn operation_id() -> Option {\n\t\tNone\n\t}\n\n\t/// Add a description to the openapi specification. Usually taken from the rustdoc comment\n\t/// when using the proc macro.\n\t#[openapi_only]\n\tfn description() -> Option {\n\t\tNone\n\t}\n\n\t/// The handler for this endpoint.\n\tfn handle(\n\t\tstate: &mut State,\n\t\tplaceholders: Self::Placeholders,\n\t\tparams: Self::Params,\n\t\tbody: Option\n\t) -> BoxFuture<'_, Self::Output>;\n}\n\n#[cfg(feature = \"openapi\")]\nimpl Endpoint for E {\n\tfn http_method() -> Method {\n\t\tE::http_method()\n\t}\n\tfn uri() -> Cow<'static, str> {\n\t\tE::uri()\n\t}\n\n\ttype Output = E::Output;\n\n\tfn has_placeholders() -> bool {\n\t\tE::has_placeholders()\n\t}\n\ttype Placeholders = E::Placeholders;\n\n\tfn needs_params() -> bool {\n\t\tE::needs_params()\n\t}\n\ttype Params = E::Params;\n\n\tfn needs_body() -> bool {\n\t\tE::needs_body()\n\t}\n\ttype Body = E::Body;\n\n\tfn wants_auth() -> bool {\n\t\tE::wants_auth()\n\t}\n\n\tfn handle<'a>(\n\t\tstate: &'a mut State,\n\t\tplaceholders: Self::Placeholders,\n\t\tparams: Self::Params,\n\t\tbody: Option\n\t) -> BoxFuture<'a, Self::Output> {\n\t\tE::handle(state, placeholders, params, body)\n\t}\n}\n","traces":[{"line":20,"address":[6734432,6734416],"length":1,"stats":{"Line":10},"fn_name":"deserialize>, gotham::extractor::internal::from_query_string_mapping::{closure_env#0}>, &alloc::vec::Vec, gotham::helpers::http::FormUrlDecoded>>>"},{"line":21,"address":[6734457,6734419],"length":1,"stats":{"Line":10},"fn_name":null},{"line":27,"address":[7557072],"length":1,"stats":{"Line":0},"fn_name":"visit_type"},{"line":28,"address":[7557085,7557153],"length":1,"stats":{"Line":0},"fn_name":null},{"line":31,"address":[7557120],"length":1,"stats":{"Line":0},"fn_name":null},{"line":39,"address":[6290560,6290570],"length":1,"stats":{"Line":0},"fn_name":"extend"},{"line":60,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":61,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":69,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":70,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":78,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":79,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":85,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":86,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":92,"address":[],"length":0,"stats":{"Line":6},"fn_name":null},{"line":93,"address":[6360019],"length":1,"stats":{"Line":6},"fn_name":null},{"line":99,"address":[6360000],"length":1,"stats":{"Line":7},"fn_name":"description"},{"line":100,"address":[6360003],"length":1,"stats":{"Line":7},"fn_name":null},{"line":114,"address":[6414144],"length":1,"stats":{"Line":29},"fn_name":"http_method"},{"line":115,"address":[],"length":0,"stats":{"Line":30},"fn_name":null},{"line":117,"address":[],"length":0,"stats":{"Line":30},"fn_name":null},{"line":118,"address":[],"length":0,"stats":{"Line":30},"fn_name":null},{"line":123,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":124,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":128,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":129,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":133,"address":[],"length":0,"stats":{"Line":21},"fn_name":null},{"line":134,"address":[],"length":0,"stats":{"Line":21},"fn_name":null},{"line":138,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":139,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":142,"address":[6414208],"length":1,"stats":{"Line":21},"fn_name":"handle"},{"line":148,"address":[],"length":0,"stats":{"Line":21},"fn_name":null}],"covered":14,"coverable":32},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","lib.rs"],"content":"#![warn(missing_debug_implementations, rust_2018_idioms, unreachable_pub)]\n#![forbid(unsafe_code)]\n// deny warnings in CI\n#![cfg_attr(gotham_restful_deny_warnings, deny(warnings))]\n// clippy doesn't like our code style\n#![cfg_attr(feature = \"cargo-clippy\", allow(clippy::tabs_in_doc_comments))]\n// intra-doc links only fully work when OpenAPI is enabled\n#![cfg_attr(feature = \"openapi\", deny(rustdoc::broken_intra_doc_links))]\n#![cfg_attr(not(feature = \"openapi\"), allow(rustdoc::broken_intra_doc_links))]\n\n//! This crate is an extension to the popular [gotham web framework][gotham] for Rust. It allows you to\n//! create resources with assigned endpoints that aim to be a more convenient way of creating handlers\n//! for requests.\n//!\n//! # Features\n//!\n//! - Automatically parse **JSON** request and produce response bodies\n//! - Allow using **raw** request and response bodies\n//! - Convenient **macros** to create responses that can be registered with gotham's router\n//! - Auto-Generate an **OpenAPI** specification for your API\n//! - Manage **CORS** headers so you don't have to\n//! - Manage **Authentication** with JWT\n//! - Integrate diesel connection pools for easy **database** integration\n//!\n//! # Safety\n//!\n//! This crate is just as safe as you'd expect from anything written in safe Rust - and\n//! `#![forbid(unsafe_code)]` ensures that no unsafe was used.\n//!\n//! # Endpoints\n//!\n//! There are a set of pre-defined endpoints that should cover the majority of REST APIs. However,\n//! it is also possible to define your own endpoints.\n//!\n//! ## Pre-defined Endpoints\n//!\n//! Assuming you assign `/foobar` to your resource, the following pre-defined endpoints exist:\n//!\n//! | Endpoint Name | Required Arguments | HTTP Verb | HTTP Path |\n//! | ------------- | ------------------ | --------- | -------------- |\n//! | read_all | | GET | /foobar |\n//! | read | id | GET | /foobar/:id |\n//! | search | query | GET | /foobar/search |\n//! | create | body | POST | /foobar |\n//! | update_all | body | PUT | /foobar |\n//! | update | id, body | PUT | /foobar/:id |\n//! | delete_all | | DELETE | /foobar |\n//! | delete | id | DELETE | /foobar/:id |\n//!\n//! Each of those endpoints has a macro that creates the neccessary boilerplate for the Resource. A\n//! simple example looks like this:\n//!\n//! ```rust,no_run\n//! # #[macro_use] extern crate gotham_restful_derive;\n//! # use gotham::router::builder::*;\n//! # use gotham_restful::*;\n//! # use serde::{Deserialize, Serialize};\n//! /// Our RESTful resource.\n//! #[derive(Resource)]\n//! #[resource(read)]\n//! struct FooResource;\n//!\n//! /// The return type of the foo read endpoint.\n//! #[derive(Serialize)]\n//! # #[cfg_attr(feature = \"openapi\", derive(openapi_type::OpenapiType))]\n//! struct Foo {\n//! \tid: u64\n//! }\n//!\n//! /// The foo read endpoint.\n//! #[read]\n//! fn read(id: u64) -> Success {\n//! \tFoo { id }.into()\n//! }\n//! # fn main() {\n//! # \tgotham::start(\"127.0.0.1:8080\", build_simple_router(|route| {\n//! # \t\troute.resource::(\"foo\");\n//! # \t})).expect(\"Failed to start gotham\");\n//! # }\n//! ```\n//!\n//! ## Custom Endpoints\n//!\n//! Defining custom endpoints is done with the `#[endpoint]` macro. The syntax is similar to that\n//! of the pre-defined endpoints, but you need to give it more context:\n//!\n//! ```rust,no_run\n//! # #[macro_use] extern crate gotham_restful_derive;\n//! # use gotham::{router::build_simple_router, prelude::*};\n//! # use gotham_restful::*;\n//! # use serde::{Deserialize, Serialize};\n//! use gotham_restful::gotham::hyper::Method;\n//!\n//! #[derive(Resource)]\n//! #[resource(custom_endpoint)]\n//! struct CustomResource;\n//!\n//! /// This type is used to parse path parameters.\n//! #[derive(Clone, Deserialize, StateData, StaticResponseExtender)]\n//! # #[cfg_attr(feature = \"openapi\", derive(openapi_type::OpenapiType))]\n//! struct CustomPath {\n//! \tname: String\n//! }\n//!\n//! #[endpoint(\n//! \turi = \"custom/:name/read\",\n//! \tmethod = \"Method::GET\",\n//! \tparams = false,\n//! \tbody = false\n//! )]\n//! fn custom_endpoint(path: CustomPath) -> Success {\n//! \tpath.name.into()\n//! }\n//! # fn main() {\n//! # \tgotham::start(\"127.0.0.1:8080\", build_simple_router(|route| {\n//! # \t\troute.resource::(\"custom\");\n//! # \t})).expect(\"Failed to start gotham\");\n//! # }\n//! ```\n//!\n//! # Arguments\n//!\n//! Some endpoints require arguments. Those should be\n//! * **id** Should be a deserializable json-primitive like [`i64`] or [`String`].\n//! * **body** Should be any deserializable object, or any type implementing [`RequestBody`].\n//! * **query** Should be any deserializable object whose variables are json-primitives. It will\n//! however not be parsed from json, but from HTTP GET parameters like in `search?id=1`. The\n//! type needs to implement [`QueryStringExtractor`](gotham::extractor::QueryStringExtractor).\n//!\n//! Additionally, all handlers may take a reference to gotham's [`State`]. Please note that for async\n//! handlers, it needs to be a mutable reference until rustc's lifetime checks across await bounds\n//! improve.\n//!\n//! # Uploads and Downloads\n//!\n//! By default, every request body is parsed from json, and every respone is converted to json using\n//! [serde_json]. However, you may also use raw bodies. This is an example where the request body\n//! is simply returned as the response again, no json parsing involved:\n//!\n//! ```rust,no_run\n//! # #[macro_use] extern crate gotham_restful_derive;\n//! # use gotham::{mime::{self, Mime}, router::builder::*};\n//! # use gotham_restful::*;\n//! # use serde::{Deserialize, Serialize};\n//! #[derive(Resource)]\n//! #[resource(create)]\n//! struct ImageResource;\n//!\n//! #[derive(FromBody, RequestBody)]\n//! #[supported_types(mime::IMAGE_GIF, mime::IMAGE_JPEG, mime::IMAGE_PNG)]\n//! struct RawImage {\n//! \tcontent: Vec,\n//! \tcontent_type: Mime\n//! }\n//!\n//! #[create]\n//! fn create(body: RawImage) -> Raw> {\n//! \tRaw::new(body.content, body.content_type)\n//! }\n//! # fn main() {\n//! # \tgotham::start(\"127.0.0.1:8080\", build_simple_router(|route| {\n//! # \t\troute.resource::(\"image\");\n//! # \t})).expect(\"Failed to start gotham\");\n//! # }\n//! ```\n//!\n//! # Custom HTTP Headers\n//!\n//! You can read request headers from the state as you would in any other gotham handler, and specify\n//! custom response headers using [Response::header].\n//!\n//! ```rust,no_run\n//! # #[macro_use] extern crate gotham_restful_derive;\n//! # use gotham::hyper::header::{ACCEPT, HeaderMap, VARY};\n//! # use gotham::{router::builder::*, state::State};\n//! # use gotham_restful::*;\n//! #[derive(Resource)]\n//! #[resource(read_all)]\n//! struct FooResource;\n//!\n//! #[read_all]\n//! async fn read_all(state: &mut State) -> NoContent {\n//! \tlet headers: &HeaderMap = state.borrow();\n//! \tlet accept = &headers[ACCEPT];\n//! # drop(accept);\n//!\n//! \tlet mut res = NoContent::default();\n//! \tres.header(VARY, \"accept\".parse().unwrap());\n//! \tres\n//! }\n//! # fn main() {\n//! # \tgotham::start(\"127.0.0.1:8080\", build_simple_router(|route| {\n//! # \t\troute.resource::(\"foo\");\n//! # \t})).expect(\"Failed to start gotham\");\n//! # }\n//! ```\n//!\n//! # Features\n//!\n//! To make life easier for common use-cases, this create offers a few features that might be helpful\n//! when you implement your web server. The complete feature list is\n//! - [`auth`](#authentication-feature) Advanced JWT middleware\n//! - [`cors`](#cors-feature) CORS handling for all endpoint handlers\n//! - [`database`](#database-feature) diesel middleware support\n//! - `errorlog` log errors returned from endpoint handlers\n//! - `full` enables all features except `without-openapi`\n//! - [`openapi`](#openapi-feature) router additions to generate an openapi spec\n//! - `without-openapi` (**default**) disables `openapi` support.\n//!\n//! ## Authentication Feature\n//!\n//! In order to enable authentication support, enable the `auth` feature gate. This allows you to\n//! register a middleware that can automatically check for the existence of an JWT authentication\n//! token. Besides being supported by the endpoint macros, it supports to lookup the required JWT secret\n//! with the JWT data, hence you can use several JWT secrets and decide on the fly which secret to use.\n//! None of this is currently supported by gotham's own JWT middleware.\n//!\n//! A simple example that uses only a single secret looks like this:\n//!\n//! ```rust,no_run\n//! # #[macro_use] extern crate gotham_restful_derive;\n//! # #[cfg(feature = \"auth\")]\n//! # mod auth_feature_enabled {\n//! # use gotham::{router::builder::*, pipeline::*, state::State};\n//! # use gotham_restful::*;\n//! # use serde::{Deserialize, Serialize};\n//! #[derive(Resource)]\n//! #[resource(read)]\n//! struct SecretResource;\n//!\n//! #[derive(Serialize)]\n//! # #[cfg_attr(feature = \"openapi\", derive(openapi_type::OpenapiType))]\n//! struct Secret {\n//! \tid: u64,\n//! \tintended_for: String\n//! }\n//!\n//! #[derive(Deserialize, Clone)]\n//! struct AuthData {\n//! \tsub: String,\n//! \texp: u64\n//! }\n//!\n//! #[read]\n//! fn read(auth: AuthStatus, id: u64) -> AuthSuccess {\n//! \tlet intended_for = auth.ok()?.sub;\n//! \tOk(Secret { id, intended_for })\n//! }\n//!\n//! fn main() {\n//! \tlet auth: AuthMiddleware = AuthMiddleware::new(\n//! \t\tAuthSource::AuthorizationHeader,\n//! \t\tAuthValidation::default(),\n//! \t\tStaticAuthHandler::from_array(b\"zlBsA2QXnkmpe0QTh8uCvtAEa4j33YAc\")\n//! \t);\n//! \tlet (chain, pipelines) = single_pipeline(new_pipeline().add(auth).build());\n//! \tgotham::start(\n//! \t\t\"127.0.0.1:8080\",\n//! \t\tbuild_router(chain, pipelines, |route| {\n//! \t\t\troute.resource::(\"secret\");\n//! \t\t})\n//! \t)\n//! \t.expect(\"Failed to start gotham\");\n//! }\n//! # }\n//! ```\n//!\n//! ## CORS Feature\n//!\n//! The cors feature allows an easy usage of this web server from other origins. By default, only\n//! the `Access-Control-Allow-Methods` header is touched. To change the behaviour, add your desired\n//! configuration as a middleware.\n//!\n//! A simple example that allows authentication from every origin (note that `*` always disallows\n//! authentication), and every content type, looks like this:\n//!\n//! ```rust,no_run\n//! # #[macro_use] extern crate gotham_restful_derive;\n//! # #[cfg(feature = \"cors\")]\n//! # mod cors_feature_enabled {\n//! # use gotham::{hyper::header::*, router::builder::*, pipeline::*, state::State};\n//! # use gotham_restful::{*, cors::*};\n//! # use serde::{Deserialize, Serialize};\n//! #[derive(Resource)]\n//! #[resource(read_all)]\n//! struct FooResource;\n//!\n//! #[read_all]\n//! fn read_all() {\n//! \t// your handler\n//! }\n//!\n//! fn main() {\n//! \tlet cors = CorsConfig {\n//! \t\torigin: Origin::Copy,\n//! \t\theaders: Headers::List(vec![CONTENT_TYPE]),\n//! \t\tmax_age: 0,\n//! \t\tcredentials: true\n//! \t};\n//! \tlet (chain, pipelines) = single_pipeline(new_pipeline().add(cors).build());\n//! \tgotham::start(\n//! \t\t\"127.0.0.1:8080\",\n//! \t\tbuild_router(chain, pipelines, |route| {\n//! \t\t\troute.resource::(\"foo\");\n//! \t\t})\n//! \t)\n//! \t.expect(\"Failed to start gotham\");\n//! }\n//! # }\n//! ```\n//!\n//! The cors feature can also be used for non-resource handlers. Take a look at [`CorsRoute`]\n//! for an example.\n//!\n//! ## Database Feature\n//!\n//! The database feature allows an easy integration of [diesel] into your handler functions. Please\n//! note however that due to the way gotham's diesel middleware implementation, it is not possible\n//! to run async code while holding a database connection. If you need to combine async and database,\n//! you'll need to borrow the connection from the [`State`] yourself and return a boxed future.\n//!\n//! A simple non-async example looks like this:\n//!\n//! ```rust,no_run\n//! # #[macro_use] extern crate diesel;\n//! # #[macro_use] extern crate gotham_restful_derive;\n//! # #[cfg(feature = \"database\")]\n//! # mod database_feature_enabled {\n//! # use diesel::{table, PgConnection, QueryResult, RunQueryDsl};\n//! # use gotham::{router::builder::*, pipeline::*, state::State};\n//! # use gotham_middleware_diesel::DieselMiddleware;\n//! # use gotham_restful::*;\n//! # use serde::{Deserialize, Serialize};\n//! # use std::env;\n//! # table! {\n//! # foo (id) {\n//! # id -> Int8,\n//! # value -> Text,\n//! # }\n//! # }\n//! #[derive(Resource)]\n//! #[resource(read_all)]\n//! struct FooResource;\n//!\n//! #[derive(Queryable, Serialize)]\n//! # #[cfg_attr(feature = \"openapi\", derive(openapi_type::OpenapiType))]\n//! struct Foo {\n//! \tid: i64,\n//! \tvalue: String\n//! }\n//!\n//! #[read_all]\n//! fn read_all(conn: &mut PgConnection) -> QueryResult> {\n//! \tfoo::table.load(conn)\n//! }\n//!\n//! type Repo = gotham_middleware_diesel::Repo;\n//!\n//! fn main() {\n//! \tlet repo = Repo::new(&env::var(\"DATABASE_URL\").unwrap());\n//! \tlet diesel = DieselMiddleware::new(repo);\n//!\n//! \tlet (chain, pipelines) = single_pipeline(new_pipeline().add(diesel).build());\n//! \tgotham::start(\n//! \t\t\"127.0.0.1:8080\",\n//! \t\tbuild_router(chain, pipelines, |route| {\n//! \t\t\troute.resource::(\"foo\");\n//! \t\t})\n//! \t)\n//! \t.expect(\"Failed to start gotham\");\n//! }\n//! # }\n//! ```\n//!\n//! ## OpenAPI Feature\n//!\n//! The OpenAPI feature is probably the most powerful one of this crate. Definitely read this section\n//! carefully both as a binary as well as a library author to avoid unwanted suprises.\n//!\n//! In order to automatically create an openapi specification, gotham-restful needs knowledge over\n//! all routes and the types returned. `serde` does a great job at serialization but doesn't give\n//! enough type information, so all types used in the router need to implement\n//! [`OpenapiType`](openapi_type::OpenapiType). This can be derived for almoust any type and there\n//! should be no need to implement it manually. A simple example looks like this:\n//!\n//! ```rust,no_run\n//! # #[macro_use] extern crate gotham_restful_derive;\n//! # #[cfg(feature = \"openapi\")]\n//! # mod openapi_feature_enabled {\n//! # use gotham::{router::builder::*, state::State};\n//! # use gotham_restful::*;\n//! # use openapi_type::OpenapiType;\n//! # use serde::{Deserialize, Serialize};\n//! #[derive(Resource)]\n//! #[resource(read_all)]\n//! struct FooResource;\n//!\n//! #[derive(OpenapiType, Serialize)]\n//! struct Foo {\n//! \tbar: String\n//! }\n//!\n//! #[read_all]\n//! fn read_all() -> Success {\n//! \tFoo {\n//! \t\tbar: \"Hello World\".to_owned()\n//! \t}\n//! \t.into()\n//! }\n//!\n//! fn main() {\n//! \tgotham::start(\n//! \t\t\"127.0.0.1:8080\",\n//! \t\tbuild_simple_router(|route| {\n//! \t\t\tlet info = OpenapiInfo {\n//! \t\t\t\ttitle: \"My Foo API\".to_owned(),\n//! \t\t\t\tversion: \"0.1.0\".to_owned(),\n//! \t\t\t\turls: vec![\"https://example.org/foo/api/v1\".to_owned()]\n//! \t\t\t};\n//! \t\t\troute.with_openapi(info, |mut route| {\n//! \t\t\t\troute.resource::(\"foo\");\n//! \t\t\t\troute.openapi_spec(\"openapi\");\n//! \t\t\t\troute.openapi_doc(\"/\");\n//! \t\t\t});\n//! \t\t})\n//! \t)\n//! \t.expect(\"Failed to start gotham\");\n//! }\n//! # }\n//! ```\n//!\n//! Above example adds the resource as before, but adds two other endpoints as well: `/openapi` and `/`.\n//! The first one will return the generated openapi specification in JSON format, allowing you to easily\n//! generate clients in different languages without worying to exactly replicate your api in each of those\n//! languages. The second one will return documentation in HTML format, so you can easily view your\n//! api and share it with other people.\n//!\n//! ### Gotchas\n//!\n//! The openapi feature has some gotchas you should be aware of.\n//!\n//! - The name of a struct is used as a \"link\" in the openapi specification. Therefore, if you have two\n//! structs with the same name in your project, the openapi specification will be invalid as only one\n//! of the two will make it into the spec.\n//! - By default, the `without-openapi` feature of this crate is enabled. Disabling it in favour of the\n//! `openapi` feature will add additional type bounds and method requirements to some of the traits and\n//! \ttypes in this crate, for example instead of [`Endpoint`] you now have to implement\n//! \t[`EndpointWithSchema`]. This means that some code might only compile on either feature, but not\n//! on both. If you are writing a library that uses gotham-restful, it is strongly recommended to pass\n//! \tboth features through and conditionally enable the openapi code, like this:\n//!\n//! ```rust\n//! # #[macro_use] extern crate gotham_restful;\n//! # use serde::{Deserialize, Serialize};\n//! #[derive(Deserialize, Serialize)]\n//! #[cfg_attr(feature = \"openapi\", derive(openapi_type::OpenapiType))]\n//! struct Foo;\n//! ```\n//!\n//! [diesel]: https://diesel.rs/\n//! [`State`]: gotham::state::State\n\n#[cfg(all(feature = \"openapi\", feature = \"without-openapi\"))]\ncompile_error!(\"The 'openapi' and 'without-openapi' features cannot be combined\");\n\n#[cfg(all(not(feature = \"openapi\"), not(feature = \"without-openapi\")))]\ncompile_error!(\"Either the 'openapi' or 'without-openapi' feature needs to be enabled\");\n\n// weird proc macro issue\nextern crate self as gotham_restful;\n\n#[macro_use]\nextern crate gotham_restful_derive;\n#[macro_use]\nextern crate log;\n#[macro_use]\nextern crate serde;\n\n#[cfg(test)]\n#[macro_use]\nextern crate pretty_assertions;\n\n#[doc(no_inline)]\npub use gotham;\n\npub use gotham_restful_derive::*;\n\n/// Not public API\n#[doc(hidden)]\npub mod private {\n\tpub use crate::routing::PathExtractor as IdPlaceholder;\n\tpub use futures_util::future::{BoxFuture, FutureExt};\n\t#[cfg(feature = \"database\")]\n\tpub use gotham_middleware_diesel::Repo;\n\t#[cfg(feature = \"openapi\")]\n\tpub use openapi_type::{OpenapiSchema, OpenapiType, Visitor};\n\tpub use serde_json;\n\n\t#[cfg(feature = \"openapi\")]\n\tuse gotham::hyper::StatusCode;\n\t#[cfg(feature = \"auth\")]\n\tuse gotham::state::{FromState, State};\n\n\t/// This method is used by the endpoint macro to generate a good error message\n\t/// when the used AuthData type does not implement Clone.\n\t#[cfg(feature = \"auth\")]\n\t#[inline]\n\tpub fn clone_from_state(state: &State) -> T\n\twhere\n\t\tT: FromState + Clone\n\t{\n\t\tT::borrow_from(state).clone()\n\t}\n\n\t/// This trait is used by the endpoint macro to generate a good error message\n\t/// when the schema function has the wrong signature.\n\t#[cfg(feature = \"openapi\")]\n\tpub trait CustomSchema {\n\t\tfn schema(self, code: StatusCode) -> OpenapiSchema;\n\t}\n\n\t#[cfg(feature = \"openapi\")]\n\timpl CustomSchema for F\n\twhere\n\t\tF: FnOnce(StatusCode) -> OpenapiSchema\n\t{\n\t\t#[inline]\n\t\tfn schema(self, code: StatusCode) -> OpenapiSchema {\n\t\t\tself(code)\n\t\t}\n\t}\n\n\t/// This trait is used by the endpoint macro to generate a good error message\n\t/// when the status_codes function has the wrong signature.\n\t#[cfg(feature = \"openapi\")]\n\tpub trait CustomStatusCodes {\n\t\tfn status_codes(self) -> Vec;\n\t}\n\n\t#[cfg(feature = \"openapi\")]\n\timpl CustomStatusCodes for F\n\twhere\n\t\tF: FnOnce() -> Vec\n\t{\n\t\t#[inline]\n\t\tfn status_codes(self) -> Vec {\n\t\t\tself()\n\t\t}\n\t}\n}\n\n#[cfg(feature = \"auth\")]\nmod auth;\n#[cfg(feature = \"auth\")]\npub use auth::{\n\tAuthHandler, AuthMiddleware, AuthSource, AuthStatus, AuthValidation, StaticAuthHandler\n};\n\n#[cfg(feature = \"cors\")]\npub mod cors;\n#[cfg(feature = \"cors\")]\npub use cors::{handle_cors, CorsConfig, CorsRoute};\n\n#[cfg(feature = \"openapi\")]\nmod openapi;\n#[cfg(feature = \"openapi\")]\npub use openapi::{builder::OpenapiInfo, router::GetOpenapi};\n\nmod endpoint;\n#[cfg(feature = \"openapi\")]\npub use endpoint::EndpointWithSchema;\npub use endpoint::{Endpoint, NoopExtractor};\n\nmod response;\npub use response::{\n\tAuthError, AuthErrorOrOther, AuthResult, AuthSuccess, IntoResponse, IntoResponseError,\n\tNoContent, Raw, Redirect, Response, Success\n};\n#[cfg(feature = \"openapi\")]\npub use response::{IntoResponseWithSchema, ResponseSchema};\n\nmod routing;\npub use routing::{DrawResourceRoutes, DrawResources};\n#[cfg(feature = \"openapi\")]\npub use routing::{DrawResourceRoutesWithSchema, DrawResourcesWithSchema, WithOpenapi};\n\nmod types;\npub use types::{FromBody, RequestBody, ResponseBody};\n\n/// This trait must be implemented for every resource. It allows you to register the different\n/// endpoints that can be handled by this resource to be registered with the underlying router.\n///\n/// It is not recommended to implement this yourself, just use `#[derive(Resource)]`.\n#[_private_openapi_trait(ResourceWithSchema)]\npub trait Resource {\n\t/// Register all methods handled by this resource with the underlying router.\n\t#[openapi_bound(D: crate::DrawResourceRoutesWithSchema)]\n\t#[non_openapi_bound(D: crate::DrawResourceRoutes)]\n\tfn setup(route: D);\n}\n","traces":[{"line":463,"address":[15740893],"length":1,"stats":{"Line":0},"fn_name":null},{"line":464,"address":[18612688],"length":1,"stats":{"Line":8},"fn_name":"partial_cmp"},{"line":466,"address":[15017436,15017499],"length":1,"stats":{"Line":9},"fn_name":null},{"line":467,"address":[14188699],"length":1,"stats":{"Line":0},"fn_name":null},{"line":489,"address":[18613105],"length":1,"stats":{"Line":0},"fn_name":null},{"line":508,"address":[3271040],"length":1,"stats":{"Line":14},"fn_name":"from_str"},{"line":512,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":518,"address":[1464025,1464049,1463811,1463795,1463706,1464015,1463785],"length":1,"stats":{"Line":0},"fn_name":null},{"line":523,"address":[15743808],"length":1,"stats":{"Line":6},"fn_name":null},{"line":528,"address":[15743872],"length":1,"stats":{"Line":9},"fn_name":null},{"line":529,"address":[3892408],"length":1,"stats":{"Line":7},"fn_name":null},{"line":536,"address":[15744124],"length":1,"stats":{"Line":0},"fn_name":null},{"line":541,"address":[15133840],"length":1,"stats":{"Line":0},"fn_name":"next"},{"line":546,"address":[3271165],"length":1,"stats":{"Line":1},"fn_name":null},{"line":547,"address":[3271198],"length":1,"stats":{"Line":1},"fn_name":null},{"line":552,"address":[3271749,3271465],"length":1,"stats":{"Line":0},"fn_name":null},{"line":559,"address":[9335363,9335274],"length":1,"stats":{"Line":0},"fn_name":null},{"line":564,"address":[3272319,3272303,3272118],"length":1,"stats":{"Line":0},"fn_name":null},{"line":595,"address":[7593418],"length":1,"stats":{"Line":0},"fn_name":null}],"covered":8,"coverable":19},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","openapi","builder.rs"],"content":"use openapi_type::{\n\tindexmap::IndexMap,\n\topenapiv3::{\n\t\tself, Components, OpenAPI, PathItem, ReferenceOr,\n\t\tReferenceOr::{Item, Reference},\n\t\tSchema, Server\n\t},\n\tOpenapiSchema\n};\nuse parking_lot::RwLock;\nuse std::sync::Arc;\n\n#[derive(Clone, Debug)]\npub struct OpenapiInfo {\n\tpub title: String,\n\tpub version: String,\n\tpub urls: Vec\n}\n\n#[derive(Clone, Debug)]\npub(crate) struct OpenapiBuilder {\n\tpub(crate) openapi: Arc>\n}\n\nimpl OpenapiBuilder {\n\tpub(crate) fn new(info: OpenapiInfo) -> Self {\n\t\tSelf {\n\t\t\topenapi: Arc::new(RwLock::new(OpenAPI {\n\t\t\t\topenapi: \"3.0.2\".to_string(),\n\t\t\t\tinfo: openapiv3::Info {\n\t\t\t\t\ttitle: info.title,\n\t\t\t\t\tversion: info.version,\n\t\t\t\t\t..Default::default()\n\t\t\t\t},\n\t\t\t\tservers: info\n\t\t\t\t\t.urls\n\t\t\t\t\t.into_iter()\n\t\t\t\t\t.map(|url| Server {\n\t\t\t\t\t\turl,\n\t\t\t\t\t\t..Default::default()\n\t\t\t\t\t})\n\t\t\t\t\t.collect(),\n\t\t\t\t..Default::default()\n\t\t\t}))\n\t\t}\n\t}\n\n\t/// Remove path from the OpenAPI spec, or return an empty one if not included. This is handy if you need to\n\t/// modify the path and add it back after the modification\n\tpub(crate) fn remove_path(&mut self, path: &str) -> PathItem {\n\t\tlet mut openapi = self.openapi.write();\n\t\tmatch openapi.paths.paths.swap_remove(path) {\n\t\t\tSome(Item(item)) => item,\n\t\t\t_ => PathItem::default()\n\t\t}\n\t}\n\n\tpub(crate) fn add_path(&mut self, path: Path, item: PathItem) {\n\t\tlet mut openapi = self.openapi.write();\n\t\topenapi.paths.paths.insert(path.to_string(), Item(item));\n\t}\n\n\tfn add_schema_impl(&mut self, name: String, mut schema: OpenapiSchema) {\n\t\tself.add_schema_dependencies(&mut schema.dependencies);\n\n\t\tlet mut openapi = self.openapi.write();\n\t\tmatch &mut openapi.components {\n\t\t\tSome(comp) => {\n\t\t\t\tcomp.schemas.insert(name, Item(schema.schema));\n\t\t\t},\n\t\t\tNone => {\n\t\t\t\tlet mut comp = Components::default();\n\t\t\t\tcomp.schemas.insert(name, Item(schema.schema));\n\t\t\t\topenapi.components = Some(comp);\n\t\t\t}\n\t\t};\n\t}\n\n\tfn add_schema_dependencies(&mut self, dependencies: &mut IndexMap) {\n\t\tlet keys: Vec = dependencies.keys().map(|k| k.to_string()).collect();\n\t\tfor dep in keys {\n\t\t\tlet dep_schema = dependencies.swap_remove(&dep);\n\t\t\tif let Some(dep_schema) = dep_schema {\n\t\t\t\tself.add_schema_impl(dep, dep_schema);\n\t\t\t}\n\t\t}\n\t}\n\n\tpub(crate) fn add_schema(&mut self, mut schema: OpenapiSchema) -> ReferenceOr {\n\t\tmatch schema.schema.schema_data.title.clone() {\n\t\t\tSome(name) => {\n\t\t\t\tlet reference = Reference {\n\t\t\t\t\treference: format!(\"#/components/schemas/{name}\")\n\t\t\t\t};\n\t\t\t\tself.add_schema_impl(name, schema);\n\t\t\t\treference\n\t\t\t},\n\t\t\tNone => {\n\t\t\t\tself.add_schema_dependencies(&mut schema.dependencies);\n\t\t\t\tItem(schema.schema)\n\t\t\t}\n\t\t}\n\t}\n}\n\n#[cfg(test)]\n#[allow(dead_code)]\nmod test {\n\tuse super::*;\n\tuse openapi_type::OpenapiType;\n\n\t#[derive(OpenapiType)]\n\tstruct Message {\n\t\tmsg: String\n\t}\n\n\t#[derive(OpenapiType)]\n\tstruct Messages {\n\t\tmsgs: Vec\n\t}\n\n\tfn info() -> OpenapiInfo {\n\t\tOpenapiInfo {\n\t\t\ttitle: \"TEST CASE\".to_owned(),\n\t\t\tversion: \"1.2.3\".to_owned(),\n\t\t\turls: vec![\n\t\t\t\t\"http://localhost:1234\".to_owned(),\n\t\t\t\t\"https://example.org\".to_owned(),\n\t\t\t]\n\t\t}\n\t}\n\n\tfn openapi(builder: OpenapiBuilder) -> OpenAPI {\n\t\tArc::try_unwrap(builder.openapi).unwrap().into_inner()\n\t}\n\n\t#[test]\n\tfn new_builder() {\n\t\tlet info = info();\n\t\tlet builder = OpenapiBuilder::new(info.clone());\n\t\tlet openapi = openapi(builder);\n\n\t\tassert_eq!(info.title, openapi.info.title);\n\t\tassert_eq!(info.version, openapi.info.version);\n\t\tassert_eq!(info.urls.len(), openapi.servers.len());\n\t}\n\n\t#[test]\n\tfn add_schema() {\n\t\tlet mut builder = OpenapiBuilder::new(info());\n\t\tbuilder.add_schema(>::schema());\n\t\tlet openapi = openapi(builder);\n\n\t\tassert_eq!(\n\t\t\topenapi.components.clone().unwrap_or_default().schemas[\"Message\"],\n\t\t\tReferenceOr::Item(Message::schema().schema)\n\t\t);\n\t\tassert_eq!(\n\t\t\topenapi.components.clone().unwrap_or_default().schemas[\"Messages\"],\n\t\t\tReferenceOr::Item(Messages::schema().schema)\n\t\t);\n\t}\n}\n","traces":[{"line":26,"address":[6055883,6054048,6055686],"length":1,"stats":{"Line":3},"fn_name":null},{"line":28,"address":[7544280,7542955,7543785],"length":1,"stats":{"Line":9},"fn_name":null},{"line":50,"address":[7545200,7545829,7545793],"length":1,"stats":{"Line":2},"fn_name":null},{"line":51,"address":[7545323],"length":1,"stats":{"Line":2},"fn_name":null},{"line":52,"address":[7545357,7545433],"length":1,"stats":{"Line":4},"fn_name":null},{"line":53,"address":[7545522],"length":1,"stats":{"Line":1},"fn_name":null},{"line":54,"address":[6056583,6056690],"length":1,"stats":{"Line":4},"fn_name":null},{"line":58,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":59,"address":[],"length":0,"stats":{"Line":4},"fn_name":null},{"line":60,"address":[],"length":0,"stats":{"Line":4},"fn_name":null},{"line":63,"address":[6056960,6058064,6058229],"length":1,"stats":{"Line":2},"fn_name":null},{"line":64,"address":[7545961],"length":1,"stats":{"Line":2},"fn_name":null},{"line":66,"address":[7546072],"length":1,"stats":{"Line":2},"fn_name":null},{"line":67,"address":[7546134,7546207],"length":1,"stats":{"Line":4},"fn_name":null},{"line":68,"address":[7546289],"length":1,"stats":{"Line":2},"fn_name":null},{"line":69,"address":[7547057,7546297],"length":1,"stats":{"Line":4},"fn_name":null},{"line":72,"address":[7546258],"length":1,"stats":{"Line":2},"fn_name":null},{"line":73,"address":[7546471,7546676],"length":1,"stats":{"Line":4},"fn_name":null},{"line":74,"address":[7546695,7547002],"length":1,"stats":{"Line":2},"fn_name":null},{"line":79,"address":[6058895,6058272],"length":1,"stats":{"Line":3},"fn_name":null},{"line":80,"address":[6058928,6058318,6058963],"length":1,"stats":{"Line":7},"fn_name":"{closure#0}"},{"line":81,"address":[6058521,6058363,6058849],"length":1,"stats":{"Line":7},"fn_name":null},{"line":82,"address":[6058574,6058622],"length":1,"stats":{"Line":4},"fn_name":null},{"line":83,"address":[6058630],"length":1,"stats":{"Line":2},"fn_name":null},{"line":84,"address":[6058790,6058707],"length":1,"stats":{"Line":4},"fn_name":null},{"line":89,"address":[6059807,6058992,6059749],"length":1,"stats":{"Line":3},"fn_name":null},{"line":90,"address":[6059035,6059139],"length":1,"stats":{"Line":6},"fn_name":null},{"line":91,"address":[6059189],"length":1,"stats":{"Line":1},"fn_name":null},{"line":93,"address":[6059413],"length":1,"stats":{"Line":1},"fn_name":null},{"line":95,"address":[6059534],"length":1,"stats":{"Line":1},"fn_name":null},{"line":96,"address":[6059680],"length":1,"stats":{"Line":1},"fn_name":null},{"line":99,"address":[6059175],"length":1,"stats":{"Line":3},"fn_name":null},{"line":100,"address":[6059294],"length":1,"stats":{"Line":3},"fn_name":null}],"covered":33,"coverable":33},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","openapi","handler","mod.rs"],"content":"#![cfg_attr(not(feature = \"auth\"), allow(unused_imports))]\nuse super::SECURITY_NAME;\nuse base64::prelude::*;\nuse futures_util::{future, future::FutureExt};\nuse gotham::{\n\tanyhow,\n\thandler::{Handler, HandlerError, HandlerFuture, NewHandler},\n\thelpers::http::response::{create_empty_response, create_response},\n\thyper::{\n\t\theader::{\n\t\t\tHeaderMap, HeaderValue, CACHE_CONTROL, CONTENT_SECURITY_POLICY, ETAG, IF_NONE_MATCH,\n\t\t\tREFERRER_POLICY, X_CONTENT_TYPE_OPTIONS\n\t\t},\n\t\tBody, Response, StatusCode\n\t},\n\tmime::{APPLICATION_JSON, TEXT_HTML_UTF_8, TEXT_PLAIN_UTF_8},\n\tstate::State\n};\nuse gotham_restful_redoc::Redoc;\nuse openapi_type::{\n\tindexmap::IndexMap,\n\topenapiv3::{APIKeyLocation, OpenAPI, ReferenceOr, SecurityScheme}\n};\nuse parking_lot::RwLock;\nuse sha2::{Digest, Sha256};\nuse std::{panic::RefUnwindSafe, pin::Pin, sync::Arc};\n\n#[cfg(feature = \"auth\")]\nfn get_security(state: &State) -> IndexMap> {\n\tuse crate::AuthSource;\n\tuse gotham::state::FromState;\n\n\tlet source = match AuthSource::try_borrow_from(state) {\n\t\tSome(source) => source,\n\t\tNone => return Default::default()\n\t};\n\n\tlet security_scheme = match source {\n\t\tAuthSource::Cookie(name) => SecurityScheme::APIKey {\n\t\t\tlocation: APIKeyLocation::Cookie,\n\t\t\tname: name.to_string(),\n\t\t\tdescription: None\n\t\t},\n\t\tAuthSource::Header(name) => SecurityScheme::APIKey {\n\t\t\tlocation: APIKeyLocation::Header,\n\t\t\tname: name.to_string(),\n\t\t\tdescription: None\n\t\t},\n\t\tAuthSource::AuthorizationHeader => SecurityScheme::HTTP {\n\t\t\tscheme: \"bearer\".to_owned(),\n\t\t\tbearer_format: Some(\"JWT\".to_owned()),\n\t\t\tdescription: None\n\t\t}\n\t};\n\n\tlet mut security_schemes: IndexMap> = Default::default();\n\tsecurity_schemes.insert(SECURITY_NAME.to_owned(), ReferenceOr::Item(security_scheme));\n\n\tsecurity_schemes\n}\n\n#[cfg(not(feature = \"auth\"))]\nfn get_security(_state: &State) -> IndexMap> {\n\tDefault::default()\n}\n\nfn openapi_string(\n\tstate: &State,\n\topenapi: &Arc>\n) -> Result {\n\tlet openapi = openapi.read();\n\n\tlet mut openapi = openapi.clone();\n\tlet security_schemes = get_security(state);\n\tlet mut components = openapi.components.unwrap_or_default();\n\tcomponents.security_schemes = security_schemes;\n\topenapi.components = Some(components);\n\n\tserde_json::to_string(&openapi)\n}\n\nfn create_openapi_response(state: &State, openapi: &Arc>) -> Response {\n\tmatch openapi_string(state, openapi) {\n\t\tOk(body) => {\n\t\t\tlet mut res = create_response(state, StatusCode::OK, APPLICATION_JSON, body);\n\t\t\tlet headers = res.headers_mut();\n\t\t\theaders.insert(X_CONTENT_TYPE_OPTIONS, HeaderValue::from_static(\"nosniff\"));\n\t\t\tres\n\t\t},\n\t\tErr(e) => {\n\t\t\terror!(\"Unable to handle OpenAPI request due to error: {e}\");\n\t\t\tcreate_response(\n\t\t\t\tstate,\n\t\t\t\tStatusCode::INTERNAL_SERVER_ERROR,\n\t\t\t\tTEXT_PLAIN_UTF_8,\n\t\t\t\t\"\"\n\t\t\t)\n\t\t}\n\t}\n}\n\n#[derive(Clone)]\npub(crate) struct OpenapiSpecHandler {\n\topenapi: Arc>\n}\n\n// safety: the handler only ever aquires a read lock, so this usage of\n// RwLock is, in fact, unwind safe\nimpl RefUnwindSafe for OpenapiSpecHandler {}\n\nimpl OpenapiSpecHandler {\n\tpub(crate) fn new(openapi: Arc>) -> Self {\n\t\tSelf { openapi }\n\t}\n}\n\nimpl NewHandler for OpenapiSpecHandler {\n\ttype Instance = Self;\n\n\tfn new_handler(&self) -> anyhow::Result {\n\t\tOk(self.clone())\n\t}\n}\n\nimpl Handler for OpenapiSpecHandler {\n\tfn handle(self, mut state: State) -> Pin> {\n\t\tlet res = create_openapi_response(&mut state, &self.openapi);\n\t\tfuture::ok((state, res)).boxed()\n\t}\n}\n\n#[derive(Clone)]\npub(crate) struct OpenapiDocHandler {\n\topenapi: Arc>\n}\n\n// safety: the handler only ever aquires a read lock, so this usage of\n// RwLock is, in fact, unwind safe\nimpl RefUnwindSafe for OpenapiDocHandler {}\n\nimpl OpenapiDocHandler {\n\tpub(crate) fn new(openapi: Arc>) -> Self {\n\t\tSelf { openapi }\n\t}\n}\n\nimpl NewHandler for OpenapiDocHandler {\n\ttype Instance = Self;\n\n\tfn new_handler(&self) -> anyhow::Result {\n\t\tOk(self.clone())\n\t}\n}\n\nfn redoc_handler(\n\tstate: &State,\n\topenapi: &Arc>\n) -> Result, HandlerError> {\n\tlet spec = openapi_string(state, openapi)?;\n\tlet Redoc { html, script_hash } = gotham_restful_redoc::html(spec);\n\n\tlet mut etag = Sha256::new();\n\tetag.update(&html);\n\tlet etag = format!(\"\\\"{}\\\"\", BASE64_STANDARD.encode(etag.finalize()));\n\n\tif state\n\t\t.borrow::()\n\t\t.get(IF_NONE_MATCH)\n\t\t.map_or(false, |header| header.as_bytes() == etag.as_bytes())\n\t{\n\t\tlet res = create_empty_response(state, StatusCode::NOT_MODIFIED);\n\t\treturn Ok(res);\n\t}\n\n\tlet mut res = create_response(state, StatusCode::OK, TEXT_HTML_UTF_8, html);\n\tlet headers = res.headers_mut();\n\theaders.insert(\n\t\tCACHE_CONTROL,\n\t\tHeaderValue::from_static(\"public,max-age=2592000\")\n\t);\n\theaders.insert(\n\t\tCONTENT_SECURITY_POLICY,\n\t\tformat!(\n\t\t\t\"default-src 'none';base-uri 'none';script-src 'unsafe-inline' https://cdn.jsdelivr.net 'sha256-{script_hash}' 'strict-dynamic';style-src 'unsafe-inline' https://fonts.googleapis.com;font-src https://fonts.gstatic.com;connect-src 'self';img-src blob: data:\",\n\t\t).parse().unwrap()\n\t);\n\theaders.insert(ETAG, etag.parse().unwrap());\n\theaders.insert(REFERRER_POLICY, HeaderValue::from_static(\"no-referrer\"));\n\theaders.insert(X_CONTENT_TYPE_OPTIONS, HeaderValue::from_static(\"nosniff\"));\n\tOk(res)\n}\n\nimpl Handler for OpenapiDocHandler {\n\tfn handle(self, state: State) -> Pin> {\n\t\tmatch redoc_handler(&state, &self.openapi) {\n\t\t\tOk(res) => future::ok((state, res)).boxed(),\n\t\t\tErr(err) => future::err((state, err)).boxed()\n\t\t}\n\t}\n}\n","traces":[{"line":29,"address":[6283259,6282160],"length":1,"stats":{"Line":2},"fn_name":"get_security"},{"line":33,"address":[6282323,6282198],"length":1,"stats":{"Line":2},"fn_name":null},{"line":34,"address":[6282255],"length":1,"stats":{"Line":1},"fn_name":null},{"line":35,"address":[6282247],"length":1,"stats":{"Line":1},"fn_name":null},{"line":38,"address":[6282273],"length":1,"stats":{"Line":1},"fn_name":null},{"line":41,"address":[6282350],"length":1,"stats":{"Line":0},"fn_name":null},{"line":46,"address":[6282517],"length":1,"stats":{"Line":0},"fn_name":null},{"line":50,"address":[6282656],"length":1,"stats":{"Line":1},"fn_name":null},{"line":51,"address":[6282681,6282774],"length":1,"stats":{"Line":2},"fn_name":null},{"line":56,"address":[6282708],"length":1,"stats":{"Line":1},"fn_name":null},{"line":57,"address":[6283026,6283094],"length":1,"stats":{"Line":2},"fn_name":null},{"line":59,"address":[6283228],"length":1,"stats":{"Line":1},"fn_name":null},{"line":67,"address":[6283312,6284224,6284692],"length":1,"stats":{"Line":2},"fn_name":"openapi_string"},{"line":71,"address":[6283378],"length":1,"stats":{"Line":2},"fn_name":null},{"line":73,"address":[6283433,6283492],"length":1,"stats":{"Line":4},"fn_name":null},{"line":74,"address":[6283520,6283568],"length":1,"stats":{"Line":4},"fn_name":null},{"line":75,"address":[6283677,6283576],"length":1,"stats":{"Line":4},"fn_name":null},{"line":76,"address":[6283693],"length":1,"stats":{"Line":2},"fn_name":null},{"line":77,"address":[6283949],"length":1,"stats":{"Line":2},"fn_name":null},{"line":79,"address":[6284081],"length":1,"stats":{"Line":2},"fn_name":null},{"line":82,"address":[6284720,6285339],"length":1,"stats":{"Line":2},"fn_name":"create_openapi_response"},{"line":83,"address":[6284758],"length":1,"stats":{"Line":2},"fn_name":null},{"line":84,"address":[6284811],"length":1,"stats":{"Line":2},"fn_name":null},{"line":85,"address":[6284834],"length":1,"stats":{"Line":2},"fn_name":null},{"line":86,"address":[6285092,6284969],"length":1,"stats":{"Line":4},"fn_name":null},{"line":87,"address":[6285100,6285317],"length":1,"stats":{"Line":2},"fn_name":null},{"line":88,"address":[6285286],"length":1,"stats":{"Line":2},"fn_name":null},{"line":90,"address":[6284985],"length":1,"stats":{"Line":0},"fn_name":null},{"line":91,"address":[6284998,6285601,6285736,6285410],"length":1,"stats":{"Line":0},"fn_name":null},{"line":95,"address":[6285430],"length":1,"stats":{"Line":0},"fn_name":null},{"line":112,"address":[6285888],"length":1,"stats":{"Line":2},"fn_name":null},{"line":120,"address":[6285904],"length":1,"stats":{"Line":2},"fn_name":"new_handler"},{"line":121,"address":[6285913],"length":1,"stats":{"Line":2},"fn_name":null},{"line":126,"address":[6286248,6285952],"length":1,"stats":{"Line":2},"fn_name":"handle"},{"line":127,"address":[6285995],"length":1,"stats":{"Line":2},"fn_name":null},{"line":128,"address":[6286048,6285969],"length":1,"stats":{"Line":4},"fn_name":null},{"line":142,"address":[6286288],"length":1,"stats":{"Line":0},"fn_name":null},{"line":150,"address":[6286304],"length":1,"stats":{"Line":0},"fn_name":"new_handler"},{"line":151,"address":[6286313],"length":1,"stats":{"Line":0},"fn_name":null},{"line":155,"address":[6289605,6286352,6289376],"length":1,"stats":{"Line":0},"fn_name":"redoc_handler"},{"line":159,"address":[6286667,6286396],"length":1,"stats":{"Line":0},"fn_name":null},{"line":160,"address":[6286592,6286741],"length":1,"stats":{"Line":0},"fn_name":null},{"line":162,"address":[6286813],"length":1,"stats":{"Line":0},"fn_name":null},{"line":163,"address":[6286892],"length":1,"stats":{"Line":0},"fn_name":null},{"line":164,"address":[6287147,6286899],"length":1,"stats":{"Line":0},"fn_name":null},{"line":166,"address":[6287381,6287476,6287521],"length":1,"stats":{"Line":0},"fn_name":null},{"line":168,"address":[6287446],"length":1,"stats":{"Line":0},"fn_name":null},{"line":169,"address":[6289648,6289673,6287513],"length":1,"stats":{"Line":0},"fn_name":"{closure#0}"},{"line":171,"address":[6287736],"length":1,"stats":{"Line":0},"fn_name":null},{"line":172,"address":[6289503],"length":1,"stats":{"Line":0},"fn_name":null},{"line":175,"address":[6287561],"length":1,"stats":{"Line":0},"fn_name":null},{"line":176,"address":[6287763,6287836],"length":1,"stats":{"Line":0},"fn_name":null},{"line":177,"address":[6287955],"length":1,"stats":{"Line":0},"fn_name":null},{"line":178,"address":[6287844],"length":1,"stats":{"Line":0},"fn_name":null},{"line":179,"address":[6287882],"length":1,"stats":{"Line":0},"fn_name":null},{"line":181,"address":[6288438],"length":1,"stats":{"Line":0},"fn_name":null},{"line":182,"address":[6288025],"length":1,"stats":{"Line":0},"fn_name":null},{"line":183,"address":[6288192,6288380],"length":1,"stats":{"Line":0},"fn_name":null},{"line":187,"address":[6288571,6289409],"length":1,"stats":{"Line":0},"fn_name":null},{"line":188,"address":[6288813,6289387],"length":1,"stats":{"Line":0},"fn_name":null},{"line":189,"address":[6288994,6289354],"length":1,"stats":{"Line":0},"fn_name":null},{"line":190,"address":[6289217],"length":1,"stats":{"Line":0},"fn_name":null},{"line":194,"address":[6290339,6289744],"length":1,"stats":{"Line":0},"fn_name":"handle"},{"line":195,"address":[6290212,6289761,6289835],"length":1,"stats":{"Line":0},"fn_name":null},{"line":196,"address":[6290163,6289902],"length":1,"stats":{"Line":0},"fn_name":null},{"line":197,"address":[6290032,6290260],"length":1,"stats":{"Line":0},"fn_name":null}],"covered":31,"coverable":66},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","openapi","mod.rs"],"content":"const SECURITY_NAME: &str = \"authToken\";\n\npub(crate) mod builder;\npub(crate) mod handler;\npub(crate) mod operation;\npub(crate) mod router;\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","openapi","operation.rs"],"content":"use super::SECURITY_NAME;\nuse crate::{response::OrAllTypes, EndpointWithSchema, IntoResponse, RequestBody};\nuse gotham::{hyper::StatusCode, mime::Mime};\nuse openapi_type::{\n\tindexmap::IndexMap,\n\topenapiv3::{\n\t\tMediaType, Operation, Parameter, ParameterData, ParameterSchemaOrContent, ReferenceOr,\n\t\tReferenceOr::Item, RequestBody as OARequestBody, Response, Responses, Schema, SchemaKind,\n\t\tStatusCode as OAStatusCode, Type\n\t},\n\tOpenapiSchema\n};\nuse std::collections::HashMap;\n\nfn new_parameter_data(\n\tname: String,\n\trequired: bool,\n\tschema: ReferenceOr>\n) -> ParameterData {\n\tParameterData {\n\t\tname,\n\t\tdescription: None,\n\t\trequired,\n\t\tdeprecated: None,\n\t\tformat: ParameterSchemaOrContent::Schema(schema.unbox()),\n\t\texample: None,\n\t\texamples: Default::default(),\n\t\texplode: None,\n\t\textensions: Default::default()\n\t}\n}\n\n#[derive(Default)]\nstruct OperationParams {\n\tpath_params: Option,\n\tquery_params: Option\n}\n\nimpl OperationParams {\n\t// TODO shouldn't this be a custom openapi_type::Visitor\n\t// rather than this hacky code?\n\tfn add_path_params(\n\t\tpath_params: Option,\n\t\tparams: &mut Vec>\n\t) {\n\t\tlet path_params = match path_params {\n\t\t\tSome(pp) => pp.schema,\n\t\t\tNone => return\n\t\t};\n\t\tlet path_params = match path_params.schema_kind {\n\t\t\tSchemaKind::Type(Type::Object(ty)) => ty,\n\t\t\t_ => panic!(\"Path Parameters needs to be a plain struct\")\n\t\t};\n\t\tfor (name, schema) in path_params.properties {\n\t\t\tlet required = path_params.required.contains(&name);\n\t\t\tparams.push(Item(Parameter::Path {\n\t\t\t\tparameter_data: new_parameter_data(name, required, schema),\n\t\t\t\tstyle: Default::default()\n\t\t\t}))\n\t\t}\n\t}\n\n\t// TODO shouldn't this be a custom openapi_type::Visitor\n\t// rather than this hacky code?\n\tfn add_query_params(\n\t\tquery_params: Option,\n\t\tparams: &mut Vec>\n\t) {\n\t\tlet query_params = match query_params {\n\t\t\tSome(qp) => qp.schema,\n\t\t\tNone => return\n\t\t};\n\t\tlet query_params = match query_params.schema_kind {\n\t\t\tSchemaKind::Type(Type::Object(ty)) => ty,\n\t\t\t_ => panic!(\"Query Parameters needs to be a plain struct\")\n\t\t};\n\t\tfor (name, schema) in query_params.properties {\n\t\t\tlet required = query_params.required.contains(&name);\n\t\t\tparams.push(Item(Parameter::Query {\n\t\t\t\tparameter_data: new_parameter_data(name, required, schema),\n\t\t\t\tallow_reserved: false,\n\t\t\t\tstyle: Default::default(),\n\t\t\t\tallow_empty_value: None\n\t\t\t}))\n\t\t}\n\t}\n\n\tfn into_params(self) -> Vec> {\n\t\tlet mut params: Vec> = Vec::new();\n\t\tSelf::add_path_params(self.path_params, &mut params);\n\t\tSelf::add_query_params(self.query_params, &mut params);\n\t\tparams\n\t}\n}\n\npub(crate) struct OperationDescription {\n\toperation_id: Option,\n\tdescription: Option,\n\n\taccepted_types: Option>,\n\tresponses: HashMap>,\n\tparams: OperationParams,\n\tbody_schema: Option>,\n\tsupported_types: Option>,\n\trequires_auth: bool\n}\n\nimpl OperationDescription {\n\t/// Create a new operation description for the given endpoint type and schema. If the endpoint\n\t/// does not specify an operation id, the path is used to generate one.\n\tpub(crate) fn new(\n\t\tresponses: HashMap>,\n\t\tpath: &str\n\t) -> Self {\n\t\tlet operation_id = E::operation_id().or_else(|| {\n\t\t\tE::operation_verb()\n\t\t\t\t.map(|verb| format!(\"{verb}_{}\", path.replace(\"/\", \"_\").trim_start_matches('_')))\n\t\t});\n\t\tSelf {\n\t\t\toperation_id,\n\t\t\tdescription: E::description(),\n\n\t\t\taccepted_types: E::Output::accepted_types(),\n\t\t\tresponses,\n\t\t\tparams: Default::default(),\n\t\t\tbody_schema: None,\n\t\t\tsupported_types: None,\n\t\t\trequires_auth: E::wants_auth()\n\t\t}\n\t}\n\n\tpub(crate) fn set_path_params(&mut self, params: OpenapiSchema) {\n\t\tself.params.path_params = Some(params);\n\t}\n\n\tpub(crate) fn set_query_params(&mut self, params: OpenapiSchema) {\n\t\tself.params.query_params = Some(params);\n\t}\n\n\tpub(crate) fn set_body(&mut self, schema: ReferenceOr) {\n\t\tself.body_schema = Some(schema);\n\t\tself.supported_types = Body::supported_types();\n\t}\n\n\tfn schema_to_content(\n\t\ttypes: Vec,\n\t\tschema: ReferenceOr\n\t) -> IndexMap {\n\t\tlet mut content: IndexMap = IndexMap::new();\n\t\tfor ty in types {\n\t\t\tcontent.insert(ty.to_string(), MediaType {\n\t\t\t\tschema: Some(schema.clone()),\n\t\t\t\t..Default::default()\n\t\t\t});\n\t\t}\n\t\tcontent\n\t}\n\n\tpub(crate) fn into_operation(self) -> Operation {\n\t\t// this is unfortunately neccessary to prevent rust from complaining about partially moving self\n\t\tlet (\n\t\t\toperation_id,\n\t\t\tdescription,\n\t\t\taccepted_types,\n\t\t\tresponses,\n\t\t\tparams,\n\t\t\tbody_schema,\n\t\t\tsupported_types,\n\t\t\trequires_auth\n\t\t) = (\n\t\t\tself.operation_id,\n\t\t\tself.description,\n\t\t\tself.accepted_types,\n\t\t\tself.responses,\n\t\t\tself.params,\n\t\t\tself.body_schema,\n\t\t\tself.supported_types,\n\t\t\tself.requires_auth\n\t\t);\n\n\t\tlet responses: IndexMap> = responses\n\t\t\t.into_iter()\n\t\t\t.map(|(code, schema)| {\n\t\t\t\tlet content =\n\t\t\t\t\tSelf::schema_to_content(accepted_types.clone().or_all_types(), schema);\n\t\t\t\t(\n\t\t\t\t\tOAStatusCode::Code(code.as_u16()),\n\t\t\t\t\tItem(Response {\n\t\t\t\t\t\tdescription: code\n\t\t\t\t\t\t\t.canonical_reason()\n\t\t\t\t\t\t\t.map(|d| d.to_string())\n\t\t\t\t\t\t\t.unwrap_or_default(),\n\t\t\t\t\t\tcontent,\n\t\t\t\t\t\t..Default::default()\n\t\t\t\t\t})\n\t\t\t\t)\n\t\t\t})\n\t\t\t.collect();\n\n\t\tlet request_body = body_schema.map(|schema| {\n\t\t\tItem(OARequestBody {\n\t\t\t\tcontent: Self::schema_to_content(supported_types.or_all_types(), schema),\n\t\t\t\trequired: true,\n\t\t\t\t..Default::default()\n\t\t\t})\n\t\t});\n\n\t\tlet mut security = None;\n\t\tif requires_auth {\n\t\t\tlet mut sec = IndexMap::new();\n\t\t\tsec.insert(SECURITY_NAME.to_owned(), Vec::new());\n\t\t\tsecurity = Some(vec![sec]);\n\t\t}\n\n\t\tOperation {\n\t\t\ttags: Vec::new(),\n\t\t\toperation_id,\n\t\t\tdescription,\n\t\t\tparameters: params.into_params(),\n\t\t\trequest_body,\n\t\t\tresponses: Responses {\n\t\t\t\tresponses,\n\t\t\t\t..Default::default()\n\t\t\t},\n\t\t\tdeprecated: false,\n\t\t\tsecurity,\n\t\t\t..Default::default()\n\t\t}\n\t}\n}\n\n#[cfg(test)]\nmod test {\n\tuse super::*;\n\tuse crate::{NoContent, Raw, ResponseSchema};\n\n\t#[test]\n\tfn no_content_schema_to_content() {\n\t\tlet types = NoContent::accepted_types();\n\t\tlet schema = ::schema(StatusCode::NO_CONTENT);\n\t\tlet content =\n\t\t\tOperationDescription::schema_to_content(types.or_all_types(), Item(schema.schema));\n\t\tassert!(content.is_empty());\n\t}\n\n\t#[test]\n\tfn raw_schema_to_content() {\n\t\tlet types = Raw::<&str>::accepted_types();\n\t\tlet schema = as ResponseSchema>::schema(StatusCode::OK);\n\t\tlet content =\n\t\t\tOperationDescription::schema_to_content(types.or_all_types(), Item(schema.schema));\n\t\tassert_eq!(content.len(), 1);\n\t\tlet json = serde_json::to_string(&content.values().nth(0).unwrap()).unwrap();\n\t\tassert_eq!(json, r#\"{\"schema\":{\"type\":\"string\",\"format\":\"binary\"}}\"#);\n\t}\n}\n","traces":[{"line":15,"address":[6228237,6228283,6227680],"length":1,"stats":{"Line":1},"fn_name":"new_parameter_data"},{"line":25,"address":[6227836,6227763],"length":1,"stats":{"Line":2},"fn_name":null},{"line":27,"address":[6227846],"length":1,"stats":{"Line":1},"fn_name":null},{"line":29,"address":[6227917],"length":1,"stats":{"Line":1},"fn_name":null},{"line":42,"address":[6228304,6229448,6229417],"length":1,"stats":{"Line":2},"fn_name":null},{"line":46,"address":[6228344],"length":1,"stats":{"Line":2},"fn_name":null},{"line":47,"address":[6228404],"length":1,"stats":{"Line":1},"fn_name":null},{"line":50,"address":[6228474,6228512],"length":1,"stats":{"Line":2},"fn_name":null},{"line":51,"address":[6228570],"length":1,"stats":{"Line":1},"fn_name":null},{"line":54,"address":[6228792,6228645,6229841],"length":1,"stats":{"Line":3},"fn_name":null},{"line":55,"address":[6229518,6229043],"length":1,"stats":{"Line":2},"fn_name":null},{"line":56,"address":[6229721],"length":1,"stats":{"Line":1},"fn_name":null},{"line":57,"address":[6229545],"length":1,"stats":{"Line":1},"fn_name":null},{"line":58,"address":[6229662],"length":1,"stats":{"Line":1},"fn_name":null},{"line":65,"address":[6231240,6231209,6230096],"length":1,"stats":{"Line":2},"fn_name":null},{"line":69,"address":[6230136],"length":1,"stats":{"Line":2},"fn_name":null},{"line":70,"address":[6230196],"length":1,"stats":{"Line":1},"fn_name":null},{"line":73,"address":[6230304,6230266],"length":1,"stats":{"Line":2},"fn_name":null},{"line":74,"address":[6230362],"length":1,"stats":{"Line":1},"fn_name":null},{"line":77,"address":[6231663,6230437,6230584],"length":1,"stats":{"Line":3},"fn_name":null},{"line":78,"address":[6230835,6231310],"length":1,"stats":{"Line":2},"fn_name":null},{"line":79,"address":[6231521],"length":1,"stats":{"Line":1},"fn_name":null},{"line":80,"address":[6231337],"length":1,"stats":{"Line":1},"fn_name":null},{"line":82,"address":[6231454],"length":1,"stats":{"Line":1},"fn_name":null},{"line":83,"address":[6231513],"length":1,"stats":{"Line":1},"fn_name":null},{"line":88,"address":[6232209,6231904,6232248],"length":1,"stats":{"Line":2},"fn_name":null},{"line":89,"address":[6231926],"length":1,"stats":{"Line":2},"fn_name":null},{"line":90,"address":[6232016],"length":1,"stats":{"Line":2},"fn_name":null},{"line":91,"address":[6232108],"length":1,"stats":{"Line":2},"fn_name":null},{"line":92,"address":[6232175],"length":1,"stats":{"Line":2},"fn_name":null},{"line":111,"address":[6511429,6510656,6511503],"length":1,"stats":{"Line":8},"fn_name":null},{"line":115,"address":[],"length":0,"stats":{"Line":22},"fn_name":null},{"line":116,"address":[],"length":0,"stats":{"Line":12},"fn_name":null},{"line":117,"address":[],"length":0,"stats":{"Line":22},"fn_name":null},{"line":121,"address":[],"length":0,"stats":{"Line":8},"fn_name":null},{"line":123,"address":[],"length":0,"stats":{"Line":8},"fn_name":null},{"line":125,"address":[],"length":0,"stats":{"Line":8},"fn_name":null},{"line":128,"address":[],"length":0,"stats":{"Line":8},"fn_name":null},{"line":132,"address":[6232367,6232288],"length":1,"stats":{"Line":1},"fn_name":null},{"line":133,"address":[6232409,6232325],"length":1,"stats":{"Line":2},"fn_name":null},{"line":136,"address":[6232525,6232432],"length":1,"stats":{"Line":1},"fn_name":null},{"line":137,"address":[6232567,6232469],"length":1,"stats":{"Line":2},"fn_name":null},{"line":140,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":141,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":142,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":145,"address":[6232608,6233849],"length":1,"stats":{"Line":3},"fn_name":null},{"line":149,"address":[6232650],"length":1,"stats":{"Line":3},"fn_name":null},{"line":150,"address":[6232813,6232724],"length":1,"stats":{"Line":6},"fn_name":null},{"line":151,"address":[6233087,6233443],"length":1,"stats":{"Line":6},"fn_name":null},{"line":152,"address":[6233265,6233353],"length":1,"stats":{"Line":6},"fn_name":null},{"line":153,"address":[6233363],"length":1,"stats":{"Line":3},"fn_name":null},{"line":156,"address":[6233107],"length":1,"stats":{"Line":3},"fn_name":null},{"line":159,"address":[6237609,6237869,6233904],"length":1,"stats":{"Line":2},"fn_name":null},{"line":161,"address":[6233971,6234325],"length":1,"stats":{"Line":4},"fn_name":null},{"line":162,"address":[6234572],"length":1,"stats":{"Line":2},"fn_name":null},{"line":163,"address":[6234612],"length":1,"stats":{"Line":2},"fn_name":null},{"line":164,"address":[6234652],"length":1,"stats":{"Line":2},"fn_name":null},{"line":165,"address":[6234684],"length":1,"stats":{"Line":2},"fn_name":null},{"line":166,"address":[6234740],"length":1,"stats":{"Line":2},"fn_name":null},{"line":167,"address":[6234773],"length":1,"stats":{"Line":2},"fn_name":null},{"line":168,"address":[6234791],"length":1,"stats":{"Line":2},"fn_name":null},{"line":169,"address":[6234831],"length":1,"stats":{"Line":2},"fn_name":null},{"line":171,"address":[6234051],"length":1,"stats":{"Line":2},"fn_name":null},{"line":172,"address":[6234081],"length":1,"stats":{"Line":2},"fn_name":null},{"line":173,"address":[6234111],"length":1,"stats":{"Line":2},"fn_name":null},{"line":174,"address":[6234141],"length":1,"stats":{"Line":2},"fn_name":null},{"line":175,"address":[6234221],"length":1,"stats":{"Line":2},"fn_name":null},{"line":176,"address":[6234233],"length":1,"stats":{"Line":2},"fn_name":null},{"line":177,"address":[6234285],"length":1,"stats":{"Line":2},"fn_name":null},{"line":178,"address":[6234315],"length":1,"stats":{"Line":2},"fn_name":null},{"line":181,"address":[6234849,6234985],"length":1,"stats":{"Line":4},"fn_name":null},{"line":183,"address":[6239378,6239433,6234977,6238299,6238256],"length":1,"stats":{"Line":6},"fn_name":"{closure#0}"},{"line":185,"address":[6238359,6238434],"length":1,"stats":{"Line":4},"fn_name":null},{"line":187,"address":[6238580,6238522],"length":1,"stats":{"Line":4},"fn_name":null},{"line":188,"address":[6238819],"length":1,"stats":{"Line":2},"fn_name":null},{"line":189,"address":[6238598],"length":1,"stats":{"Line":2},"fn_name":null},{"line":191,"address":[6239472,6239494],"length":1,"stats":{"Line":4},"fn_name":"{closure#0}"},{"line":193,"address":[6238672],"length":1,"stats":{"Line":2},"fn_name":null},{"line":194,"address":[6238768],"length":1,"stats":{"Line":2},"fn_name":null},{"line":200,"address":[6239520,6235047,6240005],"length":1,"stats":{"Line":3},"fn_name":"{closure#1}"},{"line":201,"address":[6239542,6239775],"length":1,"stats":{"Line":2},"fn_name":null},{"line":202,"address":[6239558,6239650],"length":1,"stats":{"Line":2},"fn_name":null},{"line":204,"address":[6239719],"length":1,"stats":{"Line":1},"fn_name":null},{"line":208,"address":[6235211],"length":1,"stats":{"Line":2},"fn_name":null},{"line":209,"address":[6235223,6235892],"length":1,"stats":{"Line":3},"fn_name":null},{"line":210,"address":[6235257],"length":1,"stats":{"Line":1},"fn_name":null},{"line":211,"address":[6235381,6237966,6235308],"length":1,"stats":{"Line":2},"fn_name":null},{"line":212,"address":[6235530],"length":1,"stats":{"Line":1},"fn_name":null},{"line":216,"address":[6235227],"length":1,"stats":{"Line":2},"fn_name":null},{"line":219,"address":[6235977],"length":1,"stats":{"Line":2},"fn_name":null},{"line":221,"address":[6236297],"length":1,"stats":{"Line":2},"fn_name":null}],"covered":91,"coverable":91},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","openapi","router.rs"],"content":"use super::{\n\tbuilder::OpenapiBuilder,\n\thandler::{OpenapiDocHandler, OpenapiSpecHandler},\n\toperation::OperationDescription\n};\nuse crate::{routing::*, EndpointWithSchema, ResourceWithSchema, ResponseSchema};\nuse gotham::{\n\thyper::{Method, StatusCode},\n\tpipeline::PipelineHandleChain,\n\tprelude::*,\n\trouter::builder::{RouterBuilder, ScopeBuilder}\n};\nuse lazy_regex::regex_replace_all;\nuse openapi_type::OpenapiType;\nuse std::{collections::HashMap, panic::RefUnwindSafe};\n\n/// This trait adds the `openapi_spec` and `openapi_doc` method to an OpenAPI-aware router.\npub trait GetOpenapi {\n\t/// Register a GET route to `path` that returns the OpenAPI specification in JSON format.\n\tfn openapi_spec(&mut self, path: &str);\n\n\t/// Register a GET route to `path` that returns the OpenAPI documentation in HTML format.\n\tfn openapi_doc(&mut self, path: &str);\n}\n\n#[derive(Debug)]\npub struct OpenapiRouter<'a, D> {\n\tpub(crate) router: &'a mut D,\n\tpub(crate) scope: Option<&'a str>,\n\tpub(crate) openapi_builder: &'a mut OpenapiBuilder\n}\n\nmacro_rules! implOpenapiRouter {\n\t($implType:ident) => {\n\t\timpl<'a, 'b, C, P> OpenapiRouter<'a, $implType<'b, C, P>>\n\t\twhere\n\t\t\tC: PipelineHandleChain

+ Copy + Send + Sync + 'static,\n\t\t\tP: RefUnwindSafe + Send + Sync + 'static\n\t\t{\n\t\t\tpub fn scope(&mut self, path: &str, callback: F)\n\t\t\twhere\n\t\t\t\tF: FnOnce(&mut OpenapiRouter<'_, ScopeBuilder<'_, C, P>>)\n\t\t\t{\n\t\t\t\tlet mut openapi_builder = self.openapi_builder.clone();\n\t\t\t\tlet new_scope = self\n\t\t\t\t\t.scope\n\t\t\t\t\t.map(|scope| format!(\"{scope}/{path}\").replace(\"//\", \"/\"));\n\t\t\t\tself.router.scope(path, |router| {\n\t\t\t\t\tlet mut router = OpenapiRouter {\n\t\t\t\t\t\trouter,\n\t\t\t\t\t\tscope: Some(new_scope.as_ref().map(String::as_ref).unwrap_or(path)),\n\t\t\t\t\t\topenapi_builder: &mut openapi_builder\n\t\t\t\t\t};\n\t\t\t\t\tcallback(&mut router);\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\timpl<'a, 'b, C, P> GetOpenapi for OpenapiRouter<'a, $implType<'b, C, P>>\n\t\twhere\n\t\t\tC: PipelineHandleChain

+ Copy + Send + Sync + 'static,\n\t\t\tP: RefUnwindSafe + Send + Sync + 'static\n\t\t{\n\t\t\tfn openapi_spec(&mut self, path: &str) {\n\t\t\t\tself.router\n\t\t\t\t\t.get(path)\n\t\t\t\t\t.to_new_handler(OpenapiSpecHandler::new(\n\t\t\t\t\t\tself.openapi_builder.openapi.clone()\n\t\t\t\t\t));\n\t\t\t}\n\n\t\t\tfn openapi_doc(&mut self, path: &str) {\n\t\t\t\tself.router\n\t\t\t\t\t.get(path)\n\t\t\t\t\t.to_new_handler(OpenapiDocHandler::new(self.openapi_builder.openapi.clone()));\n\t\t\t}\n\t\t}\n\n\t\timpl<'a, 'b, C, P> DrawResourcesWithSchema for OpenapiRouter<'a, $implType<'b, C, P>>\n\t\twhere\n\t\t\tC: PipelineHandleChain

+ Copy + Send + Sync + 'static,\n\t\t\tP: RefUnwindSafe + Send + Sync + 'static\n\t\t{\n\t\t\tfn resource(&mut self, mut path: &str) {\n\t\t\t\tif path.starts_with('/') {\n\t\t\t\t\tpath = &path[1..];\n\t\t\t\t}\n\t\t\t\tR::setup((self, path));\n\t\t\t}\n\t\t}\n\n\t\timpl<'a, 'b, C, P> DrawResourceRoutesWithSchema\n\t\t\tfor (&mut OpenapiRouter<'a, $implType<'b, C, P>>, &str)\n\t\twhere\n\t\t\tC: PipelineHandleChain

+ Copy + Send + Sync + 'static,\n\t\t\tP: RefUnwindSafe + Send + Sync + 'static\n\t\t{\n\t\t\tfn endpoint(&mut self) {\n\t\t\t\tlet mut responses: HashMap = HashMap::new();\n\t\t\t\tfor code in E::Output::status_codes() {\n\t\t\t\t\tresponses.insert(\n\t\t\t\t\t\tcode,\n\t\t\t\t\t\t(self.0).openapi_builder.add_schema(E::Output::schema(code))\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tlet mut path = format!(\"{}/{}\", self.0.scope.unwrap_or_default(), self.1);\n\t\t\t\tlet mut descr = OperationDescription::new::(responses, &path);\n\t\t\t\tif E::has_placeholders() {\n\t\t\t\t\tdescr.set_path_params(E::Placeholders::schema());\n\t\t\t\t}\n\t\t\t\tif E::needs_params() {\n\t\t\t\t\tdescr.set_query_params(E::Params::schema());\n\t\t\t\t}\n\t\t\t\tif E::needs_body() {\n\t\t\t\t\tlet body_schema = (self.0).openapi_builder.add_schema(E::Body::schema());\n\t\t\t\t\tdescr.set_body::(body_schema);\n\t\t\t\t}\n\n\t\t\t\tlet uri: &str = &E::uri();\n\t\t\t\tlet uri =\n\t\t\t\t\tregex_replace_all!(r#\"(^|/):([^/]+)(/|$)\"#, uri, |_, prefix, name, suffix| {\n\t\t\t\t\t\tformat!(\"{prefix}{{{name}}}{suffix}\")\n\t\t\t\t\t});\n\t\t\t\tif !uri.is_empty() {\n\t\t\t\t\tpath = format!(\"{path}/{uri}\");\n\t\t\t\t}\n\n\t\t\t\tlet op = descr.into_operation();\n\t\t\t\tlet mut item = (self.0).openapi_builder.remove_path(&path);\n\t\t\t\tmatch E::http_method() {\n\t\t\t\t\tMethod::GET => item.get = Some(op),\n\t\t\t\t\tMethod::PUT => item.put = Some(op),\n\t\t\t\t\tMethod::POST => item.post = Some(op),\n\t\t\t\t\tMethod::DELETE => item.delete = Some(op),\n\t\t\t\t\tMethod::OPTIONS => item.options = Some(op),\n\t\t\t\t\tMethod::HEAD => item.head = Some(op),\n\t\t\t\t\tMethod::PATCH => item.patch = Some(op),\n\t\t\t\t\tMethod::TRACE => item.trace = Some(op),\n\t\t\t\t\tmethod => {\n\t\t\t\t\t\twarn!(\"Ignoring unsupported method '{method}' in OpenAPI Specification\")\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\t(self.0).openapi_builder.add_path(path, item);\n\n\t\t\t\t(&mut *(self.0).router, self.1).endpoint::()\n\t\t\t}\n\t\t}\n\t};\n}\n\nimplOpenapiRouter!(RouterBuilder);\nimplOpenapiRouter!(ScopeBuilder);\n","traces":[{"line":40,"address":[6811186,6812258,6811936,6810864],"length":1,"stats":{"Line":2},"fn_name":null},{"line":44,"address":[6810891,6810965,6811963,6812037],"length":1,"stats":{"Line":4},"fn_name":null},{"line":45,"address":[6810988,6812042,6812060,6810970],"length":1,"stats":{"Line":4},"fn_name":null},{"line":47,"address":[6811504,6810983,6811596,6812380,6812433,6811649,6812288,6812055],"length":1,"stats":{"Line":5},"fn_name":"{closure#0}<(), (), openapi_supports_scope::openapi_supports_scope::{closure#0}::{closure#0}::{closure#0}::{closure_env#0}>"},{"line":48,"address":[6812120,6812720,6812977,6811048,6811473,6811216],"length":1,"stats":{"Line":4},"fn_name":"{closure#1}<(), (), openapi_supports_scope::openapi_supports_scope::{closure#0}::{closure#0}::{closure#0}::{closure_env#0}>"},{"line":49,"address":[6812745,6811241,6811408,6812912],"length":1,"stats":{"Line":4},"fn_name":null},{"line":51,"address":[6811251,6811313,6812817,6812755],"length":1,"stats":{"Line":4},"fn_name":null},{"line":52,"address":[6811404,6812908],"length":1,"stats":{"Line":2},"fn_name":null},{"line":54,"address":[6812942,6811438],"length":1,"stats":{"Line":2},"fn_name":null},{"line":64,"address":[6819392,6819548,6819572],"length":1,"stats":{"Line":2},"fn_name":"openapi_spec<(), ()>"},{"line":65,"address":[6819422,6819521],"length":1,"stats":{"Line":4},"fn_name":null},{"line":67,"address":[6819500],"length":1,"stats":{"Line":2},"fn_name":null},{"line":68,"address":[6819450],"length":1,"stats":{"Line":2},"fn_name":null},{"line":84,"address":[6819584,6819728],"length":1,"stats":{"Line":6},"fn_name":"resource<(), (), openapi_supports_scope::FooResource>"},{"line":85,"address":[6819608,6819725,6819869,6819752],"length":1,"stats":{"Line":7},"fn_name":null},{"line":86,"address":[6819822,6819678],"length":1,"stats":{"Line":1},"fn_name":null},{"line":88,"address":[6819782,6819638],"length":1,"stats":{"Line":6},"fn_name":null},{"line":98,"address":[6825961,6826912,6832375,6833001,6819872,6825335],"length":1,"stats":{"Line":9},"fn_name":"endpoint<(), (), openapi_supports_scope::read_all___gotham_restful_endpoint>"},{"line":99,"address":[6819925,6826965],"length":1,"stats":{"Line":9},"fn_name":null},{"line":100,"address":[6820074,6827114,6827178,6820138],"length":1,"stats":{"Line":18},"fn_name":null},{"line":101,"address":[6832945,6825905],"length":1,"stats":{"Line":9},"fn_name":null},{"line":103,"address":[6827401,6820361,6825870,6832910],"length":1,"stats":{"Line":18},"fn_name":null},{"line":106,"address":[6827445,6827630,6820590,6820697,6827737,6820405],"length":1,"stats":{"Line":27},"fn_name":null},{"line":107,"address":[6825821,6832861,6827871,6820831],"length":1,"stats":{"Line":9},"fn_name":null},{"line":108,"address":[6821030,6828070,6821092,6828132],"length":1,"stats":{"Line":18},"fn_name":null},{"line":109,"address":[6828152,6821112],"length":1,"stats":{"Line":4},"fn_name":null},{"line":111,"address":[6821098,6821167,6828207,6828138],"length":1,"stats":{"Line":18},"fn_name":null},{"line":112,"address":[6828227,6821187],"length":1,"stats":{"Line":1},"fn_name":null},{"line":114,"address":[6821173,6828213,6821242,6828282],"length":1,"stats":{"Line":18},"fn_name":null},{"line":115,"address":[6828311,6821271],"length":1,"stats":{"Line":2},"fn_name":null},{"line":116,"address":[6821356,6828396],"length":1,"stats":{"Line":2},"fn_name":null},{"line":119,"address":[6828405,6821365,6828500,6821460,6821256,6828296],"length":1,"stats":{"Line":27},"fn_name":null},{"line":121,"address":[6421929,6422187,6421904,6421709,6421584,6421867,6422029,6421609],"length":1,"stats":{"Line":62},"fn_name":"{closure#0}"},{"line":122,"address":[6833778,6826770],"length":1,"stats":{"Line":4},"fn_name":null},{"line":124,"address":[6821564,6821659,6828604,6828699,6829278,6822238],"length":1,"stats":{"Line":23},"fn_name":null},{"line":125,"address":[6821986,6829026],"length":1,"stats":{"Line":5},"fn_name":null},{"line":128,"address":[6822251,6829291,6821767,6828807],"length":1,"stats":{"Line":18},"fn_name":null},{"line":129,"address":[6822259,6822370,6829299,6829410],"length":1,"stats":{"Line":18},"fn_name":null},{"line":130,"address":[6822517,6829557,6822469,6829509],"length":1,"stats":{"Line":18},"fn_name":null},{"line":131,"address":[6830727,6829817,6823687,6822777],"length":1,"stats":{"Line":7},"fn_name":null},{"line":132,"address":[6823013,6823898,6830053,6830938],"length":1,"stats":{"Line":1},"fn_name":null},{"line":133,"address":[6823784,6830824,6829935,6822895],"length":1,"stats":{"Line":0},"fn_name":null},{"line":134,"address":[6824012,6823131,6830171,6831052],"length":1,"stats":{"Line":0},"fn_name":null},{"line":135,"address":[6829699,6823543,6822659,6830583],"length":1,"stats":{"Line":0},"fn_name":null},{"line":136,"address":[6823243,6831166,6830283,6824126],"length":1,"stats":{"Line":0},"fn_name":null},{"line":137,"address":[6831394,6830483,6823443,6824354],"length":1,"stats":{"Line":1},"fn_name":null},{"line":138,"address":[6824240,6830383,6831280,6823343],"length":1,"stats":{"Line":0},"fn_name":null},{"line":139,"address":[6822571,6829611],"length":1,"stats":{"Line":0},"fn_name":null},{"line":140,"address":[6824589,6822611,6831761,6831559,6824721,6824519,6829651,6831629],"length":1,"stats":{"Line":0},"fn_name":null},{"line":143,"address":[6824891,6831931],"length":1,"stats":{"Line":9},"fn_name":null},{"line":145,"address":[6825103,6832143],"length":1,"stats":{"Line":9},"fn_name":null}],"covered":44,"coverable":51},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","response","auth_result.rs"],"content":"use crate::{IntoResponseError, Response};\nuse gotham::{hyper::StatusCode, mime::TEXT_PLAIN_UTF_8};\nuse gotham_restful_derive::ResourceError;\n#[cfg(feature = \"openapi\")]\nuse openapi_type::{OpenapiSchema, OpenapiType};\n\n/// This is an error type that always yields a _403 Forbidden_ response. This type\n/// is best used in combination with [`AuthSuccess`] or [`AuthResult`].\n#[derive(Clone, Debug)]\npub struct AuthError(String);\n\nimpl AuthError {\n\tpub fn new>(msg: T) -> Self {\n\t\tSelf(msg.into())\n\t}\n}\n\nimpl IntoResponseError for AuthError {\n\t// TODO why does this need to be serde_json::Error ?!?\n\ttype Err = serde_json::Error;\n\n\tfn into_response_error(self) -> Result {\n\t\tOk(Response::new(\n\t\t\tStatusCode::FORBIDDEN,\n\t\t\tself.0,\n\t\t\tSome(TEXT_PLAIN_UTF_8)\n\t\t))\n\t}\n\n\t#[cfg(feature = \"openapi\")]\n\tfn status_codes() -> Vec {\n\t\tvec![StatusCode::FORBIDDEN]\n\t}\n\n\t#[cfg(feature = \"openapi\")]\n\tfn schema(code: StatusCode) -> OpenapiSchema {\n\t\tassert_eq!(code, StatusCode::FORBIDDEN);\n\t\t as OpenapiType>::schema()\n\t}\n}\n\n/// This return type can be used to wrap any type implementing [IntoResponse](crate::IntoResponse)\n/// that can only be returned if the client is authenticated. Otherwise, an empty _403 Forbidden_\n/// response will be issued.\n///\n/// Use can look something like this (assuming the `auth` feature is enabled):\n///\n/// ```rust\n/// # #[macro_use] extern crate gotham_restful_derive;\n/// # #[cfg(feature = \"auth\")]\n/// # mod auth_feature_enabled {\n/// # use gotham::state::State;\n/// # use gotham_restful::*;\n/// # use serde::Deserialize;\n/// #\n/// # #[derive(Resource)]\n/// # #[resource(read_all)]\n/// # struct MyResource;\n/// #\n/// # #[derive(Clone, Deserialize)]\n/// # struct MyAuthData { exp : u64 }\n/// #\n/// #[read_all]\n/// fn read_all(auth: AuthStatus) -> AuthSuccess {\n/// \tlet auth_data = auth.ok()?;\n/// \t// do something\n/// \tOk(NoContent::default())\n/// }\n/// # }\n/// ```\npub type AuthSuccess = Result;\n\n/// This is an error type that either yields a _403 Forbidden_ response if produced\n/// from an authentication error, or delegates to another error type. This type is\n/// best used with [`AuthResult`].\n#[derive(Debug, Clone, ResourceError)]\npub enum AuthErrorOrOther {\n\tForbidden(#[from] AuthError),\n\n\t#[status(INTERNAL_SERVER_ERROR)]\n\t#[display(\"{0}\")]\n\tOther(E)\n}\n\nmod private {\n\tuse gotham::handler::HandlerError;\n\tpub trait Sealed {}\n\timpl> Sealed for E {}\n}\n\nimpl From for AuthErrorOrOther\nwhere\n\t// TODO https://github.com/msrd0/gotham_restful/issues/20\n\tF: private::Sealed + Into\n{\n\tfn from(err: F) -> Self {\n\t\tSelf::Other(err.into())\n\t}\n}\n\n/// This return type can be used to wrap any type implementing [IntoResponse](crate::IntoResponse)\n/// that can only be returned if the client is authenticated. Otherwise, an empty _403 Forbidden_\n/// response will be issued.\n///\n/// Use can look something like this (assuming the `auth` feature is enabled):\n///\n/// ```\n/// # #[macro_use] extern crate gotham_restful_derive;\n/// # #[cfg(feature = \"auth\")]\n/// # mod auth_feature_enabled {\n/// # use gotham::state::State;\n/// # use gotham_restful::*;\n/// # use serde::Deserialize;\n/// # use std::io;\n/// #\n/// # #[derive(Resource)]\n/// # #[resource(read_all)]\n/// # struct MyResource;\n/// #\n/// # #[derive(Clone, Deserialize)]\n/// # struct MyAuthData { exp : u64 }\n/// #\n/// #[read_all]\n/// fn read_all(auth: AuthStatus) -> AuthResult {\n/// \tlet auth_data = auth.ok()?;\n/// \t// do something\n/// \tOk(NoContent::default().into())\n/// }\n/// # }\n/// ```\npub type AuthResult = Result>;\n","traces":[{"line":13,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":14,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":22,"address":[7835264],"length":1,"stats":{"Line":0},"fn_name":"into_response_error"},{"line":23,"address":[8680071],"length":1,"stats":{"Line":0},"fn_name":null},{"line":25,"address":[8649169],"length":1,"stats":{"Line":0},"fn_name":null},{"line":26,"address":[6096788],"length":1,"stats":{"Line":0},"fn_name":null},{"line":31,"address":[6096912],"length":1,"stats":{"Line":1},"fn_name":"status_codes"},{"line":32,"address":[8649341,8649416],"length":1,"stats":{"Line":1},"fn_name":null},{"line":36,"address":[7644288],"length":1,"stats":{"Line":1},"fn_name":"schema"},{"line":38,"address":[6097317],"length":1,"stats":{"Line":1},"fn_name":null},{"line":96,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":97,"address":[],"length":0,"stats":{"Line":0},"fn_name":null}],"covered":4,"coverable":12},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","response","mod.rs"],"content":"use futures_util::future::{self, BoxFuture, FutureExt};\nuse gotham::{\n\thandler::HandlerError,\n\thyper::{\n\t\theader::{HeaderMap, HeaderName, HeaderValue},\n\t\tBody, StatusCode\n\t},\n\tmime::{Mime, APPLICATION_JSON, STAR_STAR}\n};\n#[cfg(feature = \"openapi\")]\nuse openapi_type::{OpenapiSchema, OpenapiType};\nuse serde::Serialize;\n#[cfg(feature = \"errorlog\")]\nuse std::fmt::Display;\nuse std::{convert::Infallible, fmt::Debug, future::Future, pin::Pin};\n\nmod auth_result;\n#[allow(unreachable_pub)]\npub use auth_result::{AuthError, AuthErrorOrOther, AuthResult, AuthSuccess};\n\nmod no_content;\n#[allow(unreachable_pub)]\npub use no_content::NoContent;\n\nmod raw;\n#[allow(unreachable_pub)]\npub use raw::Raw;\n\nmod redirect;\n#[allow(unreachable_pub)]\npub use redirect::Redirect;\n\nmod result;\n#[allow(unreachable_pub)]\npub use result::IntoResponseError;\n\nmod success;\n#[allow(unreachable_pub)]\npub use success::Success;\n\npub(crate) trait OrAllTypes {\n\tfn or_all_types(self) -> Vec;\n}\n\nimpl OrAllTypes for Option> {\n\tfn or_all_types(self) -> Vec {\n\t\tself.unwrap_or_else(|| vec![STAR_STAR])\n\t}\n}\n\n/// A response, used to create the final gotham response from.\n///\n/// This type is not meant to be used as the return type of endpoint handlers. While it can be\n/// freely used without the `openapi` feature, it is more complicated to use when you enable it,\n/// since this type does not store any schema information. You can attach schema information\n/// like so:\n///\n/// ```rust\n/// # #[cfg(feature = \"openapi\")] mod example {\n/// # use gotham::hyper::StatusCode;\n/// # use gotham_restful::*;\n/// # use openapi_type::*;\n/// fn schema(code: StatusCode) -> OpenapiSchema {\n/// \tassert_eq!(code, StatusCode::ACCEPTED);\n/// \t<()>::schema()\n/// }\n///\n/// fn status_codes() -> Vec {\n/// \tvec![StatusCode::ACCEPTED]\n/// }\n///\n/// #[create(schema = \"schema\", status_codes = \"status_codes\")]\n/// fn create(body: Raw>) {}\n/// # }\n/// ```\n#[derive(Debug)]\npub struct Response {\n\tpub(crate) status: StatusCode,\n\tpub(crate) body: Body,\n\tpub(crate) mime: Option,\n\tpub(crate) headers: HeaderMap\n}\n\nimpl Response {\n\t/// Create a new [Response] from raw data.\n\t#[must_use = \"Creating a response is pointless if you don't use it\"]\n\tpub fn new>(status: StatusCode, body: B, mime: Option) -> Self {\n\t\tSelf {\n\t\t\tstatus,\n\t\t\tbody: body.into(),\n\t\t\tmime,\n\t\t\theaders: Default::default()\n\t\t}\n\t}\n\n\t/// Create a [Response] with mime type json from already serialized data.\n\t#[must_use = \"Creating a response is pointless if you don't use it\"]\n\tpub fn json>(status: StatusCode, body: B) -> Self {\n\t\tSelf {\n\t\t\tstatus,\n\t\t\tbody: body.into(),\n\t\t\tmime: Some(APPLICATION_JSON),\n\t\t\theaders: Default::default()\n\t\t}\n\t}\n\n\t/// Create a _204 No Content_ [Response].\n\t#[must_use = \"Creating a response is pointless if you don't use it\"]\n\tpub fn no_content() -> Self {\n\t\tSelf {\n\t\t\tstatus: StatusCode::NO_CONTENT,\n\t\t\tbody: Body::empty(),\n\t\t\tmime: None,\n\t\t\theaders: Default::default()\n\t\t}\n\t}\n\n\t/// Create an empty _403 Forbidden_ [Response].\n\t#[must_use = \"Creating a response is pointless if you don't use it\"]\n\tpub fn forbidden() -> Self {\n\t\tSelf {\n\t\t\tstatus: StatusCode::FORBIDDEN,\n\t\t\tbody: Body::empty(),\n\t\t\tmime: None,\n\t\t\theaders: Default::default()\n\t\t}\n\t}\n\n\t/// Return the status code of this [Response].\n\tpub fn status(&self) -> StatusCode {\n\t\tself.status\n\t}\n\n\t/// Return the mime type of this [Response].\n\tpub fn mime(&self) -> Option<&Mime> {\n\t\tself.mime.as_ref()\n\t}\n\n\t/// Add an HTTP header to the [Response].\n\tpub fn header(&mut self, name: HeaderName, value: HeaderValue) {\n\t\tself.headers.insert(name, value);\n\t}\n\n\tpub(crate) fn with_headers(mut self, headers: HeaderMap) -> Self {\n\t\tself.headers = headers;\n\t\tself\n\t}\n\n\t#[cfg(test)]\n\tpub(crate) fn full_body(\n\t\tmut self\n\t) -> Result, ::Error> {\n\t\tuse futures_executor::block_on;\n\t\tuse gotham::hyper::body::to_bytes;\n\n\t\tlet bytes: &[u8] = &block_on(to_bytes(&mut self.body))?;\n\t\tOk(bytes.to_vec())\n\t}\n}\n\nimpl IntoResponse for Response {\n\ttype Err = Infallible;\n\n\tfn into_response(self) -> BoxFuture<'static, Result> {\n\t\tfuture::ok(self).boxed()\n\t}\n}\n\n/// This trait needs to be implemented by every type returned from an endpoint to\n/// to provide the response.\npub trait IntoResponse {\n\ttype Err: Into + Send + Sync + 'static;\n\n\t/// Turn this into a response that can be returned to the browser. This api will likely\n\t/// change in the future.\n\tfn into_response(self) -> BoxFuture<'static, Result>;\n\n\t/// Return a list of supported mime types.\n\tfn accepted_types() -> Option> {\n\t\tNone\n\t}\n}\n\n/// Additional details for [IntoResponse] to be used with an OpenAPI-aware router.\n#[cfg(feature = \"openapi\")]\npub trait ResponseSchema {\n\t/// All status codes returned by this response. Returns `[StatusCode::OK]` by default.\n\tfn status_codes() -> Vec {\n\t\tvec![StatusCode::OK]\n\t}\n\n\t/// Return the schema of the response for the given status code. The code may\n\t/// only be one that was previously returned by [Self::status_codes]. The\n\t/// implementation should panic if that is not the case.\n\tfn schema(code: StatusCode) -> OpenapiSchema;\n}\n\n#[cfg(feature = \"openapi\")]\nmod private {\n\tpub trait Sealed {}\n}\n\n/// A trait provided to convert a resource's result to json, and provide an OpenAPI schema to the\n/// router. This trait is implemented for all types that implement [IntoResponse] and\n/// [ResponseSchema].\n#[cfg(feature = \"openapi\")]\npub trait IntoResponseWithSchema: IntoResponse + ResponseSchema + private::Sealed {}\n\n#[cfg(feature = \"openapi\")]\nimpl private::Sealed for R {}\n\n#[cfg(feature = \"openapi\")]\nimpl IntoResponseWithSchema for R {}\n\n/// The default json returned on an 500 Internal Server Error.\n#[derive(Debug, Serialize)]\n#[cfg_attr(feature = \"openapi\", derive(OpenapiType))]\npub(crate) struct ResourceError {\n\t/// This is always `true` and can be used to detect an error response without looking at the\n\t/// HTTP status code.\n\terror: bool,\n\t/// The error message.\n\tmessage: String\n}\n\nimpl From for ResourceError {\n\tfn from(message: T) -> Self {\n\t\tSelf {\n\t\t\terror: true,\n\t\t\tmessage: message.to_string()\n\t\t}\n\t}\n}\n\n#[cfg(feature = \"errorlog\")]\nfn errorlog(e: E) {\n\terror!(\"The handler encountered an error: {e}\");\n}\n\n#[cfg(not(feature = \"errorlog\"))]\nfn errorlog(_e: E) {}\n\nfn handle_error(e: E) -> Pin> + Send>>\nwhere\n\tE: Debug + IntoResponseError\n{\n\tlet msg = format!(\"{e:?}\");\n\tlet res = e.into_response_error();\n\tmatch &res {\n\t\tOk(res) if res.status.is_server_error() => errorlog(msg),\n\t\tErr(err) => {\n\t\t\terrorlog(msg);\n\t\t\terrorlog(format!(\"{err:?}\"));\n\t\t},\n\t\t_ => {}\n\t};\n\tfuture::ready(res).boxed()\n}\n\nimpl IntoResponse for Pin + Send>>\nwhere\n\tRes: IntoResponse + 'static\n{\n\ttype Err = Res::Err;\n\n\tfn into_response(self) -> Pin> + Send>> {\n\t\tself.then(IntoResponse::into_response).boxed()\n\t}\n\n\tfn accepted_types() -> Option> {\n\t\tRes::accepted_types()\n\t}\n}\n\n#[cfg(feature = \"openapi\")]\nimpl ResponseSchema for Pin + Send>>\nwhere\n\tRes: ResponseSchema\n{\n\tfn status_codes() -> Vec {\n\t\tRes::status_codes()\n\t}\n\n\tfn schema(code: StatusCode) -> OpenapiSchema {\n\t\tRes::schema(code)\n\t}\n}\n\n#[cfg(test)]\nmod test {\n\tuse super::*;\n\tuse futures_executor::block_on;\n\tuse thiserror::Error;\n\n\t#[derive(Debug, Default, Deserialize, Serialize)]\n\t#[cfg_attr(feature = \"openapi\", derive(openapi_type::OpenapiType))]\n\tstruct Msg {\n\t\tmsg: String\n\t}\n\n\t#[derive(Debug, Default, Error)]\n\t#[error(\"An Error\")]\n\tstruct MsgError;\n\n\t#[test]\n\tfn result_from_future() {\n\t\tlet nc = NoContent::default();\n\t\tlet res = block_on(nc.into_response()).unwrap();\n\n\t\tlet fut_nc = async move { NoContent::default() }.boxed();\n\t\tlet fut_res = block_on(fut_nc.into_response()).unwrap();\n\n\t\tassert_eq!(res.status, fut_res.status);\n\t\tassert_eq!(res.mime, fut_res.mime);\n\t\tassert_eq!(res.full_body().unwrap(), fut_res.full_body().unwrap());\n\t}\n}\n","traces":[{"line":46,"address":[6140384],"length":1,"stats":{"Line":3},"fn_name":"or_all_types"},{"line":47,"address":[6140392],"length":1,"stats":{"Line":9},"fn_name":null},{"line":87,"address":[6060415,6060805,6060448,6061294,6060880,6060385,6060835,6060032,6061264],"length":1,"stats":{"Line":8},"fn_name":null},{"line":90,"address":[6060971,6060511,6060100],"length":1,"stats":{"Line":8},"fn_name":null},{"line":92,"address":[6060646,6060226,6061105],"length":1,"stats":{"Line":8},"fn_name":null},{"line":98,"address":[6061718,6061328,6061745],"length":1,"stats":{"Line":2},"fn_name":null},{"line":101,"address":[6061368],"length":1,"stats":{"Line":2},"fn_name":null},{"line":102,"address":[6061382],"length":1,"stats":{"Line":2},"fn_name":null},{"line":103,"address":[6061559],"length":1,"stats":{"Line":3},"fn_name":null},{"line":109,"address":[6061760,6061979,6061952],"length":1,"stats":{"Line":3},"fn_name":null},{"line":112,"address":[6061782],"length":1,"stats":{"Line":4},"fn_name":null},{"line":114,"address":[6061796],"length":1,"stats":{"Line":4},"fn_name":null},{"line":120,"address":[6062219,6062192,6062000],"length":1,"stats":{"Line":0},"fn_name":null},{"line":123,"address":[6062022],"length":1,"stats":{"Line":0},"fn_name":null},{"line":125,"address":[6062036],"length":1,"stats":{"Line":0},"fn_name":null},{"line":130,"address":[6062240],"length":1,"stats":{"Line":1},"fn_name":null},{"line":131,"address":[6062245],"length":1,"stats":{"Line":1},"fn_name":null},{"line":135,"address":[6062256],"length":1,"stats":{"Line":1},"fn_name":null},{"line":136,"address":[6062261],"length":1,"stats":{"Line":1},"fn_name":null},{"line":140,"address":[6062272],"length":1,"stats":{"Line":2},"fn_name":null},{"line":141,"address":[6062290],"length":1,"stats":{"Line":2},"fn_name":null},{"line":144,"address":[6062336,6062541],"length":1,"stats":{"Line":4},"fn_name":null},{"line":145,"address":[6062368,6062494],"length":1,"stats":{"Line":8},"fn_name":null},{"line":146,"address":[6062521],"length":1,"stats":{"Line":4},"fn_name":null},{"line":150,"address":[6062975,6062998,6062576],"length":1,"stats":{"Line":1},"fn_name":null},{"line":156,"address":[6062663,6062873,6062606],"length":1,"stats":{"Line":6},"fn_name":null},{"line":157,"address":[6062889],"length":1,"stats":{"Line":2},"fn_name":null},{"line":164,"address":[6063024],"length":1,"stats":{"Line":0},"fn_name":"into_response"},{"line":165,"address":[6063044],"length":1,"stats":{"Line":0},"fn_name":null},{"line":179,"address":[],"length":0,"stats":{"Line":7},"fn_name":null},{"line":180,"address":[],"length":0,"stats":{"Line":7},"fn_name":null},{"line":188,"address":[],"length":0,"stats":{"Line":4},"fn_name":null},{"line":189,"address":[],"length":0,"stats":{"Line":4},"fn_name":null},{"line":227,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":230,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":236,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":237,"address":[],"length":0,"stats":{"Line":3},"fn_name":null},{"line":243,"address":[6065628,6066636,6066688,6067674,6064672,6063664,6064620,6064650,6065680,6065658,6066666,6067644],"length":1,"stats":{"Line":1},"fn_name":"handle_error"},{"line":247,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":248,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":249,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":250,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":251,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":252,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":253,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":255,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":257,"address":[],"length":0,"stats":{"Line":3},"fn_name":null},{"line":266,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":267,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":270,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":271,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":280,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":281,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":284,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":285,"address":[],"length":0,"stats":{"Line":0},"fn_name":null}],"covered":40,"coverable":55},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","response","no_content.rs"],"content":"use super::{handle_error, IntoResponse};\n#[cfg(feature = \"openapi\")]\nuse crate::ResponseSchema;\nuse crate::{IntoResponseError, Response};\nuse futures_util::{future, future::FutureExt};\n#[cfg(feature = \"openapi\")]\nuse gotham::hyper::StatusCode;\nuse gotham::{\n\thyper::header::{HeaderMap, HeaderValue, IntoHeaderName},\n\tmime::Mime\n};\n#[cfg(feature = \"openapi\")]\nuse openapi_type::{OpenapiSchema, OpenapiType};\nuse std::{fmt::Debug, future::Future, pin::Pin};\n\n/// This is the return type of a resource that doesn't actually return something. It will result\n/// in a _204 No Content_ answer by default. You don't need to use this type directly if using\n/// the function attributes:\n///\n/// ```\n/// # #[macro_use] extern crate gotham_restful_derive;\n/// # mod doc_tests_are_broken {\n/// # use gotham::state::State;\n/// # use gotham_restful::*;\n/// #\n/// # #[derive(Resource)]\n/// # #[resource(read_all)]\n/// # struct MyResource;\n/// #\n/// #[read_all]\n/// fn read_all() {\n/// \t// do something\n/// }\n/// # }\n/// ```\n#[derive(Clone, Debug, Default)]\npub struct NoContent {\n\theaders: HeaderMap\n}\n\nimpl From<()> for NoContent {\n\tfn from(_: ()) -> Self {\n\t\tSelf::default()\n\t}\n}\n\nimpl NoContent {\n\t/// Set a custom HTTP header. If a header with this name was set before, its value is being updated.\n\tpub fn header(&mut self, name: K, value: HeaderValue) {\n\t\tself.headers.insert(name, value);\n\t}\n\n\t/// Allow manipulating HTTP headers.\n\tpub fn headers_mut(&mut self) -> &mut HeaderMap {\n\t\t&mut self.headers\n\t}\n}\n\nimpl IntoResponse for NoContent {\n\t// TODO this shouldn't be a serde_json::Error\n\ttype Err = serde_json::Error; // just for easier handling of `Result`\n\n\t/// This will always be a _204 No Content_ together with an empty string.\n\tfn into_response(self) -> Pin> + Send>> {\n\t\tfuture::ok(Response::no_content().with_headers(self.headers)).boxed()\n\t}\n\n\tfn accepted_types() -> Option> {\n\t\tSome(Vec::new())\n\t}\n}\n\n#[cfg(feature = \"openapi\")]\nimpl ResponseSchema for NoContent {\n\tfn status_codes() -> Vec {\n\t\tvec![StatusCode::NO_CONTENT]\n\t}\n\n\t/// Returns the schema of the `()` type.\n\tfn schema(code: StatusCode) -> OpenapiSchema {\n\t\tassert_eq!(code, StatusCode::NO_CONTENT);\n\t\t<()>::schema()\n\t}\n}\n\nimpl IntoResponse for Result\nwhere\n\tE: Debug + IntoResponseError\n{\n\ttype Err = serde_json::Error;\n\n\tfn into_response(\n\t\tself\n\t) -> Pin> + Send>> {\n\t\tmatch self {\n\t\t\tOk(nc) => nc.into_response(),\n\t\t\tErr(e) => handle_error(e)\n\t\t}\n\t}\n\n\tfn accepted_types() -> Option> {\n\t\tNoContent::accepted_types()\n\t}\n}\n\n#[cfg(feature = \"openapi\")]\nimpl ResponseSchema for Result\nwhere\n\tE: Debug + IntoResponseError\n{\n\tfn status_codes() -> Vec {\n\t\tlet mut status_codes = E::status_codes();\n\t\tstatus_codes.push(StatusCode::NO_CONTENT);\n\t\tstatus_codes\n\t}\n\n\tfn schema(code: StatusCode) -> OpenapiSchema {\n\t\tmatch code {\n\t\t\tStatusCode::NO_CONTENT => ::schema(StatusCode::NO_CONTENT),\n\t\t\tcode => E::schema(code)\n\t\t}\n\t}\n}\n\n#[cfg(test)]\nmod test {\n\tuse super::*;\n\tuse futures_executor::block_on;\n\tuse gotham::hyper::{header::ACCESS_CONTROL_ALLOW_ORIGIN, StatusCode};\n\tuse thiserror::Error;\n\n\t#[derive(Debug, Default, Error)]\n\t#[error(\"An Error\")]\n\tstruct MsgError;\n\n\t#[test]\n\tfn no_content_has_empty_response() {\n\t\tlet no_content = NoContent::default();\n\t\tlet res = block_on(no_content.into_response()).expect(\"didn't expect error response\");\n\t\tassert_eq!(res.status, StatusCode::NO_CONTENT);\n\t\tassert_eq!(res.mime, None);\n\t\tassert_eq!(res.full_body().unwrap(), &[] as &[u8]);\n\n\t\t#[cfg(feature = \"openapi\")]\n\t\tassert_eq!(NoContent::status_codes(), vec![StatusCode::NO_CONTENT]);\n\t}\n\n\t#[test]\n\tfn no_content_result() {\n\t\tlet no_content: Result = Ok(NoContent::default());\n\t\tlet res = block_on(no_content.into_response()).expect(\"didn't expect error response\");\n\t\tassert_eq!(res.status, StatusCode::NO_CONTENT);\n\t\tassert_eq!(res.mime, None);\n\t\tassert_eq!(res.full_body().unwrap(), &[] as &[u8]);\n\n\t\t#[cfg(feature = \"openapi\")]\n\t\tassert_eq!(>::status_codes(), vec![\n\t\t\tStatusCode::INTERNAL_SERVER_ERROR,\n\t\t\tStatusCode::NO_CONTENT\n\t\t]);\n\t}\n\n\t#[test]\n\tfn no_content_custom_headers() {\n\t\tlet mut no_content = NoContent::default();\n\t\tno_content.header(ACCESS_CONTROL_ALLOW_ORIGIN, HeaderValue::from_static(\"*\"));\n\t\tlet res = block_on(no_content.into_response()).expect(\"didn't expect error response\");\n\t\tlet cors = res.headers.get(ACCESS_CONTROL_ALLOW_ORIGIN);\n\t\tassert_eq!(cors.map(|value| value.to_str().unwrap()), Some(\"*\"));\n\t}\n}\n","traces":[{"line":42,"address":[6021424],"length":1,"stats":{"Line":0},"fn_name":"from"},{"line":43,"address":[6021436],"length":1,"stats":{"Line":0},"fn_name":null},{"line":49,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":50,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":54,"address":[7557312],"length":1,"stats":{"Line":0},"fn_name":null},{"line":64,"address":[7557328,7557601,7557632],"length":1,"stats":{"Line":2},"fn_name":"into_response"},{"line":65,"address":[6021532,6021609],"length":1,"stats":{"Line":6},"fn_name":null},{"line":68,"address":[6021824],"length":1,"stats":{"Line":3},"fn_name":"accepted_types"},{"line":69,"address":[6021837],"length":1,"stats":{"Line":4},"fn_name":null},{"line":75,"address":[6021888],"length":1,"stats":{"Line":2},"fn_name":"status_codes"},{"line":76,"address":[6021975,6021901],"length":1,"stats":{"Line":2},"fn_name":null},{"line":80,"address":[7557824],"length":1,"stats":{"Line":2},"fn_name":"schema"},{"line":82,"address":[6022293],"length":1,"stats":{"Line":2},"fn_name":null},{"line":92,"address":[6290576],"length":1,"stats":{"Line":1},"fn_name":"into_response"},{"line":95,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":96,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":97,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":101,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":102,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":111,"address":[6290688,6290803],"length":1,"stats":{"Line":1},"fn_name":"status_codes"},{"line":112,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":113,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":114,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":117,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":118,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":119,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":120,"address":[],"length":0,"stats":{"Line":0},"fn_name":null}],"covered":17,"coverable":27},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","response","raw.rs"],"content":"use super::{handle_error, IntoResponse, IntoResponseError};\nuse crate::{types::ResourceType, FromBody, RequestBody, Response};\n#[cfg(feature = \"openapi\")]\nuse crate::{IntoResponseWithSchema, ResponseSchema};\nuse futures_core::future::Future;\nuse futures_util::{future, future::FutureExt};\nuse gotham::{\n\thyper::{\n\t\tbody::{Body, Bytes},\n\t\tStatusCode\n\t},\n\tmime::Mime\n};\n#[cfg(feature = \"openapi\")]\nuse openapi_type::{OpenapiSchema, OpenapiType, Visitor};\nuse serde_json::error::Error as SerdeJsonError;\nuse std::{convert::Infallible, fmt::Debug, pin::Pin};\n\n/// This type can be used both as a raw request body, as well as as a raw response. However, all types\n/// of request bodies are accepted by this type. It is therefore recommended to derive your own type\n/// from [RequestBody] and only use this when you need to return a raw response. This is a usage\n/// example that simply returns its body:\n///\n/// ```rust,no_run\n/// # #[macro_use] extern crate gotham_restful_derive;\n/// # use gotham::router::builder::*;\n/// # use gotham_restful::*;\n/// #[derive(Resource)]\n/// #[resource(create)]\n/// struct ImageResource;\n///\n/// #[create]\n/// fn create(body: Raw>) -> Raw> {\n/// \tbody\n/// }\n/// # fn main() {\n/// # \tgotham::start(\"127.0.0.1:8080\", build_simple_router(|route| {\n/// # \t\troute.resource::(\"img\");\n/// # \t}));\n/// # }\n/// ```\n#[derive(Debug)]\npub struct Raw {\n\tpub raw: T,\n\tpub mime: Mime\n}\n\nimpl Raw {\n\tpub fn new(raw: T, mime: Mime) -> Self {\n\t\tSelf { raw, mime }\n\t}\n}\n\nimpl AsMut for Raw\nwhere\n\tT: AsMut\n{\n\tfn as_mut(&mut self) -> &mut U {\n\t\tself.raw.as_mut()\n\t}\n}\n\nimpl AsRef for Raw\nwhere\n\tT: AsRef\n{\n\tfn as_ref(&self) -> &U {\n\t\tself.raw.as_ref()\n\t}\n}\n\nimpl Clone for Raw {\n\tfn clone(&self) -> Self {\n\t\tSelf {\n\t\t\traw: self.raw.clone(),\n\t\t\tmime: self.mime.clone()\n\t\t}\n\t}\n}\n\nimpl From<&'a [u8]>> FromBody for Raw {\n\ttype Err = Infallible;\n\n\tfn from_body(body: Bytes, mime: Mime) -> Result {\n\t\tOk(Self::new(body.as_ref().into(), mime))\n\t}\n}\n\nimpl RequestBody for Raw where Raw: FromBody + ResourceType {}\n\n#[cfg(feature = \"openapi\")]\nimpl OpenapiType for Raw {\n\tfn visit_type(visitor: &mut V) {\n\t\tvisitor.visit_binary()\n\t}\n}\n\nimpl> IntoResponse for Raw\nwhere\n\tSelf: Send\n{\n\ttype Err = SerdeJsonError; // just for easier handling of `Result, E>`\n\n\tfn into_response(\n\t\tself\n\t) -> Pin> + Send>> {\n\t\tfuture::ok(Response::new(StatusCode::OK, self.raw, Some(self.mime))).boxed()\n\t}\n}\n\n#[cfg(feature = \"openapi\")]\nimpl> ResponseSchema for Raw\nwhere\n\tSelf: Send\n{\n\tfn schema(code: StatusCode) -> OpenapiSchema {\n\t\tassert_eq!(code, StatusCode::OK);\n\t\t::schema()\n\t}\n}\n\nimpl IntoResponse for Result, E>\nwhere\n\tRaw: IntoResponse,\n\tE: Debug + IntoResponseError as IntoResponse>::Err>\n{\n\ttype Err = E::Err;\n\n\tfn into_response(self) -> Pin> + Send>> {\n\t\tmatch self {\n\t\t\tOk(raw) => raw.into_response(),\n\t\t\tErr(e) => handle_error(e)\n\t\t}\n\t}\n}\n\n#[cfg(feature = \"openapi\")]\nimpl ResponseSchema for Result, E>\nwhere\n\tRaw: IntoResponseWithSchema,\n\tE: Debug + IntoResponseError as IntoResponse>::Err>\n{\n\tfn status_codes() -> Vec {\n\t\tlet mut status_codes = E::status_codes();\n\t\tstatus_codes.push(StatusCode::OK);\n\t\tstatus_codes\n\t}\n\n\tfn schema(code: StatusCode) -> OpenapiSchema {\n\t\tmatch code {\n\t\t\tStatusCode::OK => as ResponseSchema>::schema(StatusCode::OK),\n\t\t\tcode => E::schema(code)\n\t\t}\n\t}\n}\n\n#[cfg(test)]\nmod test {\n\tuse super::*;\n\tuse futures_executor::block_on;\n\tuse gotham::mime::TEXT_PLAIN;\n\tuse thiserror::Error;\n\n\t#[derive(Debug, Default, Error)]\n\t#[error(\"An Error\")]\n\tstruct MsgError;\n\n\t#[test]\n\tfn raw_response() {\n\t\tlet msg = \"Test\";\n\t\tlet raw = Raw::new(msg, TEXT_PLAIN);\n\t\tlet res = block_on(raw.into_response()).expect(\"didn't expect error response\");\n\t\tassert_eq!(res.status, StatusCode::OK);\n\t\tassert_eq!(res.mime, Some(TEXT_PLAIN));\n\t\tassert_eq!(res.full_body().unwrap(), msg.as_bytes());\n\n\t\t#[cfg(feature = \"openapi\")]\n\t\tassert_eq!(>::status_codes(), vec![StatusCode::OK]);\n\t}\n\n\t#[test]\n\tfn raw_result() {\n\t\tlet msg = \"Test\";\n\t\tlet raw: Result, MsgError> = Ok(Raw::new(msg, TEXT_PLAIN));\n\t\tlet res = block_on(raw.into_response()).expect(\"didn't expect error response\");\n\t\tassert_eq!(res.status, StatusCode::OK);\n\t\tassert_eq!(res.mime, Some(TEXT_PLAIN));\n\t\tassert_eq!(res.full_body().unwrap(), msg.as_bytes());\n\n\t\t#[cfg(feature = \"openapi\")]\n\t\tassert_eq!(, MsgError>>::status_codes(), vec![\n\t\t\tStatusCode::INTERNAL_SERVER_ERROR,\n\t\t\tStatusCode::OK\n\t\t]);\n\t}\n}\n","traces":[{"line":49,"address":[6462960],"length":1,"stats":{"Line":6},"fn_name":null},{"line":58,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":59,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":67,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":68,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":73,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":75,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":76,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":84,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":85,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":93,"address":[],"length":0,"stats":{"Line":4},"fn_name":null},{"line":94,"address":[],"length":0,"stats":{"Line":4},"fn_name":null},{"line":104,"address":[6022416],"length":1,"stats":{"Line":5},"fn_name":"into_response<&str>"},{"line":107,"address":[],"length":0,"stats":{"Line":5},"fn_name":null},{"line":116,"address":[],"length":0,"stats":{"Line":3},"fn_name":null},{"line":118,"address":[6022965],"length":1,"stats":{"Line":3},"fn_name":null},{"line":129,"address":[6290832],"length":1,"stats":{"Line":1},"fn_name":"into_response<&str, gotham_restful::response::raw::test::MsgError>"},{"line":130,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":131,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":132,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":143,"address":[6290944,6291059],"length":1,"stats":{"Line":1},"fn_name":"status_codes"},{"line":144,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":145,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":146,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":149,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":150,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":151,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":152,"address":[],"length":0,"stats":{"Line":0},"fn_name":null}],"covered":16,"coverable":28},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","response","redirect.rs"],"content":"use super::{handle_error, IntoResponse};\nuse crate::{IntoResponseError, Response};\n#[cfg(feature = \"openapi\")]\nuse crate::{NoContent, ResponseSchema};\nuse futures_util::future::{BoxFuture, FutureExt, TryFutureExt};\nuse gotham::hyper::{\n\theader::{InvalidHeaderValue, LOCATION},\n\tBody, StatusCode\n};\n#[cfg(feature = \"openapi\")]\nuse openapi_type::OpenapiSchema;\nuse std::{error::Error as StdError, fmt::Debug};\nuse thiserror::Error;\n\n/// This is the return type of a resource that only returns a redirect. It will result\n/// in a _303 See Other_ answer, meaning the redirect will always result in a GET request\n/// on the target.\n///\n/// ```\n/// # #[macro_use] extern crate gotham_restful_derive;\n/// # mod doc_tests_are_broken {\n/// # use gotham::state::State;\n/// # use gotham_restful::*;\n/// #\n/// # #[derive(Resource)]\n/// # #[resource(read_all)]\n/// # struct MyResource;\n/// #\n/// #[read_all]\n/// fn read_all() -> Redirect {\n/// \tRedirect {\n/// \t\tto: \"http://localhost:8080/cool/new/location\".to_owned()\n/// \t}\n/// }\n/// # }\n/// ```\n#[derive(Clone, Debug, Default)]\npub struct Redirect {\n\tpub to: String\n}\n\nimpl IntoResponse for Redirect {\n\ttype Err = InvalidHeaderValue;\n\n\tfn into_response(self) -> BoxFuture<'static, Result> {\n\t\tasync move {\n\t\t\tlet mut res = Response::new(StatusCode::SEE_OTHER, Body::empty(), None);\n\t\t\tres.header(LOCATION, self.to.parse()?);\n\t\t\tOk(res)\n\t\t}\n\t\t.boxed()\n\t}\n}\n\n#[cfg(feature = \"openapi\")]\nimpl ResponseSchema for Redirect {\n\tfn status_codes() -> Vec {\n\t\tvec![StatusCode::SEE_OTHER]\n\t}\n\n\tfn schema(code: StatusCode) -> OpenapiSchema {\n\t\tassert_eq!(code, StatusCode::SEE_OTHER);\n\t\t::schema(StatusCode::NO_CONTENT)\n\t}\n}\n\n// private type due to parent mod\n#[derive(Debug, Error)]\npub enum RedirectError {\n\t#[error(\"{0}\")]\n\tInvalidLocation(#[from] InvalidHeaderValue),\n\t#[error(\"{0}\")]\n\tOther(#[source] E)\n}\n\n#[allow(ambiguous_associated_items)] // an enum variant is not a type. never.\nimpl IntoResponse for Result\nwhere\n\tE: Debug + IntoResponseError,\n\t::Err: StdError + Sync\n{\n\ttype Err = RedirectError<::Err>;\n\n\tfn into_response(self) -> BoxFuture<'static, Result> {\n\t\tmatch self {\n\t\t\tOk(nc) => nc.into_response().map_err(Into::into).boxed(),\n\t\t\tErr(e) => handle_error(e).map_err(RedirectError::Other).boxed()\n\t\t}\n\t}\n}\n\n#[cfg(feature = \"openapi\")]\nimpl ResponseSchema for Result\nwhere\n\tE: Debug + IntoResponseError,\n\t::Err: StdError + Sync\n{\n\tfn status_codes() -> Vec {\n\t\tlet mut status_codes = E::status_codes();\n\t\tstatus_codes.push(StatusCode::SEE_OTHER);\n\t\tstatus_codes\n\t}\n\n\tfn schema(code: StatusCode) -> OpenapiSchema {\n\t\tmatch code {\n\t\t\tStatusCode::SEE_OTHER => ::schema(StatusCode::SEE_OTHER),\n\t\t\tcode => E::schema(code)\n\t\t}\n\t}\n}\n\n#[cfg(test)]\nmod test {\n\tuse super::*;\n\tuse futures_executor::block_on;\n\tuse gotham::hyper::StatusCode;\n\tuse thiserror::Error;\n\n\t#[derive(Debug, Default, Error)]\n\t#[error(\"An Error\")]\n\tstruct MsgError;\n\n\t#[test]\n\tfn redirect_response() {\n\t\tlet redir = Redirect {\n\t\t\tto: \"http://localhost/foo\".to_owned()\n\t\t};\n\t\tlet res = block_on(redir.into_response()).expect(\"didn't expect error response\");\n\t\tassert_eq!(res.status, StatusCode::SEE_OTHER);\n\t\tassert_eq!(res.mime, None);\n\t\tassert_eq!(\n\t\t\tres.headers.get(LOCATION).map(|hdr| hdr.to_str().unwrap()),\n\t\t\tSome(\"http://localhost/foo\")\n\t\t);\n\t\tassert_eq!(res.full_body().unwrap(), &[] as &[u8]);\n\n\t\t#[cfg(feature = \"openapi\")]\n\t\tassert_eq!(Redirect::status_codes(), vec![StatusCode::SEE_OTHER]);\n\t}\n\n\t#[test]\n\tfn redirect_result() {\n\t\tlet redir: Result = Ok(Redirect {\n\t\t\tto: \"http://localhost/foo\".to_owned()\n\t\t});\n\t\tlet res = block_on(redir.into_response()).expect(\"didn't expect error response\");\n\t\tassert_eq!(res.status, StatusCode::SEE_OTHER);\n\t\tassert_eq!(res.mime, None);\n\t\tassert_eq!(\n\t\t\tres.headers.get(LOCATION).map(|hdr| hdr.to_str().unwrap()),\n\t\t\tSome(\"http://localhost/foo\")\n\t\t);\n\t\tassert_eq!(res.full_body().unwrap(), &[] as &[u8]);\n\n\t\t#[cfg(feature = \"openapi\")]\n\t\tassert_eq!(>::status_codes(), vec![\n\t\t\tStatusCode::INTERNAL_SERVER_ERROR,\n\t\t\tStatusCode::SEE_OTHER\n\t\t]);\n\t}\n}\n","traces":[{"line":45,"address":[7621520],"length":1,"stats":{"Line":1},"fn_name":"into_response"},{"line":46,"address":[8658411,8657566,8657492,8657536,8658167,8658371,8657623],"length":1,"stats":{"Line":3},"fn_name":"{async_block#0}"},{"line":47,"address":[6320582,6320496],"length":1,"stats":{"Line":4},"fn_name":null},{"line":48,"address":[6321138,6321273,6321228,6320627,6320494],"length":1,"stats":{"Line":2},"fn_name":null},{"line":49,"address":[8627309],"length":1,"stats":{"Line":2},"fn_name":null},{"line":57,"address":[7622512],"length":1,"stats":{"Line":1},"fn_name":"status_codes"},{"line":58,"address":[8627752,8627677],"length":1,"stats":{"Line":1},"fn_name":null},{"line":61,"address":[6321456],"length":1,"stats":{"Line":0},"fn_name":"schema"},{"line":63,"address":[8627922],"length":1,"stats":{"Line":0},"fn_name":null},{"line":84,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":85,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":86,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":87,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":98,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":99,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":100,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":101,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":104,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":105,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":106,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":107,"address":[],"length":0,"stats":{"Line":0},"fn_name":null}],"covered":14,"coverable":21},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","response","result.rs"],"content":"use super::{handle_error, IntoResponse, ResourceError};\n#[cfg(feature = \"openapi\")]\nuse crate::ResponseSchema;\nuse crate::{Response, ResponseBody, Success};\nuse futures_core::future::Future;\nuse gotham::{\n\tanyhow::Error,\n\thyper::StatusCode,\n\tmime::{Mime, APPLICATION_JSON}\n};\n#[cfg(feature = \"openapi\")]\nuse openapi_type::{OpenapiSchema, OpenapiType};\nuse std::{fmt::Debug, pin::Pin};\n\npub trait IntoResponseError {\n\ttype Err: Debug + Send + 'static;\n\n\tfn into_response_error(self) -> Result;\n\n\t#[cfg(feature = \"openapi\")]\n\tfn status_codes() -> Vec;\n\n\t#[cfg(feature = \"openapi\")]\n\tfn schema(code: StatusCode) -> OpenapiSchema;\n}\n\nimpl IntoResponseError for E\nwhere\n\tE: Into\n{\n\ttype Err = serde_json::Error;\n\n\tfn into_response_error(self) -> Result {\n\t\tlet err: Error = self.into();\n\t\tlet err: ResourceError = err.into();\n\t\tOk(Response::json(\n\t\t\tStatusCode::INTERNAL_SERVER_ERROR,\n\t\t\tserde_json::to_string(&err)?\n\t\t))\n\t}\n\n\t#[cfg(feature = \"openapi\")]\n\tfn status_codes() -> Vec {\n\t\tvec![StatusCode::INTERNAL_SERVER_ERROR]\n\t}\n\n\t#[cfg(feature = \"openapi\")]\n\tfn schema(code: StatusCode) -> OpenapiSchema {\n\t\tassert_eq!(code, StatusCode::INTERNAL_SERVER_ERROR);\n\t\tResourceError::schema()\n\t}\n}\n\nimpl IntoResponse for Result\nwhere\n\tR: ResponseBody,\n\tE: Debug + IntoResponseError\n{\n\ttype Err = E::Err;\n\n\tfn into_response(self) -> Pin> + Send>> {\n\t\tmatch self {\n\t\t\tOk(r) => Success::from(r).into_response(),\n\t\t\tErr(e) => handle_error(e)\n\t\t}\n\t}\n\n\tfn accepted_types() -> Option> {\n\t\tSome(vec![APPLICATION_JSON])\n\t}\n}\n\n#[cfg(feature = \"openapi\")]\nimpl ResponseSchema for Result\nwhere\n\tR: ResponseBody,\n\tE: Debug + IntoResponseError\n{\n\tfn status_codes() -> Vec {\n\t\tlet mut status_codes = E::status_codes();\n\t\tstatus_codes.push(StatusCode::OK);\n\t\tstatus_codes\n\t}\n\n\tfn schema(code: StatusCode) -> OpenapiSchema {\n\t\tmatch code {\n\t\t\tStatusCode::OK => R::schema(),\n\t\t\tcode => E::schema(code)\n\t\t}\n\t}\n}\n\n#[cfg(test)]\nmod test {\n\tuse super::*;\n\tuse crate::response::OrAllTypes;\n\tuse futures_executor::block_on;\n\tuse thiserror::Error;\n\n\t#[derive(Debug, Default, Deserialize, Serialize)]\n\t#[cfg_attr(feature = \"openapi\", derive(openapi_type::OpenapiType))]\n\tstruct Msg {\n\t\tmsg: String\n\t}\n\n\t#[derive(Debug, Default, Error)]\n\t#[error(\"An Error\")]\n\tstruct MsgError;\n\n\t#[test]\n\tfn result_ok() {\n\t\tlet ok: Result = Ok(Msg::default());\n\t\tlet res = block_on(ok.into_response()).expect(\"didn't expect error response\");\n\t\tassert_eq!(res.status, StatusCode::OK);\n\t\tassert_eq!(res.mime, Some(APPLICATION_JSON));\n\t\tassert_eq!(res.full_body().unwrap(), br#\"{\"msg\":\"\"}\"#);\n\t}\n\n\t#[test]\n\tfn result_err() {\n\t\tlet err: Result = Err(MsgError);\n\t\tlet res = block_on(err.into_response()).expect(\"didn't expect error response\");\n\t\tassert_eq!(res.status, StatusCode::INTERNAL_SERVER_ERROR);\n\t\tassert_eq!(res.mime, Some(APPLICATION_JSON));\n\t\tassert_eq!(\n\t\t\tres.full_body().unwrap(),\n\t\t\tformat!(r#\"{{\"error\":true,\"message\":\"{}\"}}\"#, MsgError).as_bytes()\n\t\t);\n\t}\n\n\t#[test]\n\tfn success_accepts_json() {\n\t\tassert!(\n\t\t\t>::accepted_types()\n\t\t\t\t.or_all_types()\n\t\t\t\t.contains(&APPLICATION_JSON)\n\t\t)\n\t}\n}\n","traces":[{"line":33,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":34,"address":[6321792],"length":1,"stats":{"Line":2},"fn_name":null},{"line":35,"address":[6321818],"length":1,"stats":{"Line":2},"fn_name":null},{"line":36,"address":[5921857,5921778],"length":1,"stats":{"Line":4},"fn_name":null},{"line":37,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":38,"address":[],"length":0,"stats":{"Line":4},"fn_name":null},{"line":43,"address":[6023360],"length":1,"stats":{"Line":3},"fn_name":"status_codes"},{"line":44,"address":[6023373,6023447],"length":1,"stats":{"Line":3},"fn_name":null},{"line":48,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":50,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":61,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":62,"address":[],"length":0,"stats":{"Line":3},"fn_name":null},{"line":63,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":64,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":68,"address":[],"length":0,"stats":{"Line":3},"fn_name":null},{"line":69,"address":[],"length":0,"stats":{"Line":3},"fn_name":null},{"line":79,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":80,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":81,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":82,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":85,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":86,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":87,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":88,"address":[],"length":0,"stats":{"Line":2},"fn_name":null}],"covered":21,"coverable":24},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","response","success.rs"],"content":"use super::IntoResponse;\n#[cfg(feature = \"openapi\")]\nuse crate::ResponseSchema;\nuse crate::{Response, ResponseBody};\nuse futures_util::future::{self, FutureExt};\nuse gotham::{\n\thyper::{\n\t\theader::{HeaderMap, HeaderValue, IntoHeaderName},\n\t\tStatusCode\n\t},\n\tmime::{Mime, APPLICATION_JSON}\n};\n#[cfg(feature = \"openapi\")]\nuse openapi_type::OpenapiSchema;\nuse std::{fmt::Debug, future::Future, pin::Pin};\n\n/// This can be returned from a resource when there is no cause of an error.\n///\n/// Usage example:\n///\n/// ```\n/// # #[macro_use] extern crate gotham_restful_derive;\n/// # mod doc_tests_are_broken {\n/// # use gotham::state::State;\n/// # use gotham_restful::*;\n/// # use serde::{Deserialize, Serialize};\n/// #\n/// # #[derive(Resource)]\n/// # #[resource(read_all)]\n/// # struct MyResource;\n/// #\n/// #[derive(Deserialize, Serialize)]\n/// # #[cfg_attr(feature = \"openapi\", derive(openapi_type::OpenapiType))]\n/// struct MyResponse {\n/// \tmessage: &'static str\n/// }\n///\n/// #[read_all]\n/// fn read_all() -> Success {\n/// \tlet res = MyResponse {\n/// \t\tmessage: \"I'm always happy\"\n/// \t};\n/// \tres.into()\n/// }\n/// # }\n/// ```\n#[derive(Clone, Debug, Default)]\npub struct Success {\n\tvalue: T,\n\theaders: HeaderMap\n}\n\nimpl From for Success {\n\tfn from(t: T) -> Self {\n\t\tSelf {\n\t\t\tvalue: t,\n\t\t\theaders: HeaderMap::new()\n\t\t}\n\t}\n}\n\nimpl Success {\n\t/// Set a custom HTTP header. If a header with this name was set before, its value is being updated.\n\tpub fn header(&mut self, name: K, value: HeaderValue) {\n\t\tself.headers.insert(name, value);\n\t}\n\n\t/// Allow manipulating HTTP headers.\n\tpub fn headers_mut(&mut self) -> &mut HeaderMap {\n\t\t&mut self.headers\n\t}\n}\n\nimpl IntoResponse for Success {\n\ttype Err = serde_json::Error;\n\n\tfn into_response(self) -> Pin> + Send>> {\n\t\tlet res = serde_json::to_string(&self.value)\n\t\t\t.map(|body| Response::json(StatusCode::OK, body).with_headers(self.headers));\n\t\tfuture::ready(res).boxed()\n\t}\n\n\tfn accepted_types() -> Option> {\n\t\tSome(vec![APPLICATION_JSON])\n\t}\n}\n\n#[cfg(feature = \"openapi\")]\nimpl ResponseSchema for Success {\n\tfn schema(code: StatusCode) -> OpenapiSchema {\n\t\tassert_eq!(code, StatusCode::OK);\n\t\tT::schema()\n\t}\n}\n\n#[cfg(test)]\nmod test {\n\tuse super::*;\n\tuse crate::response::OrAllTypes;\n\tuse futures_executor::block_on;\n\tuse gotham::hyper::header::ACCESS_CONTROL_ALLOW_ORIGIN;\n\n\t#[derive(Debug, Default, Serialize)]\n\t#[cfg_attr(feature = \"openapi\", derive(openapi_type::OpenapiType))]\n\tstruct Msg {\n\t\tmsg: String\n\t}\n\n\t#[test]\n\tfn success_always_successfull() {\n\t\tlet success: Success = Msg::default().into();\n\t\tlet res = block_on(success.into_response()).expect(\"didn't expect error response\");\n\t\tassert_eq!(res.status, StatusCode::OK);\n\t\tassert_eq!(res.mime, Some(APPLICATION_JSON));\n\t\tassert_eq!(res.full_body().unwrap(), br#\"{\"msg\":\"\"}\"#);\n\t\t#[cfg(feature = \"openapi\")]\n\t\tassert_eq!(>::status_codes(), vec![StatusCode::OK]);\n\t}\n\n\t#[test]\n\tfn success_custom_headers() {\n\t\tlet mut success: Success = Msg::default().into();\n\t\tsuccess.header(ACCESS_CONTROL_ALLOW_ORIGIN, HeaderValue::from_static(\"*\"));\n\t\tlet res = block_on(success.into_response()).expect(\"didn't expect error response\");\n\t\tlet cors = res.headers.get(ACCESS_CONTROL_ALLOW_ORIGIN);\n\t\tassert_eq!(cors.map(|value| value.to_str().unwrap()), Some(\"*\"));\n\t}\n\n\t#[test]\n\tfn success_accepts_json() {\n\t\tassert!(\n\t\t\t>::accepted_types()\n\t\t\t\t.or_all_types()\n\t\t\t\t.contains(&APPLICATION_JSON)\n\t\t)\n\t}\n}\n","traces":[{"line":54,"address":[6549680,6549728,6549504,6549646],"length":1,"stats":{"Line":3},"fn_name":"from"},{"line":57,"address":[],"length":0,"stats":{"Line":3},"fn_name":null},{"line":64,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":65,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":69,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":70,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":77,"address":[6552254,6552304,6552285,6551984,6552588,6552609],"length":1,"stats":{"Line":2},"fn_name":"into_response"},{"line":78,"address":[],"length":0,"stats":{"Line":6},"fn_name":null},{"line":79,"address":[],"length":0,"stats":{"Line":9},"fn_name":null},{"line":80,"address":[],"length":0,"stats":{"Line":5},"fn_name":null},{"line":83,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":84,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":90,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":92,"address":[],"length":0,"stats":{"Line":0},"fn_name":null}],"covered":10,"coverable":14},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","routing.rs"],"content":"#[cfg(feature = \"openapi\")]\nuse crate::openapi::{\n\tbuilder::{OpenapiBuilder, OpenapiInfo},\n\trouter::OpenapiRouter\n};\nuse crate::{response::ResourceError, Endpoint, FromBody, IntoResponse, Resource, Response};\n#[cfg(feature = \"cors\")]\nuse gotham::router::route::matcher::AccessControlRequestMethodMatcher;\nuse gotham::{\n\thandler::HandlerError,\n\thelpers::http::response::{create_empty_response, create_response},\n\thyper::{body::to_bytes, header::CONTENT_TYPE, Body, HeaderMap, Method, StatusCode},\n\tmime::{Mime, APPLICATION_JSON},\n\tpipeline::PipelineHandleChain,\n\tprelude::*,\n\trouter::{\n\t\tbuilder::{RouterBuilder, ScopeBuilder},\n\t\troute::matcher::{AcceptHeaderRouteMatcher, ContentTypeHeaderRouteMatcher, RouteMatcher},\n\t\tRouteNonMatch\n\t},\n\tstate::{FromState, State}\n};\n#[cfg(feature = \"openapi\")]\nuse openapi_type::OpenapiType;\nuse std::{any::TypeId, panic::RefUnwindSafe};\n\n/// Allow us to extract an id from a path.\n#[derive(Clone, Copy, Debug, Deserialize, StateData, StaticResponseExtender)]\n#[cfg_attr(feature = \"openapi\", derive(OpenapiType))]\npub struct PathExtractor {\n\tpub id: ID\n}\n\n/// This trait adds the `with_openapi` method to gotham's routing. It turns the default\n/// router into one that will only allow RESTful resources, but record them and generate\n/// an OpenAPI specification on request.\n#[cfg(feature = \"openapi\")]\npub trait WithOpenapi {\n\tfn with_openapi(&mut self, info: OpenapiInfo, block: F)\n\twhere\n\t\tF: FnOnce(OpenapiRouter<'_, D>);\n}\n\n/// This trait adds the `resource` method to gotham's routing. It allows you to register\n/// any RESTful [Resource] with a path.\n#[_private_openapi_trait(DrawResourcesWithSchema)]\npub trait DrawResources {\n\t#[openapi_bound(R: crate::ResourceWithSchema)]\n\t#[non_openapi_bound(R: crate::Resource)]\n\tfn resource(&mut self, path: &str);\n}\n\n/// This trait allows to draw routes within an resource. Use this only inside the\n/// [Resource::setup] method.\n#[_private_openapi_trait(DrawResourceRoutesWithSchema)]\npub trait DrawResourceRoutes {\n\t#[openapi_bound(E: crate::EndpointWithSchema)]\n\t#[non_openapi_bound(E: crate::Endpoint)]\n\tfn endpoint(&mut self);\n}\n\nfn response_from(res: Response, state: &State) -> gotham::hyper::Response {\n\tlet mut r = create_empty_response(state, res.status);\n\tlet headers = r.headers_mut();\n\tif let Some(mime) = res.mime {\n\t\theaders.insert(CONTENT_TYPE, mime.as_ref().parse().unwrap());\n\t}\n\tlet mut last_name = None;\n\tfor (name, value) in res.headers {\n\t\tif name.is_some() {\n\t\t\tlast_name = name;\n\t\t}\n\t\t// this unwrap is safe: the first item will always be Some\n\t\tlet name = last_name.clone().unwrap();\n\t\theaders.insert(name, value);\n\t}\n\n\tlet method = Method::borrow_from(state);\n\tif method != Method::HEAD {\n\t\t*r.body_mut() = res.body;\n\t}\n\n\t#[cfg(feature = \"cors\")]\n\tcrate::cors::handle_cors(state, &mut r);\n\n\tr\n}\n\nasync fn endpoint_handler(\n\tstate: &mut State\n) -> Result, HandlerError>\nwhere\n\tE: Endpoint,\n\t::Err: Into\n{\n\ttrace!(\"entering endpoint_handler\");\n\tlet placeholders = E::Placeholders::take_from(state);\n\t// workaround for E::Placeholders and E::Param being the same type\n\t// when fixed remove `Clone` requirement on endpoint\n\tif TypeId::of::() == TypeId::of::() {\n\t\tstate.put(placeholders.clone());\n\t}\n\tlet params = E::Params::take_from(state);\n\n\tlet body = match E::needs_body() {\n\t\ttrue => {\n\t\t\tlet body = to_bytes(Body::take_from(state)).await?;\n\n\t\t\tlet content_type: Mime = match HeaderMap::borrow_from(state).get(CONTENT_TYPE) {\n\t\t\t\tSome(content_type) => content_type.to_str().unwrap().parse().unwrap(),\n\t\t\t\tNone => {\n\t\t\t\t\tdebug!(\"Missing Content-Type: Returning 415 Response\");\n\t\t\t\t\tlet res = create_empty_response(state, StatusCode::UNSUPPORTED_MEDIA_TYPE);\n\t\t\t\t\treturn Ok(res);\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tmatch E::Body::from_body(body, content_type) {\n\t\t\t\tOk(body) => Some(body),\n\t\t\t\tErr(e) => {\n\t\t\t\t\tdebug!(\"Invalid Body: Returning 400 Response\");\n\t\t\t\t\tlet error: ResourceError = e.into();\n\t\t\t\t\tlet json = serde_json::to_string(&error)?;\n\t\t\t\t\tlet res =\n\t\t\t\t\t\tcreate_response(state, StatusCode::BAD_REQUEST, APPLICATION_JSON, json);\n\t\t\t\t\treturn Ok(res);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tfalse => None\n\t};\n\n\tlet out = E::handle(state, placeholders, params, body).await;\n\tlet res = out.into_response().await.map_err(Into::into)?;\n\tdebug!(\"Returning response {res:?}\");\n\tOk(response_from(res, state))\n}\n\n#[derive(Clone)]\nstruct MaybeMatchAcceptHeader {\n\tmatcher: Option\n}\n\nimpl RouteMatcher for MaybeMatchAcceptHeader {\n\tfn is_match(&self, state: &State) -> Result<(), RouteNonMatch> {\n\t\tmatch &self.matcher {\n\t\t\tSome(matcher) => matcher.is_match(state),\n\t\t\tNone => Ok(())\n\t\t}\n\t}\n}\n\nimpl MaybeMatchAcceptHeader {\n\tfn new(types: Option>) -> Self {\n\t\tlet types = match types {\n\t\t\tSome(types) if types.is_empty() => None,\n\t\t\ttypes => types\n\t\t};\n\t\tSelf {\n\t\t\tmatcher: types.map(AcceptHeaderRouteMatcher::new)\n\t\t}\n\t}\n}\n\nimpl From>> for MaybeMatchAcceptHeader {\n\tfn from(types: Option>) -> Self {\n\t\tSelf::new(types)\n\t}\n}\n\n#[derive(Clone)]\nstruct MaybeMatchContentTypeHeader {\n\tmatcher: Option\n}\n\nimpl RouteMatcher for MaybeMatchContentTypeHeader {\n\tfn is_match(&self, state: &State) -> Result<(), RouteNonMatch> {\n\t\tmatch &self.matcher {\n\t\t\tSome(matcher) => matcher.is_match(state),\n\t\t\tNone => Ok(())\n\t\t}\n\t}\n}\n\nimpl MaybeMatchContentTypeHeader {\n\tfn new(types: Option>) -> Self {\n\t\tSelf {\n\t\t\tmatcher: types.map(|types| ContentTypeHeaderRouteMatcher::new(types).allow_no_type())\n\t\t}\n\t}\n}\n\nimpl From>> for MaybeMatchContentTypeHeader {\n\tfn from(types: Option>) -> Self {\n\t\tSelf::new(types)\n\t}\n}\n\nmacro_rules! implDrawResourceRoutes {\n\t($implType:ident) => {\n\t\t#[cfg(feature = \"openapi\")]\n\t\timpl<'a, C, P> WithOpenapi for $implType<'a, C, P>\n\t\twhere\n\t\t\tC: PipelineHandleChain

+ Copy + Send + Sync + 'static,\n\t\t\tP: RefUnwindSafe + Send + Sync + 'static\n\t\t{\n\t\t\tfn with_openapi(&mut self, info: OpenapiInfo, block: F)\n\t\t\twhere\n\t\t\t\tF: FnOnce(OpenapiRouter<'_, $implType<'a, C, P>>)\n\t\t\t{\n\t\t\t\tlet router = OpenapiRouter {\n\t\t\t\t\trouter: self,\n\t\t\t\t\tscope: None,\n\t\t\t\t\topenapi_builder: &mut OpenapiBuilder::new(info)\n\t\t\t\t};\n\t\t\t\tblock(router);\n\t\t\t}\n\t\t}\n\n\t\timpl<'a, C, P> DrawResources for $implType<'a, C, P>\n\t\twhere\n\t\t\tC: PipelineHandleChain

+ Copy + Send + Sync + 'static,\n\t\t\tP: RefUnwindSafe + Send + Sync + 'static\n\t\t{\n\t\t\tfn resource(&mut self, mut path: &str) {\n\t\t\t\tif path.starts_with('/') {\n\t\t\t\t\tpath = &path[1..];\n\t\t\t\t}\n\t\t\t\tR::setup((self, path));\n\t\t\t}\n\t\t}\n\n\t\timpl<'a, C, P> DrawResourceRoutes for (&mut $implType<'a, C, P>, &str)\n\t\twhere\n\t\t\tC: PipelineHandleChain

+ Copy + Send + Sync + 'static,\n\t\t\tP: RefUnwindSafe + Send + Sync + 'static\n\t\t{\n\t\t\tfn endpoint(&mut self) {\n\t\t\t\tlet uri = format!(\"{}/{}\", self.1, E::uri());\n\t\t\t\tdebug!(\"Registering endpoint for {uri}\");\n\t\t\t\tself.0.associate(&uri, |assoc| {\n\t\t\t\t\tassoc\n\t\t\t\t\t\t.request(vec![E::http_method()])\n\t\t\t\t\t\t.add_route_matcher(MaybeMatchAcceptHeader::new(E::Output::accepted_types()))\n\t\t\t\t\t\t.with_path_extractor::()\n\t\t\t\t\t\t.with_query_string_extractor::()\n\t\t\t\t\t\t.to_async_borrowing(endpoint_handler::);\n\n\t\t\t\t\t#[cfg(feature = \"cors\")]\n\t\t\t\t\tif E::http_method() != Method::GET {\n\t\t\t\t\t\tassoc\n\t\t\t\t\t\t\t.options()\n\t\t\t\t\t\t\t.add_route_matcher(AccessControlRequestMethodMatcher::new(\n\t\t\t\t\t\t\t\tE::http_method()\n\t\t\t\t\t\t\t))\n\t\t\t\t\t\t\t.to(crate::cors::cors_preflight_handler);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t};\n}\n\nimplDrawResourceRoutes!(RouterBuilder);\nimplDrawResourceRoutes!(ScopeBuilder);\n","traces":[{"line":62,"address":[6369520,6370381,6368656],"length":1,"stats":{"Line":5},"fn_name":"response_from"},{"line":63,"address":[6368850,6368699],"length":1,"stats":{"Line":10},"fn_name":null},{"line":64,"address":[6368927,6368858],"length":1,"stats":{"Line":10},"fn_name":null},{"line":65,"address":[6368935],"length":1,"stats":{"Line":5},"fn_name":null},{"line":66,"address":[6369049,6369501,6369256],"length":1,"stats":{"Line":4},"fn_name":null},{"line":68,"address":[6369120],"length":1,"stats":{"Line":5},"fn_name":null},{"line":69,"address":[6369575,6369132,6370845],"length":1,"stats":{"Line":10},"fn_name":null},{"line":70,"address":[6369825,6370483,6370669],"length":1,"stats":{"Line":0},"fn_name":null},{"line":71,"address":[6370515],"length":1,"stats":{"Line":0},"fn_name":null},{"line":74,"address":[6370505,6370674],"length":1,"stats":{"Line":0},"fn_name":null},{"line":75,"address":[6370709],"length":1,"stats":{"Line":0},"fn_name":null},{"line":78,"address":[6369844],"length":1,"stats":{"Line":5},"fn_name":null},{"line":79,"address":[6370161,6369873],"length":1,"stats":{"Line":10},"fn_name":null},{"line":80,"address":[6369938,6370416],"length":1,"stats":{"Line":5},"fn_name":null},{"line":84,"address":[6369923],"length":1,"stats":{"Line":5},"fn_name":null},{"line":86,"address":[6370171],"length":1,"stats":{"Line":5},"fn_name":null},{"line":89,"address":[6332240],"length":1,"stats":{"Line":21},"fn_name":"endpoint_handler"},{"line":96,"address":[],"length":0,"stats":{"Line":63},"fn_name":null},{"line":97,"address":[],"length":0,"stats":{"Line":42},"fn_name":null},{"line":100,"address":[],"length":0,"stats":{"Line":42},"fn_name":null},{"line":101,"address":[],"length":0,"stats":{"Line":13},"fn_name":null},{"line":103,"address":[],"length":0,"stats":{"Line":42},"fn_name":null},{"line":105,"address":[],"length":0,"stats":{"Line":42},"fn_name":null},{"line":106,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":107,"address":[],"length":0,"stats":{"Line":16},"fn_name":null},{"line":109,"address":[],"length":0,"stats":{"Line":16},"fn_name":null},{"line":110,"address":[],"length":0,"stats":{"Line":16},"fn_name":null},{"line":111,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":112,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":113,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":114,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":118,"address":[],"length":0,"stats":{"Line":8},"fn_name":null},{"line":119,"address":[],"length":0,"stats":{"Line":8},"fn_name":null},{"line":120,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":121,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":122,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":123,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":124,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":125,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":126,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":130,"address":[],"length":0,"stats":{"Line":13},"fn_name":null},{"line":133,"address":[],"length":0,"stats":{"Line":43},"fn_name":null},{"line":134,"address":[],"length":0,"stats":{"Line":42},"fn_name":null},{"line":135,"address":[],"length":0,"stats":{"Line":63},"fn_name":null},{"line":136,"address":[],"length":0,"stats":{"Line":42},"fn_name":null},{"line":145,"address":[6371072],"length":1,"stats":{"Line":7},"fn_name":"is_match"},{"line":146,"address":[6371105],"length":1,"stats":{"Line":5},"fn_name":null},{"line":147,"address":[6371154],"length":1,"stats":{"Line":0},"fn_name":null},{"line":148,"address":[6371134],"length":1,"stats":{"Line":7},"fn_name":null},{"line":154,"address":[6371184,6371561,6371631],"length":1,"stats":{"Line":7},"fn_name":null},{"line":155,"address":[6371206],"length":1,"stats":{"Line":7},"fn_name":null},{"line":156,"address":[6371267,6371410],"length":1,"stats":{"Line":5},"fn_name":null},{"line":157,"address":[6371291],"length":1,"stats":{"Line":5},"fn_name":null},{"line":160,"address":[6371474],"length":1,"stats":{"Line":7},"fn_name":null},{"line":166,"address":[6371648],"length":1,"stats":{"Line":0},"fn_name":"from"},{"line":167,"address":[6371656],"length":1,"stats":{"Line":0},"fn_name":null},{"line":177,"address":[6371680],"length":1,"stats":{"Line":0},"fn_name":"is_match"},{"line":178,"address":[6371713],"length":1,"stats":{"Line":0},"fn_name":null},{"line":179,"address":[6371759],"length":1,"stats":{"Line":0},"fn_name":null},{"line":180,"address":[6371739],"length":1,"stats":{"Line":0},"fn_name":null},{"line":186,"address":[6371792],"length":1,"stats":{"Line":0},"fn_name":null},{"line":188,"address":[6371869,6371806,6371856],"length":1,"stats":{"Line":0},"fn_name":"{closure#0}"},{"line":194,"address":[6371920],"length":1,"stats":{"Line":0},"fn_name":"from"},{"line":195,"address":[6371928],"length":1,"stats":{"Line":0},"fn_name":null},{"line":207,"address":[6819104,6819357],"length":1,"stats":{"Line":2},"fn_name":"with_openapi<(), (), openapi_supports_scope::openapi_supports_scope::{closure#0}::{closure_env#0}>"},{"line":211,"address":[6819132,6819220],"length":1,"stats":{"Line":4},"fn_name":null},{"line":213,"address":[6819142],"length":1,"stats":{"Line":2},"fn_name":null},{"line":214,"address":[6819215,6819151],"length":1,"stats":{"Line":4},"fn_name":null},{"line":216,"address":[6819255],"length":1,"stats":{"Line":2},"fn_name":null},{"line":225,"address":[6589792],"length":1,"stats":{"Line":5},"fn_name":"resource<(), (), custom_request_body::FooResource>"},{"line":226,"address":[6589816,6589933],"length":1,"stats":{"Line":6},"fn_name":null},{"line":227,"address":[6589886],"length":1,"stats":{"Line":2},"fn_name":null},{"line":229,"address":[6589846],"length":1,"stats":{"Line":5},"fn_name":null},{"line":238,"address":[6597408,6598308],"length":1,"stats":{"Line":31},"fn_name":"endpoint<(), (), custom_request_body::create___gotham_restful_endpoint>"},{"line":239,"address":[6597428,6597510,6597587],"length":1,"stats":{"Line":60},"fn_name":null},{"line":240,"address":[6598010,6597837,6598140,6597924],"length":1,"stats":{"Line":91},"fn_name":null},{"line":241,"address":[6331424,6332181,6332211],"length":1,"stats":{"Line":91},"fn_name":"{closure#0}<(), (), custom_request_body::create___gotham_restful_endpoint>"},{"line":242,"address":[6331444,6331769,6331836,6331645],"length":1,"stats":{"Line":125},"fn_name":null},{"line":243,"address":[6332237,6331470,6331650,6331678],"length":1,"stats":{"Line":63},"fn_name":null},{"line":244,"address":[6331666,6331808,6331701,6332230],"length":1,"stats":{"Line":59},"fn_name":null},{"line":250,"address":[6331883],"length":1,"stats":{"Line":30},"fn_name":null},{"line":251,"address":[6332007,6332116,6332163],"length":1,"stats":{"Line":46},"fn_name":null},{"line":253,"address":[6332089],"length":1,"stats":{"Line":16},"fn_name":null},{"line":254,"address":[6332036],"length":1,"stats":{"Line":14},"fn_name":null}],"covered":57,"coverable":84},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","types.rs"],"content":"use gotham::{\n\thyper::body::Bytes,\n\tmime::{Mime, APPLICATION_JSON}\n};\n#[cfg(feature = \"openapi\")]\nuse openapi_type::OpenapiType;\nuse serde::{de::DeserializeOwned, Serialize};\nuse std::error::Error;\n\n#[cfg(not(feature = \"openapi\"))]\npub trait ResourceType {}\n\n#[cfg(not(feature = \"openapi\"))]\nimpl ResourceType for T {}\n\n#[cfg(feature = \"openapi\")]\npub trait ResourceType: OpenapiType {}\n\n#[cfg(feature = \"openapi\")]\nimpl ResourceType for T {}\n\n/// A type that can be used inside a response body. Implemented for every type that is\n/// serializable with serde. If the `openapi` feature is used, it must also be of type\n/// [OpenapiType].\npub trait ResponseBody: ResourceType + Serialize {}\n\nimpl ResponseBody for T {}\n\n/// This trait should be implemented for every type that can be built from an HTTP request body\n/// plus its media type.\n///\n/// For most use cases it is sufficient to derive this trait, you usually don't need to manually\n/// implement this. Therefore, make sure that the first variable of your struct can be built from\n/// [Bytes], and the second one can be build from [Mime]. If you have any additional variables, they\n/// need to be [Default]. This is an example of such a struct:\n///\n/// ```rust\n/// # use gotham::mime::{self, Mime};\n/// # use gotham_restful::{FromBody, RequestBody};\n/// #[derive(FromBody, RequestBody)]\n/// #[supported_types(mime::IMAGE_GIF, mime::IMAGE_JPEG, mime::IMAGE_PNG)]\n/// struct RawImage {\n/// \tcontent: Vec,\n/// \tcontent_type: Mime\n/// }\n/// ```\npub trait FromBody: Sized {\n\t/// The error type returned by the conversion if it was unsuccessfull. When using the derive\n\t/// macro, there is no way to trigger an error, so [std::convert::Infallible] is used here.\n\t/// However, this might change in the future.\n\ttype Err: Error;\n\n\t/// Perform the conversion.\n\tfn from_body(body: Bytes, content_type: Mime) -> Result;\n}\n\nimpl FromBody for T {\n\ttype Err = serde_json::Error;\n\n\tfn from_body(body: Bytes, _content_type: Mime) -> Result {\n\t\tserde_json::from_slice(&body)\n\t}\n}\n\n/// A type that can be used inside a request body. Implemented for every type that is deserializable\n/// with serde. If the `openapi` feature is used, it must also be of type [OpenapiType].\n///\n/// If you want a non-deserializable type to be used as a request body, e.g. because you'd like to\n/// get the raw data, you can derive it for your own type. All you need is to have a type implementing\n/// [FromBody] and optionally a list of supported media types:\n///\n/// ```rust\n/// # use gotham::mime::{self, Mime};\n/// # use gotham_restful::{FromBody, RequestBody};\n/// #[derive(FromBody, RequestBody)]\n/// #[supported_types(mime::IMAGE_GIF, mime::IMAGE_JPEG, mime::IMAGE_PNG)]\n/// struct RawImage {\n/// \tcontent: Vec,\n/// \tcontent_type: Mime\n/// }\n/// ```\npub trait RequestBody: ResourceType + FromBody {\n\t/// Return all types that are supported as content types. Use `None` if all types are supported.\n\tfn supported_types() -> Option> {\n\t\tNone\n\t}\n}\n\nimpl RequestBody for T {\n\tfn supported_types() -> Option> {\n\t\tSome(vec![APPLICATION_JSON])\n\t}\n}\n","traces":[{"line":60,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":61,"address":[6516910,6516969],"length":1,"stats":{"Line":4},"fn_name":null},{"line":84,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":85,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":90,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":91,"address":[],"length":0,"stats":{"Line":1},"fn_name":null}],"covered":4,"coverable":6},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","async_methods.rs"],"content":"use gotham::{\n\thyper::{HeaderMap, Method},\n\tmime::{APPLICATION_JSON, TEXT_PLAIN},\n\tprelude::*,\n\trouter::build_simple_router,\n\tstate::State,\n\ttest::TestServer\n};\nuse gotham_restful::*;\n#[cfg(feature = \"openapi\")]\nuse openapi_type::OpenapiType;\nuse serde::Deserialize;\nuse tokio::time::{sleep, Duration};\n\nmod util {\n\tinclude!(\"util/mod.rs\");\n}\nuse util::{test_delete_response, test_get_response, test_post_response, test_put_response};\n\n#[derive(Resource)]\n#[resource(\n\tread_all, read, search, create, update_all, update, delete_all, delete, state_test\n)]\nstruct FooResource;\n\n#[derive(Deserialize)]\n#[cfg_attr(feature = \"openapi\", derive(OpenapiType))]\n#[allow(dead_code)]\nstruct FooBody {\n\tdata: String\n}\n\n#[derive(Clone, Deserialize, StateData, StaticResponseExtender)]\n#[cfg_attr(feature = \"openapi\", derive(OpenapiType))]\n#[allow(dead_code)]\nstruct FooSearch {\n\tquery: String\n}\n\nconst READ_ALL_RESPONSE: &[u8] = b\"1ARwwSPVyOKpJKrYwqGgECPVWDl1BqajAAj7g7WJ3e\";\n#[read_all]\nasync fn read_all() -> Raw<&'static [u8]> {\n\tRaw::new(READ_ALL_RESPONSE, TEXT_PLAIN)\n}\n\nconst READ_RESPONSE: &[u8] = b\"FEReHoeBKU17X2bBpVAd1iUvktFL43CDu0cFYHdaP9\";\n#[read]\nasync fn read(_id: u64) -> Raw<&'static [u8]> {\n\tRaw::new(READ_RESPONSE, TEXT_PLAIN)\n}\n\nconst SEARCH_RESPONSE: &[u8] = b\"AWqcQUdBRHXKh3at4u79mdupOAfEbnTcx71ogCVF0E\";\n#[search]\nasync fn search(_body: FooSearch) -> Raw<&'static [u8]> {\n\tRaw::new(SEARCH_RESPONSE, TEXT_PLAIN)\n}\n\nconst CREATE_RESPONSE: &[u8] = b\"y6POY7wOMAB0jBRBw0FJT7DOpUNbhmT8KdpQPLkI83\";\n#[create]\nasync fn create(_body: FooBody) -> Raw<&'static [u8]> {\n\tRaw::new(CREATE_RESPONSE, TEXT_PLAIN)\n}\n\nconst UPDATE_ALL_RESPONSE: &[u8] = b\"QlbYg8gHE9OQvvk3yKjXJLTSXlIrg9mcqhfMXJmQkv\";\n#[update_all]\nasync fn update_all(_body: FooBody) -> Raw<&'static [u8]> {\n\tRaw::new(UPDATE_ALL_RESPONSE, TEXT_PLAIN)\n}\n\nconst UPDATE_RESPONSE: &[u8] = b\"qGod55RUXkT1lgPO8h0uVM6l368O2S0GrwENZFFuRu\";\n#[update]\nasync fn update(_id: u64, _body: FooBody) -> Raw<&'static [u8]> {\n\tRaw::new(UPDATE_RESPONSE, TEXT_PLAIN)\n}\n\nconst DELETE_ALL_RESPONSE: &[u8] = b\"Y36kZ749MRk2Nem4BedJABOZiZWPLOtiwLfJlGTwm5\";\n#[delete_all]\nasync fn delete_all() -> Raw<&'static [u8]> {\n\tRaw::new(DELETE_ALL_RESPONSE, TEXT_PLAIN)\n}\n\nconst DELETE_RESPONSE: &[u8] = b\"CwRzBrKErsVZ1N7yeNfjZuUn1MacvgBqk4uPOFfDDq\";\n#[delete]\nasync fn delete(_id: u64) -> Raw<&'static [u8]> {\n\tRaw::new(DELETE_RESPONSE, TEXT_PLAIN)\n}\n\nconst STATE_TEST_RESPONSE: &[u8] = b\"xxJbxOuwioqR5DfzPuVqvaqRSfpdNQGluIvHU4n1LM\";\n#[endpoint(method = \"Method::GET\", uri = \"state_test\")]\nasync fn state_test(state: &mut State) -> Raw<&'static [u8]> {\n\tsleep(Duration::from_nanos(1)).await;\n\tstate.borrow::();\n\tsleep(Duration::from_nanos(1)).await;\n\tRaw::new(STATE_TEST_RESPONSE, TEXT_PLAIN)\n}\n\n#[test]\nfn async_methods() {\n\tlet _ = pretty_env_logger::try_init_timed();\n\n\tlet server = TestServer::new(build_simple_router(|router| {\n\t\trouter.resource::(\"foo\");\n\t}))\n\t.unwrap();\n\n\ttest_get_response(&server, \"http://localhost/foo\", READ_ALL_RESPONSE);\n\ttest_get_response(&server, \"http://localhost/foo/1\", READ_RESPONSE);\n\ttest_get_response(\n\t\t&server,\n\t\t\"http://localhost/foo/search?query=hello+world\",\n\t\tSEARCH_RESPONSE\n\t);\n\ttest_post_response(\n\t\t&server,\n\t\t\"http://localhost/foo\",\n\t\tr#\"{\"data\":\"hello world\"}\"#,\n\t\tAPPLICATION_JSON,\n\t\tCREATE_RESPONSE\n\t);\n\ttest_put_response(\n\t\t&server,\n\t\t\"http://localhost/foo\",\n\t\tr#\"{\"data\":\"hello world\"}\"#,\n\t\tAPPLICATION_JSON,\n\t\tUPDATE_ALL_RESPONSE\n\t);\n\ttest_put_response(\n\t\t&server,\n\t\t\"http://localhost/foo/1\",\n\t\tr#\"{\"data\":\"hello world\"}\"#,\n\t\tAPPLICATION_JSON,\n\t\tUPDATE_RESPONSE\n\t);\n\ttest_delete_response(&server, \"http://localhost/foo\", DELETE_ALL_RESPONSE);\n\ttest_delete_response(&server, \"http://localhost/foo/1\", DELETE_RESPONSE);\n\ttest_get_response(\n\t\t&server,\n\t\t\"http://localhost/foo/state_test\",\n\t\tSTATE_TEST_RESPONSE\n\t);\n}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","cors_handling.rs"],"content":"#![cfg(feature = \"cors\")]\nuse gotham::{\n\thyper::{body::Body, client::connect::Connect, header::*, StatusCode},\n\tmime::TEXT_PLAIN,\n\tpipeline::{new_pipeline, single_pipeline},\n\trouter::build_router,\n\ttest::{Server, TestRequest, TestServer}\n};\nuse gotham_restful::{\n\tcors::{Headers, Origin},\n\tread_all, update_all, CorsConfig, DrawResources, Raw, Resource\n};\n\n#[derive(Resource)]\n#[resource(read_all, update_all)]\nstruct FooResource;\n\n#[read_all]\nfn read_all() {}\n\n#[update_all]\nfn update_all(_body: Raw>) {}\n\nfn test_server(cfg: CorsConfig) -> TestServer {\n\tlet (chain, pipeline) = single_pipeline(new_pipeline().add(cfg).build());\n\tTestServer::new(build_router(chain, pipeline, |router| {\n\t\trouter.resource::(\"/foo\")\n\t}))\n\t.unwrap()\n}\n\nfn test_response(\n\treq: TestRequest,\n\torigin: Option<&str>,\n\tvary: Option<&str>,\n\tcredentials: bool\n) where\n\tTS: Server + 'static,\n\tC: Connect + Clone + Send + Sync + 'static\n{\n\tlet res = req\n\t\t.with_header(ORIGIN, \"http://example.org\".parse().unwrap())\n\t\t.perform()\n\t\t.unwrap();\n\tassert_eq!(res.status(), StatusCode::NO_CONTENT);\n\tlet headers = res.headers();\n\tprintln!(\n\t\t\"{}\",\n\t\theaders\n\t\t\t.keys()\n\t\t\t.map(|name| name.as_str())\n\t\t\t.collect::>()\n\t\t\t.join(\",\")\n\t);\n\tassert_eq!(\n\t\theaders\n\t\t\t.get(ACCESS_CONTROL_ALLOW_ORIGIN)\n\t\t\t.and_then(|value| value.to_str().ok())\n\t\t\t.as_deref(),\n\t\torigin\n\t);\n\tassert_eq!(\n\t\theaders\n\t\t\t.get(VARY)\n\t\t\t.and_then(|value| value.to_str().ok())\n\t\t\t.as_deref(),\n\t\tvary\n\t);\n\tassert_eq!(\n\t\theaders\n\t\t\t.get(ACCESS_CONTROL_ALLOW_CREDENTIALS)\n\t\t\t.and_then(|value| value.to_str().ok())\n\t\t\t.map(|value| value == \"true\")\n\t\t\t.unwrap_or(false),\n\t\tcredentials\n\t);\n\tassert!(headers.get(ACCESS_CONTROL_MAX_AGE).is_none());\n}\n\nfn test_preflight(\n\tserver: &TestServer,\n\tmethod: &str,\n\torigin: Option<&str>,\n\tvary: &str,\n\tcredentials: bool,\n\tmax_age: u64\n) {\n\tlet res = server\n\t\t.client()\n\t\t.options(\"http://example.org/foo\")\n\t\t.with_header(ACCESS_CONTROL_REQUEST_METHOD, method.parse().unwrap())\n\t\t.with_header(ORIGIN, \"http://example.org\".parse().unwrap())\n\t\t.perform()\n\t\t.unwrap();\n\tassert_eq!(res.status(), StatusCode::NO_CONTENT);\n\tlet headers = res.headers();\n\tprintln!(\n\t\t\"{}\",\n\t\theaders\n\t\t\t.keys()\n\t\t\t.map(|name| name.as_str())\n\t\t\t.collect::>()\n\t\t\t.join(\",\")\n\t);\n\tassert_eq!(\n\t\theaders\n\t\t\t.get(ACCESS_CONTROL_ALLOW_METHODS)\n\t\t\t.and_then(|value| value.to_str().ok())\n\t\t\t.as_deref(),\n\t\tSome(method)\n\t);\n\tassert_eq!(\n\t\theaders\n\t\t\t.get(ACCESS_CONTROL_ALLOW_ORIGIN)\n\t\t\t.and_then(|value| value.to_str().ok())\n\t\t\t.as_deref(),\n\t\torigin\n\t);\n\tassert_eq!(\n\t\theaders\n\t\t\t.get(VARY)\n\t\t\t.and_then(|value| value.to_str().ok())\n\t\t\t.as_deref(),\n\t\tSome(vary)\n\t);\n\tassert_eq!(\n\t\theaders\n\t\t\t.get(ACCESS_CONTROL_ALLOW_CREDENTIALS)\n\t\t\t.and_then(|value| value.to_str().ok())\n\t\t\t.map(|value| value == \"true\")\n\t\t\t.unwrap_or(false),\n\t\tcredentials\n\t);\n\tassert_eq!(\n\t\theaders\n\t\t\t.get(ACCESS_CONTROL_MAX_AGE)\n\t\t\t.and_then(|value| value.to_str().ok())\n\t\t\t.and_then(|value| value.parse().ok()),\n\t\tSome(max_age)\n\t);\n}\n\nfn test_preflight_headers(\n\tserver: &TestServer,\n\tmethod: &str,\n\trequest_headers: Option<&str>,\n\tallowed_headers: Option<&str>,\n\tvary: &str\n) {\n\tlet client = server.client();\n\tlet mut res = client\n\t\t.options(\"http://example.org/foo\")\n\t\t.with_header(ACCESS_CONTROL_REQUEST_METHOD, method.parse().unwrap())\n\t\t.with_header(ORIGIN, \"http://example.org\".parse().unwrap());\n\tif let Some(hdr) = request_headers {\n\t\tres = res.with_header(ACCESS_CONTROL_REQUEST_HEADERS, hdr.parse().unwrap());\n\t}\n\tlet res = res.perform().unwrap();\n\tassert_eq!(res.status(), StatusCode::NO_CONTENT);\n\tlet headers = res.headers();\n\tprintln!(\n\t\t\"{}\",\n\t\theaders\n\t\t\t.keys()\n\t\t\t.map(|name| name.as_str())\n\t\t\t.collect::>()\n\t\t\t.join(\",\")\n\t);\n\tif let Some(hdr) = allowed_headers {\n\t\tassert_eq!(\n\t\t\theaders\n\t\t\t\t.get(ACCESS_CONTROL_ALLOW_HEADERS)\n\t\t\t\t.and_then(|value| value.to_str().ok())\n\t\t\t\t.as_deref(),\n\t\t\tSome(hdr)\n\t\t)\n\t} else {\n\t\tassert!(!headers.contains_key(ACCESS_CONTROL_ALLOW_HEADERS));\n\t}\n\tassert_eq!(\n\t\theaders\n\t\t\t.get(VARY)\n\t\t\t.and_then(|value| value.to_str().ok())\n\t\t\t.as_deref(),\n\t\tSome(vary)\n\t);\n}\n\n#[test]\nfn cors_origin_none() {\n\tlet cfg = Default::default();\n\tlet server = test_server(cfg);\n\n\ttest_preflight(\n\t\t&server,\n\t\t\"PUT\",\n\t\tNone,\n\t\t\"access-control-request-method\",\n\t\tfalse,\n\t\t0\n\t);\n\n\ttest_response(\n\t\tserver.client().get(\"http://example.org/foo\"),\n\t\tNone,\n\t\tNone,\n\t\tfalse\n\t);\n\ttest_response(\n\t\tserver\n\t\t\t.client()\n\t\t\t.put(\"http://example.org/foo\", Body::empty(), TEXT_PLAIN),\n\t\tNone,\n\t\tNone,\n\t\tfalse\n\t);\n}\n\n#[test]\nfn cors_origin_star() {\n\tlet cfg = CorsConfig {\n\t\torigin: Origin::Star,\n\t\t..Default::default()\n\t};\n\tlet server = test_server(cfg);\n\n\ttest_preflight(\n\t\t&server,\n\t\t\"PUT\",\n\t\tSome(\"*\"),\n\t\t\"access-control-request-method\",\n\t\tfalse,\n\t\t0\n\t);\n\n\ttest_response(\n\t\tserver.client().get(\"http://example.org/foo\"),\n\t\tSome(\"*\"),\n\t\tNone,\n\t\tfalse\n\t);\n\ttest_response(\n\t\tserver\n\t\t\t.client()\n\t\t\t.put(\"http://example.org/foo\", Body::empty(), TEXT_PLAIN),\n\t\tSome(\"*\"),\n\t\tNone,\n\t\tfalse\n\t);\n}\n\n#[test]\nfn cors_origin_single() {\n\tlet cfg = CorsConfig {\n\t\torigin: Origin::Single(\"https://foo.com\".to_owned()),\n\t\t..Default::default()\n\t};\n\tlet server = test_server(cfg);\n\n\ttest_preflight(\n\t\t&server,\n\t\t\"PUT\",\n\t\tSome(\"https://foo.com\"),\n\t\t\"access-control-request-method\",\n\t\tfalse,\n\t\t0\n\t);\n\n\ttest_response(\n\t\tserver.client().get(\"http://example.org/foo\"),\n\t\tSome(\"https://foo.com\"),\n\t\tNone,\n\t\tfalse\n\t);\n\ttest_response(\n\t\tserver\n\t\t\t.client()\n\t\t\t.put(\"http://example.org/foo\", Body::empty(), TEXT_PLAIN),\n\t\tSome(\"https://foo.com\"),\n\t\tNone,\n\t\tfalse\n\t);\n}\n\n#[test]\nfn cors_origin_copy() {\n\tlet cfg = CorsConfig {\n\t\torigin: Origin::Copy,\n\t\t..Default::default()\n\t};\n\tlet server = test_server(cfg);\n\n\ttest_preflight(\n\t\t&server,\n\t\t\"PUT\",\n\t\tSome(\"http://example.org\"),\n\t\t\"access-control-request-method,origin\",\n\t\tfalse,\n\t\t0\n\t);\n\n\ttest_response(\n\t\tserver.client().get(\"http://example.org/foo\"),\n\t\tSome(\"http://example.org\"),\n\t\tSome(\"origin\"),\n\t\tfalse\n\t);\n\ttest_response(\n\t\tserver\n\t\t\t.client()\n\t\t\t.put(\"http://example.org/foo\", Body::empty(), TEXT_PLAIN),\n\t\tSome(\"http://example.org\"),\n\t\tSome(\"origin\"),\n\t\tfalse\n\t);\n}\n\n#[test]\nfn cors_headers_none() {\n\tlet cfg = Default::default();\n\tlet server = test_server(cfg);\n\n\ttest_preflight_headers(&server, \"PUT\", None, None, \"access-control-request-method\");\n\ttest_preflight_headers(\n\t\t&server,\n\t\t\"PUT\",\n\t\tSome(\"Content-Type\"),\n\t\tNone,\n\t\t\"access-control-request-method\"\n\t);\n}\n\n#[test]\nfn cors_headers_list() {\n\tlet cfg = CorsConfig {\n\t\theaders: Headers::List(vec![CONTENT_TYPE]),\n\t\t..Default::default()\n\t};\n\tlet server = test_server(cfg);\n\n\ttest_preflight_headers(\n\t\t&server,\n\t\t\"PUT\",\n\t\tNone,\n\t\tSome(\"content-type\"),\n\t\t\"access-control-request-method\"\n\t);\n\ttest_preflight_headers(\n\t\t&server,\n\t\t\"PUT\",\n\t\tSome(\"content-type\"),\n\t\tSome(\"content-type\"),\n\t\t\"access-control-request-method\"\n\t);\n}\n\n#[test]\nfn cors_headers_copy() {\n\tlet cfg = CorsConfig {\n\t\theaders: Headers::Copy,\n\t\t..Default::default()\n\t};\n\tlet server = test_server(cfg);\n\n\ttest_preflight_headers(\n\t\t&server,\n\t\t\"PUT\",\n\t\tNone,\n\t\tNone,\n\t\t\"access-control-request-method,access-control-request-headers\"\n\t);\n\ttest_preflight_headers(\n\t\t&server,\n\t\t\"PUT\",\n\t\tSome(\"content-type\"),\n\t\tSome(\"content-type\"),\n\t\t\"access-control-request-method,access-control-request-headers\"\n\t);\n}\n\n#[test]\nfn cors_credentials() {\n\tlet cfg = CorsConfig {\n\t\torigin: Origin::None,\n\t\tcredentials: true,\n\t\t..Default::default()\n\t};\n\tlet server = test_server(cfg);\n\n\ttest_preflight(\n\t\t&server,\n\t\t\"PUT\",\n\t\tNone,\n\t\t\"access-control-request-method\",\n\t\ttrue,\n\t\t0\n\t);\n\n\ttest_response(\n\t\tserver.client().get(\"http://example.org/foo\"),\n\t\tNone,\n\t\tNone,\n\t\ttrue\n\t);\n\ttest_response(\n\t\tserver\n\t\t\t.client()\n\t\t\t.put(\"http://example.org/foo\", Body::empty(), TEXT_PLAIN),\n\t\tNone,\n\t\tNone,\n\t\ttrue\n\t);\n}\n\n#[test]\nfn cors_max_age() {\n\tlet cfg = CorsConfig {\n\t\torigin: Origin::None,\n\t\tmax_age: 31536000,\n\t\t..Default::default()\n\t};\n\tlet server = test_server(cfg);\n\n\ttest_preflight(\n\t\t&server,\n\t\t\"PUT\",\n\t\tNone,\n\t\t\"access-control-request-method\",\n\t\tfalse,\n\t\t31536000\n\t);\n\n\ttest_response(\n\t\tserver.client().get(\"http://example.org/foo\"),\n\t\tNone,\n\t\tNone,\n\t\tfalse\n\t);\n\ttest_response(\n\t\tserver\n\t\t\t.client()\n\t\t\t.put(\"http://example.org/foo\", Body::empty(), TEXT_PLAIN),\n\t\tNone,\n\t\tNone,\n\t\tfalse\n\t);\n}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","custom_request_body.rs"],"content":"use gotham::{\n\thyper::header::CONTENT_TYPE,\n\tmime::{Mime, TEXT_PLAIN},\n\trouter::builder::*,\n\ttest::TestServer\n};\nuse gotham_restful::{create, DrawResources, FromBody, Raw, RequestBody, Resource};\n\nconst RESPONSE: &[u8] = b\"This is the only valid response.\";\n\n#[derive(Resource)]\n#[resource(create)]\nstruct FooResource;\n\n#[derive(FromBody, RequestBody)]\n#[supported_types(TEXT_PLAIN)]\nstruct Foo {\n\tcontent: Vec,\n\tcontent_type: Mime\n}\n\n#[create]\nfn create(body: Foo) -> Raw> {\n\tRaw::new(body.content, body.content_type)\n}\n\n#[test]\nfn custom_request_body() {\n\tlet server = TestServer::new(build_simple_router(|router| {\n\t\trouter.resource::(\"foo\");\n\t}))\n\t.unwrap();\n\n\tlet res = server\n\t\t.client()\n\t\t.post(\"http://localhost/foo\", RESPONSE, TEXT_PLAIN)\n\t\t.perform()\n\t\t.unwrap();\n\tassert_eq!(\n\t\tres.headers().get(CONTENT_TYPE).unwrap().to_str().unwrap(),\n\t\t\"text/plain\"\n\t);\n\tlet res = res.read_body().unwrap();\n\tlet body: &[u8] = res.as_ref();\n\tassert_eq!(body, RESPONSE);\n}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","openapi_specification.rs"],"content":"#![cfg(all(feature = \"auth\", feature = \"openapi\"))]\n#![allow(clippy::approx_constant)]\n\n#[macro_use]\nextern crate pretty_assertions;\n\nuse gotham::{\n\thyper::{Method, StatusCode},\n\tmime::{IMAGE_PNG, TEXT_PLAIN_UTF_8},\n\tpipeline::{new_pipeline, single_pipeline},\n\tprelude::*,\n\trouter::build_router,\n\ttest::TestServer\n};\nuse gotham_restful::*;\nuse openapi_type::{OpenapiSchema, OpenapiType, Visitor};\nuse serde::{Deserialize, Serialize};\n\n#[allow(dead_code)]\nmod util {\n\tinclude!(\"util/mod.rs\");\n}\nuse util::test_openapi_response;\n\nconst IMAGE_RESPONSE : &[u8] = b\"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUA/wA0XsCoAAAAAXRSTlN/gFy0ywAAAApJREFUeJxjYgAAAAYAAzY3fKgAAAAASUVORK5CYII=\";\n\n#[derive(Resource)]\n#[resource(get_image, set_image)]\nstruct ImageResource;\n\n#[derive(FromBody, RequestBody)]\n#[supported_types(IMAGE_PNG)]\nstruct Image(Vec);\n\n#[read(operation_id = \"getImage\")]\nfn get_image(_id: u64) -> Raw<&'static [u8]> {\n\tRaw::new(IMAGE_RESPONSE, \"image/png;base64\".parse().unwrap())\n}\n\n#[update(operation_id = \"setImage\")]\nfn set_image(_id: u64, _image: Image) {}\n\n#[derive(Resource)]\n#[resource(read_secret, search_secret)]\nstruct SecretResource;\n\n#[derive(Deserialize, Clone)]\nstruct AuthData {\n\tsub: String,\n\tiat: u64,\n\texp: u64\n}\n\ntype AuthStatus = gotham_restful::AuthStatus;\n\n#[derive(OpenapiType, Serialize)]\nstruct Secret {\n\tcode: f32\n}\n\n#[derive(OpenapiType, Serialize)]\nstruct Secrets {\n\tsecrets: Vec\n}\n\n#[derive(Clone, Deserialize, OpenapiType, StateData, StaticResponseExtender)]\nstruct SecretQuery {\n\tdate: String,\n\thour: Option,\n\tminute: Option\n}\n\n/// This endpoint gives access to the secret.\n///\n/// You need to be authenticated to call this endpoint.\n#[read]\nfn read_secret(auth: AuthStatus, _id: String) -> AuthSuccess {\n\tauth.ok()?;\n\tOk(Secret { code: 4.2 })\n}\n\n#[search]\nfn search_secret(auth: AuthStatus, _query: SecretQuery) -> AuthSuccess {\n\tauth.ok()?;\n\tOk(Secrets {\n\t\tsecrets: vec![Secret { code: 4.2 }, Secret { code: 3.14 }]\n\t})\n}\n\n#[derive(Resource)]\n#[resource(coffee_read_all)]\nstruct CoffeeResource;\n\nfn teapot_status_codes() -> Vec {\n\tvec![StatusCode::IM_A_TEAPOT]\n}\n\nfn teapot_schema(code: StatusCode) -> OpenapiSchema {\n\tassert_eq!(code, StatusCode::IM_A_TEAPOT);\n\n\tstruct Binary;\n\n\timpl OpenapiType for Binary {\n\t\tfn visit_type(visitor: &mut V) {\n\t\t\tvisitor.visit_binary();\n\t\t}\n\t}\n\n\tBinary::schema()\n}\n\n#[read_all(status_codes = \"teapot_status_codes\", schema = \"teapot_schema\")]\nfn coffee_read_all() -> Response {\n\tResponse::new(\n\t\tStatusCode::IM_A_TEAPOT,\n\t\t\"Sorry, this is just your fancy grandma's teapot. Can't make coffee.\",\n\t\tSome(TEXT_PLAIN_UTF_8)\n\t)\n}\n\n#[derive(Resource)]\n#[resource(custom_read_with, custom_patch)]\nstruct CustomResource;\n\n#[derive(Clone, Deserialize, OpenapiType, StateData, StaticResponseExtender)]\nstruct ReadWithPath {\n\tfrom: String,\n\tid: u64\n}\n\n#[endpoint(method = \"Method::GET\", uri = \"read/:from/with/:id\")]\nfn custom_read_with(_path: ReadWithPath) {}\n\n#[endpoint(method = \"Method::PATCH\", uri = \"\", body = true)]\nfn custom_patch(_body: String) {}\n\n#[test]\nfn openapi_specification() {\n\tlet info = OpenapiInfo {\n\t\ttitle: \"This is just a test\".to_owned(),\n\t\tversion: \"1.2.3\".to_owned(),\n\t\turls: vec![\"http://localhost:12345/api/v1\".to_owned()]\n\t};\n\tlet auth: AuthMiddleware = AuthMiddleware::new(\n\t\tAuthSource::AuthorizationHeader,\n\t\tAuthValidation::default(),\n\t\tStaticAuthHandler::from_array(b\"zlBsA2QXnkmpe0QTh8uCvtAEa4j33YAc\")\n\t);\n\tlet (chain, pipelines) = single_pipeline(new_pipeline().add(auth).build());\n\tlet server = TestServer::new(build_router(chain, pipelines, |router| {\n\t\trouter.with_openapi(info, |mut router| {\n\t\t\t// the leading slash tests that the spec doesn't contain '//img' nonsense\n\t\t\trouter.resource::(\"/img\");\n\t\t\trouter.resource::(\"secret\");\n\t\t\trouter.resource::(\"coffee\");\n\t\t\trouter.resource::(\"custom\");\n\t\t\trouter.openapi_spec(\"openapi\");\n\t\t});\n\t}))\n\t.unwrap();\n\n\ttest_openapi_response(\n\t\t&server,\n\t\t\"http://localhost/openapi\",\n\t\t\"tests/openapi_specification.json\"\n\t);\n}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","openapi_supports_scope.rs"],"content":"#![cfg(feature = \"openapi\")]\n\n#[macro_use]\nextern crate pretty_assertions;\n\nuse gotham::{mime::TEXT_PLAIN, router::builder::*, test::TestServer};\nuse gotham_restful::*;\n\n#[allow(dead_code)]\nmod util {\n\tinclude!(\"util/mod.rs\");\n}\nuse util::{test_get_response, test_openapi_response};\n\nconst RESPONSE: &[u8] = b\"This is the only valid response.\";\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\n#[read_all]\nfn read_all() -> Raw<&'static [u8]> {\n\tRaw::new(RESPONSE, TEXT_PLAIN)\n}\n\n#[test]\nfn openapi_supports_scope() {\n\tlet info = OpenapiInfo {\n\t\ttitle: \"Test\".to_owned(),\n\t\tversion: \"1.2.3\".to_owned(),\n\t\turls: Vec::new()\n\t};\n\tlet server = TestServer::new(build_simple_router(|router| {\n\t\trouter.with_openapi(info, |mut router| {\n\t\t\trouter.openapi_spec(\"openapi\");\n\t\t\trouter.resource::(\"foo1\");\n\t\t\trouter.scope(\"/bar\", |router| {\n\t\t\t\trouter.resource::(\"foo2\");\n\t\t\t\trouter.scope(\"/baz\", |router| {\n\t\t\t\t\trouter.resource::(\"foo3\");\n\t\t\t\t})\n\t\t\t});\n\t\t\trouter.resource::(\"foo4\");\n\t\t});\n\t}))\n\t.unwrap();\n\n\ttest_get_response(&server, \"http://localhost/foo1\", RESPONSE);\n\ttest_get_response(&server, \"http://localhost/bar/foo2\", RESPONSE);\n\ttest_get_response(&server, \"http://localhost/bar/baz/foo3\", RESPONSE);\n\ttest_get_response(&server, \"http://localhost/foo4\", RESPONSE);\n\ttest_openapi_response(\n\t\t&server,\n\t\t\"http://localhost/openapi\",\n\t\t\"tests/openapi_supports_scope.json\"\n\t);\n}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","resource_error.rs"],"content":"use gotham_restful::ResourceError;\n\n#[derive(ResourceError)]\nenum Error {\n\t#[display(\"I/O Error: {0}\")]\n\tIoError(#[from] std::io::Error),\n\n\t#[status(INTERNAL_SERVER_ERROR)]\n\t#[display(\"Internal Server Error: {0}\")]\n\tInternalServerError(String)\n}\n\n#[allow(deprecated)]\nmod resource_error {\n\tuse super::Error;\n\tuse gotham::{hyper::StatusCode, mime::APPLICATION_JSON};\n\tuse gotham_restful::IntoResponseError;\n\n\t#[test]\n\tfn io_error() {\n\t\tlet err = Error::IoError(std::io::Error::last_os_error());\n\t\tlet res = err.into_response_error().unwrap();\n\t\tassert_eq!(res.status(), StatusCode::INTERNAL_SERVER_ERROR);\n\t\tassert_eq!(res.mime(), Some(&APPLICATION_JSON));\n\t}\n\n\t#[test]\n\tfn internal_server_error() {\n\t\tlet err = Error::InternalServerError(\"Brocken\".to_owned());\n\t\tassert_eq!(&format!(\"{err}\"), \"Internal Server Error: Brocken\");\n\n\t\tlet res = err.into_response_error().unwrap();\n\t\tassert_eq!(res.status(), StatusCode::INTERNAL_SERVER_ERROR);\n\t\tassert_eq!(res.mime(), None); // TODO shouldn't this be a json error message?\n\t}\n}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","sync_methods.rs"],"content":"use gotham::{\n\tmime::{APPLICATION_JSON, TEXT_PLAIN},\n\tprelude::*,\n\trouter::build_simple_router,\n\ttest::TestServer\n};\nuse gotham_restful::*;\n#[cfg(feature = \"openapi\")]\nuse openapi_type::OpenapiType;\nuse serde::Deserialize;\n\nmod util {\n\tinclude!(\"util/mod.rs\");\n}\nuse util::{test_delete_response, test_get_response, test_post_response, test_put_response};\n\n#[derive(Resource)]\n#[resource(read_all, read, search, create, update_all, update, delete_all, delete)]\nstruct FooResource;\n\n#[derive(Deserialize)]\n#[cfg_attr(feature = \"openapi\", derive(OpenapiType))]\n#[allow(dead_code)]\nstruct FooBody {\n\tdata: String\n}\n\n#[derive(Clone, Deserialize, StateData, StaticResponseExtender)]\n#[cfg_attr(feature = \"openapi\", derive(OpenapiType))]\n#[allow(dead_code)]\nstruct FooSearch {\n\tquery: String\n}\n\nconst READ_ALL_RESPONSE: &[u8] = b\"1ARwwSPVyOKpJKrYwqGgECPVWDl1BqajAAj7g7WJ3e\";\n#[read_all]\nfn read_all() -> Raw<&'static [u8]> {\n\tRaw::new(READ_ALL_RESPONSE, TEXT_PLAIN)\n}\n\nconst READ_RESPONSE: &[u8] = b\"FEReHoeBKU17X2bBpVAd1iUvktFL43CDu0cFYHdaP9\";\n#[read]\nfn read(_id: u64) -> Raw<&'static [u8]> {\n\tRaw::new(READ_RESPONSE, TEXT_PLAIN)\n}\n\nconst SEARCH_RESPONSE: &[u8] = b\"AWqcQUdBRHXKh3at4u79mdupOAfEbnTcx71ogCVF0E\";\n#[search]\nfn search(_body: FooSearch) -> Raw<&'static [u8]> {\n\tRaw::new(SEARCH_RESPONSE, TEXT_PLAIN)\n}\n\nconst CREATE_RESPONSE: &[u8] = b\"y6POY7wOMAB0jBRBw0FJT7DOpUNbhmT8KdpQPLkI83\";\n#[create]\nfn create(_body: FooBody) -> Raw<&'static [u8]> {\n\tRaw::new(CREATE_RESPONSE, TEXT_PLAIN)\n}\n\nconst UPDATE_ALL_RESPONSE: &[u8] = b\"QlbYg8gHE9OQvvk3yKjXJLTSXlIrg9mcqhfMXJmQkv\";\n#[update_all]\nfn update_all(_body: FooBody) -> Raw<&'static [u8]> {\n\tRaw::new(UPDATE_ALL_RESPONSE, TEXT_PLAIN)\n}\n\nconst UPDATE_RESPONSE: &[u8] = b\"qGod55RUXkT1lgPO8h0uVM6l368O2S0GrwENZFFuRu\";\n#[update]\nfn update(_id: u64, _body: FooBody) -> Raw<&'static [u8]> {\n\tRaw::new(UPDATE_RESPONSE, TEXT_PLAIN)\n}\n\nconst DELETE_ALL_RESPONSE: &[u8] = b\"Y36kZ749MRk2Nem4BedJABOZiZWPLOtiwLfJlGTwm5\";\n#[delete_all]\nfn delete_all() -> Raw<&'static [u8]> {\n\tRaw::new(DELETE_ALL_RESPONSE, TEXT_PLAIN)\n}\n\nconst DELETE_RESPONSE: &[u8] = b\"CwRzBrKErsVZ1N7yeNfjZuUn1MacvgBqk4uPOFfDDq\";\n#[delete]\nfn delete(_id: u64) -> Raw<&'static [u8]> {\n\tRaw::new(DELETE_RESPONSE, TEXT_PLAIN)\n}\n\n#[test]\nfn sync_methods() {\n\tlet _ = pretty_env_logger::try_init_timed();\n\n\tlet server = TestServer::new(build_simple_router(|router| {\n\t\trouter.resource::(\"foo\");\n\t}))\n\t.unwrap();\n\n\ttest_get_response(&server, \"http://localhost/foo\", READ_ALL_RESPONSE);\n\ttest_get_response(&server, \"http://localhost/foo/1\", READ_RESPONSE);\n\ttest_get_response(\n\t\t&server,\n\t\t\"http://localhost/foo/search?query=hello+world\",\n\t\tSEARCH_RESPONSE\n\t);\n\ttest_post_response(\n\t\t&server,\n\t\t\"http://localhost/foo\",\n\t\tr#\"{\"data\":\"hello world\"}\"#,\n\t\tAPPLICATION_JSON,\n\t\tCREATE_RESPONSE\n\t);\n\ttest_put_response(\n\t\t&server,\n\t\t\"http://localhost/foo\",\n\t\tr#\"{\"data\":\"hello world\"}\"#,\n\t\tAPPLICATION_JSON,\n\t\tUPDATE_ALL_RESPONSE\n\t);\n\ttest_put_response(\n\t\t&server,\n\t\t\"http://localhost/foo/1\",\n\t\tr#\"{\"data\":\"hello world\"}\"#,\n\t\tAPPLICATION_JSON,\n\t\tUPDATE_RESPONSE\n\t);\n\ttest_delete_response(&server, \"http://localhost/foo\", DELETE_ALL_RESPONSE);\n\ttest_delete_response(&server, \"http://localhost/foo/1\", DELETE_RESPONSE);\n}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","trybuild_ui.rs"],"content":"use trybuild::TestCases;\n\n#[test]\n#[ignore]\nfn trybuild_ui() {\n\tlet t = TestCases::new();\n\tt.compile_fail(\"tests/ui/endpoint/*.rs\");\n\tt.compile_fail(\"tests/ui/from_body/*.rs\");\n\tt.compile_fail(\"tests/ui/resource/*.rs\");\n}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","async_state.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\nuse gotham::state::State;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\n#[read_all]\nasync fn read_all(state: &State) {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","auth_data_non_clone.rs"],"content":"use gotham_restful::*;\nuse serde::Deserialize;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\n#[derive(Deserialize)]\nstruct AuthData {\n\tiat: u64,\n\texp: u64\n}\n\n#[read_all]\nasync fn read_all(auth: AuthStatus) -> Result {\n\tauth.ok()?;\n\tOk(NoContent::default())\n}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","custom_method_invalid_expr.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\n#[endpoint(method = \"I like pizza\", uri = \"custom_read\")]\nasync fn read_all() {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","custom_method_invalid_type.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\n#[endpoint(method = \"String::new()\", uri = \"custom_read\")]\nasync fn read_all() {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","custom_method_missing.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\n#[endpoint(uri = \"custom_read\")]\nasync fn read_all() {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","custom_uri_missing.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\n#[endpoint(method = \"gotham_restful::gotham::hyper::Method::GET\")]\nasync fn read_all() {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","dynamic_schema_missing_schema.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\nuse gotham::hyper::StatusCode;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\nfn status_codes() -> Vec {\n\tunimplemented!()\n}\n\n#[read_all(status_codes = \"status_codes\")]\nasync fn read_all() {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","dynamic_schema_missing_status_codes.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\nuse gotham::hyper::StatusCode;\nuse gotham_restful::private::OpenapiSchema;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\nfn schema(_: StatusCode) -> OpenapiSchema {\n\tunimplemented!()\n}\n\n#[read_all(schema = \"schema\")]\nasync fn read_all() {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","dynamic_schema_wrong_type.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\nfn schema(_: u16) -> String {\n\tunimplemented!()\n}\n\nfn status_codes() -> Vec {\n\tunimplemented!()\n}\n\n#[read_all(schema = \"schema\", status_codes = \"status_codes\")]\nasync fn read_all() {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","invalid_attribute.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\n#[read_all(FooResource)]\nfn read_all() {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","invalid_body_ty.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\nuse gotham_restful::gotham::hyper::Method;\n\n#[derive(Resource)]\n#[resource(endpoint)]\nstruct FooResource;\n\n#[derive(Debug)]\nstruct FooBody {\n\tfoo: String\n}\n\n#[endpoint(method = \"Method::GET\", uri = \"\", body = true)]\nfn endpoint(_: FooBody) {\n\tunimplemented!()\n}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","invalid_params_ty.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\nuse gotham_restful::gotham::hyper::Method;\n\n#[derive(Resource)]\n#[resource(endpoint)]\nstruct FooResource;\n\n#[derive(Debug)]\nstruct FooParams {\n\tfoo: String\n}\n\n#[endpoint(method = \"Method::GET\", uri = \"\", params = true)]\nfn endpoint(_: FooParams) {\n\tunimplemented!()\n}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","invalid_placeholders_ty.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\nuse gotham_restful::gotham::hyper::Method;\n\n#[derive(Resource)]\n#[resource(endpoint)]\nstruct FooResource;\n\n#[derive(Debug)]\nstruct FooPlaceholders {\n\tfoo: String\n}\n\n#[endpoint(method = \"Method::GET\", uri = \":foo\")]\nfn endpoint(_: FooPlaceholders) {\n\tunimplemented!()\n}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","invalid_return_type.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\nuse gotham_restful::gotham::hyper::Method;\n\n#[derive(Resource)]\n#[resource(endpoint)]\nstruct FooResource;\n\nstruct FooResponse;\n\n#[endpoint(method = \"Method::GET\", uri = \"\")]\nfn endpoint() -> FooResponse {\n\tunimplemented!()\n}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","non_custom_body_attribute.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\n#[read_all(body = false)]\nasync fn read_all() {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","non_custom_method_attribute.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\n#[read_all(method = \"gotham_restful::gotham::hyper::Method::GET\")]\nasync fn read_all() {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","non_custom_params_attribute.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\n#[read_all(params = true)]\nasync fn read_all() {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","non_custom_uri_attribute.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\n#[read_all(uri = \"custom_read\")]\nasync fn read_all() {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","self.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\n#[read_all]\nfn read_all(self) {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","too_few_args.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(Resource)]\n#[resource(read)]\nstruct FooResource;\n\n#[read]\nfn read() {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","too_many_args.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\n#[read_all]\nfn read_all(_id: u64) {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","unknown_attribute.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\n#[read_all(pineapple = \"on pizza\")]\nfn read_all() {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","unsafe.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\n#[read_all]\nunsafe fn read_all() {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","wants_auth_non_bool.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\n#[read_all(wants_auth = \"yes, please\")]\nasync fn read_all() {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","from_body","enum.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(FromBody)]\nenum FromBodyEnum {\n\tSomeVariant(Vec),\n\tOtherVariant(String)\n}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","resource","unknown_method.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(Resource)]\n#[resource(read_any)]\nstruct FooResource;\n\n#[read_all]\nfn read_all() {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","util","mod.rs"],"content":"use gotham::{\n\thyper::Body,\n\ttest::TestServer\n};\nuse log::info;\nuse gotham::mime::Mime;\n#[allow(unused_imports)]\nuse std::{fs::File, io::{Read, Write}, str};\n\npub fn test_get_response(server : &TestServer, path : &str, expected : &[u8])\n{\n\tinfo!(\"GET {path}\");\n\tlet res = server.client().get(path).perform().unwrap().read_body().unwrap();\n\tlet body : &[u8] = res.as_ref();\n\tassert_eq!(body, expected);\n}\n\npub fn test_post_response(server : &TestServer, path : &str, body : B, mime : Mime, expected : &[u8])\nwhere\n\tB : Into\n{\n\tinfo!(\"POST {path}\");\n\tlet res = server.client().post(path, body, mime).perform().unwrap().read_body().unwrap();\n\tlet body : &[u8] = res.as_ref();\n\tassert_eq!(body, expected);\n}\n\npub fn test_put_response(server : &TestServer, path : &str, body : B, mime : Mime, expected : &[u8])\nwhere\n\tB : Into\n{\n\tinfo!(\"PUT {path}\");\n\tlet res = server.client().put(path, body, mime).perform().unwrap().read_body().unwrap();\n\tlet body : &[u8] = res.as_ref();\n\tassert_eq!(body, expected);\n}\n\npub fn test_delete_response(server : &TestServer, path : &str, expected : &[u8])\n{\n\tinfo!(\"DELETE {path}\");\n\tlet res = server.client().delete(path).perform().unwrap().read_body().unwrap();\n\tlet body : &[u8] = res.as_ref();\n\tassert_eq!(body, expected);\n}\n\n#[cfg(feature = \"openapi\")]\npub fn test_openapi_response(server : &TestServer, path : &str, output_file : &str)\n{\n\tinfo!(\"GET {path}\");\n\tlet res = server.client().get(path).perform().unwrap().read_body().unwrap();\n\tlet body: serde_json::Value = serde_json::from_slice(&res).unwrap();\n\n\tlet mut file = File::open(output_file).unwrap();\n\tlet expected: serde_json::Value = serde_json::from_reader(&mut file).unwrap();\n\n\t//eprintln!(\"{body}\");\n\tassert_eq!(body, expected);\n}\n","traces":[],"covered":0,"coverable":0}]} \ No newline at end of file +{"files":[{"path":["/","home","runner","work","gotham_restful","gotham_restful","redoc","src","lib.rs"],"content":"#![forbid(elided_lifetimes_in_paths, unsafe_code)]\n\n//! Private implementation detail of the `gotham_restful` crate.\n\nuse base64::prelude::*;\nuse either::Either;\nuse sha2::{Digest, Sha256};\nuse std::{io::Write, iter};\n\n#[doc(hidden)]\npub struct Redoc {\n\t/// HTML code.\n\tpub html: Vec,\n\n\t/// JS hash base64 encoded.\n\tpub script_hash: String\n}\n\n#[doc(hidden)]\npub fn html(spec: String) -> Redoc {\n\tlet encoded_spec = spec\n\t\t.chars()\n\t\t.flat_map(|c| match c {\n\t\t\t'&' => Either::Left(\"&\".chars()),\n\t\t\t'<' => Either::Left(\"<\".chars()),\n\t\t\t'>' => Either::Left(\">\".chars()),\n\t\t\tc => Either::Right(iter::once(c))\n\t\t})\n\t\t.collect::();\n\n\tlet script = include_str!(\"script.min.js\");\n\tlet mut script_hash = Sha256::new();\n\tscript_hash.update(script);\n\tlet script_hash = BASE64_STANDARD.encode(script_hash.finalize());\n\n\tlet mut html = Vec::::new();\n\twrite!(\n\t\thtml,\n\t\tconcat!(\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\tr#\"\"#,\n\t\t\tr#\"\"#,\n\t\t\t\"\",\n\t\t\tr#\"\"#,\n\t\t\tr#\"

{}
\"#,\n\t\t\tr#\"
\"#,\n\t\t\tr#\"\"#,\n\t\t\t\"\",\n\t\t\t\"\"\n\t\t),\n\t\tencoded_spec, script\n\t)\n\t.unwrap();\n\n\tRedoc { html, script_hash }\n}\n","traces":[{"line":20,"address":[6795184,6796254],"length":1,"stats":{"Line":0},"fn_name":"html"},{"line":21,"address":[6795303,6795235],"length":1,"stats":{"Line":0},"fn_name":null},{"line":23,"address":[8748160,8748187],"length":1,"stats":{"Line":0},"fn_name":"{closure#0}"},{"line":24,"address":[6796373],"length":1,"stats":{"Line":0},"fn_name":null},{"line":25,"address":[8748279],"length":1,"stats":{"Line":0},"fn_name":null},{"line":26,"address":[8748313],"length":1,"stats":{"Line":0},"fn_name":null},{"line":27,"address":[8748220],"length":1,"stats":{"Line":0},"fn_name":null},{"line":31,"address":[6795214,6795376],"length":1,"stats":{"Line":0},"fn_name":null},{"line":32,"address":[8747275],"length":1,"stats":{"Line":0},"fn_name":null},{"line":33,"address":[6412106],"length":1,"stats":{"Line":0},"fn_name":null},{"line":34,"address":[6795501],"length":1,"stats":{"Line":0},"fn_name":null},{"line":36,"address":[6795674],"length":1,"stats":{"Line":0},"fn_name":null},{"line":37,"address":[6795969],"length":1,"stats":{"Line":0},"fn_name":null}],"covered":0,"coverable":13},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","auth.rs"],"content":"use crate::AuthError;\n\nuse base64::prelude::*;\nuse futures_util::{\n\tfuture,\n\tfuture::{FutureExt, TryFutureExt}\n};\nuse gotham::{\n\tanyhow,\n\tcookie::CookieJar,\n\thandler::HandlerFuture,\n\thyper::header::{HeaderMap, HeaderName, AUTHORIZATION},\n\tmiddleware::{cookie::CookieParser, Middleware, NewMiddleware},\n\tprelude::*,\n\tstate::State\n};\nuse jsonwebtoken::DecodingKey;\nuse serde::de::DeserializeOwned;\nuse std::{marker::PhantomData, panic::RefUnwindSafe, pin::Pin};\n\npub type AuthValidation = jsonwebtoken::Validation;\n\n/// The authentication status returned by the auth middleware for each request.\n#[derive(Debug, StateData)]\npub enum AuthStatus {\n\t/// The auth status is unknown. This is likely because no secret was provided\n\t/// that could be used to verify the token of the client.\n\tUnknown,\n\n\t/// The request has been performed without any kind of authentication.\n\tUnauthenticated,\n\n\t/// The request has been performed with an invalid authentication. This\n\t/// includes expired tokens. Further details can be obtained from the\n\t/// included error.\n\tInvalid(jsonwebtoken::errors::Error),\n\n\t/// The request has been performed with a valid authentication. The claims\n\t/// that were decoded from the token are attached.\n\tAuthenticated(T)\n}\n\nimpl Clone for AuthStatus\nwhere\n\tT: Clone + Send + 'static\n{\n\tfn clone(&self) -> Self {\n\t\t// TODO why is this manually implemented?\n\t\tmatch self {\n\t\t\tSelf::Unknown => Self::Unknown,\n\t\t\tSelf::Unauthenticated => Self::Unauthenticated,\n\t\t\tSelf::Invalid(err) => Self::Invalid(err.clone()),\n\t\t\tSelf::Authenticated(data) => Self::Authenticated(data.clone())\n\t\t}\n\t}\n}\n\nimpl AuthStatus {\n\tpub fn ok(self) -> Result {\n\t\tmatch self {\n\t\t\tSelf::Unknown => Err(AuthError::new(\"The authentication could not be determined\")),\n\t\t\tSelf::Unauthenticated => Err(AuthError::new(\"Missing token\")),\n\t\t\tSelf::Invalid(err) => Err(AuthError::new(format!(\"Invalid token: {err}\"))),\n\t\t\tSelf::Authenticated(data) => Ok(data)\n\t\t}\n\t}\n}\n\n/// The source of the authentication token in the request.\n#[derive(Clone, Debug, StateData)]\npub enum AuthSource {\n\t/// Take the token from a cookie with the given name.\n\tCookie(String),\n\t/// Take the token from a header with the given name.\n\tHeader(HeaderName),\n\t/// Take the token from the HTTP Authorization header. This is different from `Header(\"Authorization\")`\n\t/// as it will follow the `scheme param` format from the HTTP specification. The `scheme` will\n\t/// be discarded, so its value doesn't matter.\n\tAuthorizationHeader\n}\n\n/// This trait will help the auth middleware to determine the validity of an authentication token.\n///\n/// A very basic implementation could look like this:\n///\n/// ```\n/// # use gotham_restful::{AuthHandler, gotham::state::State};\n/// #\n/// const SECRET: &'static [u8; 32] = b\"zlBsA2QXnkmpe0QTh8uCvtAEa4j33YAc\";\n///\n/// struct CustomAuthHandler;\n/// impl AuthHandler for CustomAuthHandler {\n/// \tfn jwt_secret Option>(\n/// \t\t&self,\n/// \t\t_state: &mut State,\n/// \t\t_decode_data: F\n/// \t) -> Option> {\n/// \t\tSome(SECRET.to_vec())\n/// \t}\n/// }\n/// ```\npub trait AuthHandler {\n\t/// Return the SHA256-HMAC secret used to verify the JWT token.\n\tfn jwt_secret Option>(\n\t\t&self,\n\t\tstate: &mut State,\n\t\tdecode_data: F\n\t) -> Option>;\n}\n\n/// An [AuthHandler] returning always the same secret. See [AuthMiddleware] for a usage example.\n#[derive(Clone, Debug)]\npub struct StaticAuthHandler {\n\tsecret: Vec\n}\n\nimpl StaticAuthHandler {\n\tpub fn from_vec(secret: Vec) -> Self {\n\t\tSelf { secret }\n\t}\n\n\tpub fn from_array(secret: &[u8]) -> Self {\n\t\tSelf::from_vec(secret.to_vec())\n\t}\n}\n\nimpl AuthHandler for StaticAuthHandler {\n\tfn jwt_secret Option>(\n\t\t&self,\n\t\t_state: &mut State,\n\t\t_decode_data: F\n\t) -> Option> {\n\t\tSome(self.secret.clone())\n\t}\n}\n\n/// This is the auth middleware. To use it, first make sure you have the `auth` feature enabled. Then\n/// simply add it to your pipeline and request it inside your handler:\n///\n/// ```rust,no_run\n/// # #[macro_use] extern crate gotham_restful_derive;\n/// # use gotham::{router::builder::*, pipeline::*, state::State};\n/// # use gotham_restful::*;\n/// # use serde::{Deserialize, Serialize};\n/// #\n/// #[derive(Resource)]\n/// #[resource(read_all)]\n/// struct AuthResource;\n///\n/// #[derive(Debug, Deserialize, Clone)]\n/// struct AuthData {\n/// \tsub: String,\n/// \texp: u64\n/// }\n///\n/// #[read_all]\n/// fn read_all(auth: &AuthStatus) -> Success {\n/// \tformat!(\"{auth:?}\").into()\n/// }\n///\n/// fn main() {\n/// \tlet auth: AuthMiddleware = AuthMiddleware::new(\n/// \t\tAuthSource::AuthorizationHeader,\n/// \t\tAuthValidation::default(),\n/// \t\tStaticAuthHandler::from_array(b\"zlBsA2QXnkmpe0QTh8uCvtAEa4j33YAc\")\n/// \t);\n/// \tlet (chain, pipelines) = single_pipeline(new_pipeline().add(auth).build());\n/// \tgotham::start(\n/// \t\t\"127.0.0.1:8080\",\n/// \t\tbuild_router(chain, pipelines, |route| {\n/// \t\t\troute.resource::(\"auth\");\n/// \t\t})\n/// \t);\n/// }\n/// ```\n#[derive(Debug)]\npub struct AuthMiddleware {\n\tsource: AuthSource,\n\tvalidation: AuthValidation,\n\thandler: Handler,\n\t_data: PhantomData\n}\n\nimpl Clone for AuthMiddleware\nwhere\n\tHandler: Clone\n{\n\tfn clone(&self) -> Self {\n\t\tSelf {\n\t\t\tsource: self.source.clone(),\n\t\t\tvalidation: self.validation.clone(),\n\t\t\thandler: self.handler.clone(),\n\t\t\t_data: self._data\n\t\t}\n\t}\n}\n\nimpl AuthMiddleware\nwhere\n\tData: DeserializeOwned + Send,\n\tHandler: AuthHandler + Default\n{\n\tpub fn from_source(source: AuthSource) -> Self {\n\t\tSelf {\n\t\t\tsource,\n\t\t\tvalidation: Default::default(),\n\t\t\thandler: Default::default(),\n\t\t\t_data: Default::default()\n\t\t}\n\t}\n}\n\nimpl AuthMiddleware\nwhere\n\tData: DeserializeOwned + Send,\n\tHandler: AuthHandler\n{\n\tpub fn new(source: AuthSource, validation: AuthValidation, handler: Handler) -> Self {\n\t\tSelf {\n\t\t\tsource,\n\t\t\tvalidation,\n\t\t\thandler,\n\t\t\t_data: Default::default()\n\t\t}\n\t}\n\n\tfn auth_status(&self, state: &mut State) -> AuthStatus {\n\t\t// extract the provided token, if any\n\t\tlet token = match &self.source {\n\t\t\tAuthSource::Cookie(name) => CookieJar::try_borrow_from(&state)\n\t\t\t\t.map(|jar| jar.get(&name).map(|cookie| cookie.value().to_owned()))\n\t\t\t\t.unwrap_or_else(|| {\n\t\t\t\t\tCookieParser::from_state(&state)\n\t\t\t\t\t\t.get(&name)\n\t\t\t\t\t\t.map(|cookie| cookie.value().to_owned())\n\t\t\t\t}),\n\t\t\tAuthSource::Header(name) => HeaderMap::try_borrow_from(&state)\n\t\t\t\t.and_then(|map| map.get(name))\n\t\t\t\t.and_then(|header| header.to_str().ok())\n\t\t\t\t.map(|value| value.to_owned()),\n\t\t\tAuthSource::AuthorizationHeader => HeaderMap::try_borrow_from(&state)\n\t\t\t\t.and_then(|map| map.get(AUTHORIZATION))\n\t\t\t\t.and_then(|header| header.to_str().ok())\n\t\t\t\t.and_then(|value| value.split_whitespace().nth(1))\n\t\t\t\t.map(|value| value.to_owned())\n\t\t};\n\n\t\t// unauthed if no token\n\t\tlet token = match token {\n\t\t\tSome(token) => token,\n\t\t\tNone => return AuthStatus::Unauthenticated\n\t\t};\n\n\t\t// get the secret from the handler, possibly decoding claims ourselves\n\t\tlet secret = self.handler.jwt_secret(state, || {\n\t\t\tlet b64 = token.split('.').nth(1)?;\n\t\t\tlet raw = BASE64_URL_SAFE_NO_PAD.decode(b64).ok()?;\n\t\t\tserde_json::from_slice(&raw).ok()?\n\t\t});\n\n\t\t// unknown if no secret\n\t\tlet secret = match secret {\n\t\t\tSome(secret) => secret,\n\t\t\tNone => return AuthStatus::Unknown\n\t\t};\n\n\t\t// validate the token\n\t\tlet data: Data = match jsonwebtoken::decode(\n\t\t\t&token,\n\t\t\t&DecodingKey::from_secret(&secret),\n\t\t\t&self.validation\n\t\t) {\n\t\t\tOk(data) => data.claims,\n\t\t\tErr(e) => return AuthStatus::Invalid(e)\n\t\t};\n\n\t\t// we found a valid token\n\t\tAuthStatus::Authenticated(data)\n\t}\n}\n\nimpl Middleware for AuthMiddleware\nwhere\n\tData: DeserializeOwned + Send + 'static,\n\tHandler: AuthHandler\n{\n\tfn call(self, mut state: State, chain: Chain) -> Pin>\n\twhere\n\t\tChain: FnOnce(State) -> Pin>\n\t{\n\t\t// put the source in our state, required for e.g. openapi\n\t\tstate.put(self.source.clone());\n\n\t\t// put the status in our state\n\t\tlet status = self.auth_status(&mut state);\n\t\tstate.put(status);\n\n\t\t// call the rest of the chain\n\t\tchain(state)\n\t\t\t.and_then(|(state, res)| future::ok((state, res)))\n\t\t\t.boxed()\n\t}\n}\n\nimpl NewMiddleware for AuthMiddleware\nwhere\n\tSelf: Clone + Middleware + Sync + RefUnwindSafe\n{\n\ttype Instance = Self;\n\n\tfn new_middleware(&self) -> anyhow::Result {\n\t\tlet c: Self = self.clone();\n\t\tOk(c)\n\t}\n}\n\n#[cfg(test)]\nmod test {\n\tuse super::*;\n\tuse gotham::{cookie::Cookie, hyper::header::COOKIE};\n\tuse jsonwebtoken::errors::ErrorKind;\n\tuse std::fmt::Debug;\n\n\t// 256-bit random string\n\tconst JWT_SECRET: &'static [u8; 32] = b\"Lyzsfnta0cdxyF0T9y6VGxp3jpgoMUuW\";\n\n\t// some known tokens\n\tconst VALID_TOKEN: &'static str = \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJtc3JkMCIsInN1YiI6ImdvdGhhbS1yZXN0ZnVsIiwiaWF0IjoxNTc3ODM2ODAwLCJleHAiOjQxMDI0NDQ4MDB9.8h8Ax-nnykqEQ62t7CxmM3ja6NzUQ4L0MLOOzddjLKk\";\n\tconst EXPIRED_TOKEN: &'static str = \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJtc3JkMCIsInN1YiI6ImdvdGhhbS1yZXN0ZnVsIiwiaWF0IjoxNTc3ODM2ODAwLCJleHAiOjE1Nzc4MzcxMDB9.eV1snaGLYrJ7qUoMk74OvBY3WUU9M0Je5HTU2xtX1v0\";\n\tconst INVALID_TOKEN: &'static str = \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJtc3JkMCIsInN1YiI6ImdvdGhhbS1yZXN0ZnVsIiwiaWF0IjoxNTc3ODM2ODAwLCJleHAiOjQxMDI0NDQ4MDB9\";\n\n\t#[derive(Debug, Deserialize, PartialEq)]\n\tstruct TestData {\n\t\tiss: String,\n\t\tsub: String,\n\t\tiat: u64,\n\t\texp: u64\n\t}\n\n\timpl Default for TestData {\n\t\tfn default() -> Self {\n\t\t\tSelf {\n\t\t\t\tiss: \"msrd0\".to_owned(),\n\t\t\t\tsub: \"gotham-restful\".to_owned(),\n\t\t\t\tiat: 1577836800,\n\t\t\t\texp: 4102444800\n\t\t\t}\n\t\t}\n\t}\n\n\t#[derive(Default)]\n\tstruct NoneAuthHandler;\n\timpl AuthHandler for NoneAuthHandler {\n\t\tfn jwt_secret Option>(\n\t\t\t&self,\n\t\t\t_state: &mut State,\n\t\t\t_decode_data: F\n\t\t) -> Option> {\n\t\t\tNone\n\t\t}\n\t}\n\n\t#[test]\n\tfn test_auth_middleware_none_secret() {\n\t\tlet middleware = >::from_source(\n\t\t\tAuthSource::AuthorizationHeader\n\t\t);\n\t\tState::with_new(|mut state| {\n\t\t\tlet mut headers = HeaderMap::new();\n\t\t\theaders.insert(\n\t\t\t\tAUTHORIZATION,\n\t\t\t\tformat!(\"Bearer {VALID_TOKEN}\").parse().unwrap()\n\t\t\t);\n\t\t\tstate.put(headers);\n\t\t\tmiddleware.auth_status(&mut state);\n\t\t});\n\t}\n\n\t#[derive(Default)]\n\tstruct TestAssertingHandler;\n\timpl AuthHandler for TestAssertingHandler\n\twhere\n\t\tT: Debug + Default + PartialEq\n\t{\n\t\tfn jwt_secret Option>(\n\t\t\t&self,\n\t\t\t_state: &mut State,\n\t\t\tdecode_data: F\n\t\t) -> Option> {\n\t\t\tassert_eq!(decode_data(), Some(T::default()));\n\t\t\tSome(JWT_SECRET.to_vec())\n\t\t}\n\t}\n\n\t#[test]\n\tfn test_auth_middleware_decode_data() {\n\t\tlet middleware = >::from_source(\n\t\t\tAuthSource::AuthorizationHeader\n\t\t);\n\t\tState::with_new(|mut state| {\n\t\t\tlet mut headers = HeaderMap::new();\n\t\t\theaders.insert(\n\t\t\t\tAUTHORIZATION,\n\t\t\t\tformat!(\"Bearer {VALID_TOKEN}\").parse().unwrap()\n\t\t\t);\n\t\t\tstate.put(headers);\n\t\t\tmiddleware.auth_status(&mut state);\n\t\t});\n\t}\n\n\tfn new_middleware(source: AuthSource) -> AuthMiddleware\n\twhere\n\t\tT: DeserializeOwned + Send\n\t{\n\t\tAuthMiddleware::new(\n\t\t\tsource,\n\t\t\tDefault::default(),\n\t\t\tStaticAuthHandler::from_array(JWT_SECRET)\n\t\t)\n\t}\n\n\t#[test]\n\tfn test_auth_middleware_no_token() {\n\t\tlet middleware = new_middleware::(AuthSource::AuthorizationHeader);\n\t\tState::with_new(|mut state| {\n\t\t\tlet status = middleware.auth_status(&mut state);\n\t\t\tmatch status {\n\t\t\t\tAuthStatus::Unauthenticated => {},\n\t\t\t\t_ => panic!(\"Expected AuthStatus::Unauthenticated, got {status:?}\")\n\t\t\t};\n\t\t});\n\t}\n\n\t#[test]\n\tfn test_auth_middleware_expired_token() {\n\t\tlet middleware = new_middleware::(AuthSource::AuthorizationHeader);\n\t\tState::with_new(|mut state| {\n\t\t\tlet mut headers = HeaderMap::new();\n\t\t\theaders.insert(\n\t\t\t\tAUTHORIZATION,\n\t\t\t\tformat!(\"Bearer {EXPIRED_TOKEN}\").parse().unwrap()\n\t\t\t);\n\t\t\tstate.put(headers);\n\t\t\tlet status = middleware.auth_status(&mut state);\n\t\t\tmatch status {\n\t\t\t\tAuthStatus::Invalid(err) if *err.kind() == ErrorKind::ExpiredSignature => {},\n\t\t\t\t_ => panic!(\n\t\t\t\t\t\"Expected AuthStatus::Invalid(..) with ErrorKind::ExpiredSignature, got {status:?}\"\n\t\t\t\t)\n\t\t\t};\n\t\t});\n\t}\n\n\t#[test]\n\tfn test_auth_middleware_invalid_token() {\n\t\tlet middleware = new_middleware::(AuthSource::AuthorizationHeader);\n\t\tState::with_new(|mut state| {\n\t\t\tlet mut headers = HeaderMap::new();\n\t\t\theaders.insert(\n\t\t\t\tAUTHORIZATION,\n\t\t\t\tformat!(\"Bearer {INVALID_TOKEN}\").parse().unwrap()\n\t\t\t);\n\t\t\tstate.put(headers);\n\t\t\tlet status = middleware.auth_status(&mut state);\n\t\t\tmatch status {\n\t\t\t\tAuthStatus::Invalid(err) if *err.kind() == ErrorKind::InvalidToken => {},\n\t\t\t\t_ => panic!(\n\t\t\t\t\t\"Expected AuthStatus::Invalid(..) with ErrorKind::InvalidToken, got {status:?}\"\n\t\t\t\t)\n\t\t\t};\n\t\t});\n\t}\n\n\t#[test]\n\tfn test_auth_middleware_auth_header_token() {\n\t\tlet middleware = new_middleware::(AuthSource::AuthorizationHeader);\n\t\tState::with_new(|mut state| {\n\t\t\tlet mut headers = HeaderMap::new();\n\t\t\theaders.insert(\n\t\t\t\tAUTHORIZATION,\n\t\t\t\tformat!(\"Bearer {VALID_TOKEN}\").parse().unwrap()\n\t\t\t);\n\t\t\tstate.put(headers);\n\t\t\tlet status = middleware.auth_status(&mut state);\n\t\t\tmatch status {\n\t\t\t\tAuthStatus::Authenticated(data) => assert_eq!(data, TestData::default()),\n\t\t\t\t_ => panic!(\"Expected AuthStatus::Authenticated, got {status:?}\")\n\t\t\t};\n\t\t})\n\t}\n\n\t#[test]\n\tfn test_auth_middleware_header_token() {\n\t\tlet header_name = \"x-znoiprwmvfexju\";\n\t\tlet middleware =\n\t\t\tnew_middleware::(AuthSource::Header(HeaderName::from_static(header_name)));\n\t\tState::with_new(|mut state| {\n\t\t\tlet mut headers = HeaderMap::new();\n\t\t\theaders.insert(header_name, VALID_TOKEN.parse().unwrap());\n\t\t\tstate.put(headers);\n\t\t\tlet status = middleware.auth_status(&mut state);\n\t\t\tmatch status {\n\t\t\t\tAuthStatus::Authenticated(data) => assert_eq!(data, TestData::default()),\n\t\t\t\t_ => panic!(\"Expected AuthStatus::Authenticated, got {status:?}\")\n\t\t\t};\n\t\t})\n\t}\n\n\t#[test]\n\tfn test_auth_middleware_cookie_token() {\n\t\tlet cookie_name = \"znoiprwmvfexju\";\n\t\tlet middleware = new_middleware::(AuthSource::Cookie(cookie_name.to_owned()));\n\t\tState::with_new(|mut state| {\n\t\t\tlet mut jar = CookieJar::new();\n\t\t\tjar.add_original(Cookie::new(cookie_name, VALID_TOKEN));\n\t\t\tstate.put(jar);\n\t\t\tlet status = middleware.auth_status(&mut state);\n\t\t\tmatch status {\n\t\t\t\tAuthStatus::Authenticated(data) => assert_eq!(data, TestData::default()),\n\t\t\t\t_ => panic!(\"Expected AuthStatus::Authenticated, got {status:?}\")\n\t\t\t};\n\t\t})\n\t}\n\n\t#[test]\n\tfn test_auth_middleware_cookie_no_jar() {\n\t\tlet cookie_name = \"znoiprwmvfexju\";\n\t\tlet middleware = new_middleware::(AuthSource::Cookie(cookie_name.to_owned()));\n\t\tState::with_new(|mut state| {\n\t\t\tlet mut headers = HeaderMap::new();\n\t\t\theaders.insert(\n\t\t\t\tCOOKIE,\n\t\t\t\tformat!(\"{cookie_name}={VALID_TOKEN}\").parse().unwrap()\n\t\t\t);\n\t\t\tstate.put(headers);\n\t\t\tlet status = middleware.auth_status(&mut state);\n\t\t\tmatch status {\n\t\t\t\tAuthStatus::Authenticated(data) => assert_eq!(data, TestData::default()),\n\t\t\t\t_ => panic!(\"Expected AuthStatus::Authenticated, got {status:?}\")\n\t\t\t};\n\t\t})\n\t}\n}\n","traces":[{"line":47,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":49,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":50,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":51,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":52,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":53,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":59,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":60,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":61,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":62,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":63,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":64,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":118,"address":[5966160],"length":1,"stats":{"Line":4},"fn_name":null},{"line":122,"address":[5966192],"length":1,"stats":{"Line":4},"fn_name":null},{"line":123,"address":[5966215],"length":1,"stats":{"Line":4},"fn_name":null},{"line":128,"address":[5966301,5966256],"length":1,"stats":{"Line":1},"fn_name":"jwt_secret>"},{"line":133,"address":[5966285,5966339],"length":1,"stats":{"Line":2},"fn_name":null},{"line":188,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":190,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":191,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":192,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":193,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":203,"address":[5966384,5966866,5966640,5966610],"length":1,"stats":{"Line":2},"fn_name":null},{"line":206,"address":[5966426,5966682],"length":1,"stats":{"Line":2},"fn_name":null},{"line":207,"address":[5966735,5966479],"length":1,"stats":{"Line":2},"fn_name":null},{"line":208,"address":[5966524,5966780],"length":1,"stats":{"Line":2},"fn_name":null},{"line":218,"address":[5967156,5967195,5966896],"length":1,"stats":{"Line":4},"fn_name":null},{"line":223,"address":[5967002],"length":1,"stats":{"Line":2},"fn_name":null},{"line":227,"address":[5969975,5969942,5968550,5970000,5968608,5971334,5968583,5971367,5967216],"length":1,"stats":{"Line":6},"fn_name":null},{"line":229,"address":[5968643,5970035,5967251],"length":1,"stats":{"Line":4},"fn_name":null},{"line":230,"address":[5967336,5968687,5967386,5968728,5967295,5970120,5970079,5970170,5968778],"length":1,"stats":{"Line":5},"fn_name":null},{"line":231,"address":[5971552,5971790,5971392,5971662,5971632,5971760,5967320,5970104,5971420,5968712,5971726,5971696,5971500,5971472,5971580],"length":1,"stats":{"Line":5},"fn_name":"{closure#0}"},{"line":232,"address":[5972422,5970141,5968749,5972240,5972214,5971824,5972032,5967357,5972006],"length":1,"stats":{"Line":2},"fn_name":"{closure#1}"},{"line":233,"address":[5972154,5972267,5972059,5971851,5972362,5971946],"length":1,"stats":{"Line":2},"fn_name":null},{"line":234,"address":[5972289,5971873,5972081],"length":1,"stats":{"Line":1},"fn_name":null},{"line":235,"address":[5972542,5972606,5972512,5972478,5972448,5972576],"length":1,"stats":{"Line":2},"fn_name":"{closure#0}"},{"line":237,"address":[5968870,5970262,5968829,5967437,5967478,5970221],"length":1,"stats":{"Line":2},"fn_name":null},{"line":238,"address":[5970246,5968854,5972713,5972761,5972736,5967462,5972665,5972640,5972688],"length":1,"stats":{"Line":3},"fn_name":"{closure#2}"},{"line":239,"address":[5972889,5972784,5972793,5972880,5972841,5972832],"length":1,"stats":{"Line":2},"fn_name":"{closure#3}"},{"line":240,"address":[5972928,5972976,5972998,5973024,5973046,5972950],"length":1,"stats":{"Line":2},"fn_name":"{closure#4}"},{"line":241,"address":[5968906,5970298,5967514],"length":1,"stats":{"Line":4},"fn_name":null},{"line":242,"address":[5973232,5973072,5973081,5973152,5973161,5973241],"length":1,"stats":{"Line":8},"fn_name":"{closure#5}"},{"line":243,"address":[5973312,5973321,5973408,5973417,5973360,5973369],"length":1,"stats":{"Line":6},"fn_name":"{closure#6}"},{"line":244,"address":[5973486,5973520,5973550,5973584,5973456,5973614],"length":1,"stats":{"Line":6},"fn_name":"{closure#7}"},{"line":245,"address":[5973670,5973696,5973718,5973766,5973744,5973648],"length":1,"stats":{"Line":6},"fn_name":"{closure#8}"},{"line":249,"address":[5967564,5968956,5970348],"length":1,"stats":{"Line":4},"fn_name":null},{"line":250,"address":[5969001,5967609,5970393],"length":1,"stats":{"Line":3},"fn_name":null},{"line":251,"address":[5968987,5970379,5967595],"length":1,"stats":{"Line":2},"fn_name":null},{"line":255,"address":[5970451,5969059,5974439,5973792,5967667],"length":1,"stats":{"Line":4},"fn_name":"{closure#9}"},{"line":256,"address":[5974046,5973814],"length":1,"stats":{"Line":1},"fn_name":null},{"line":257,"address":[5973947,5974056,5974153],"length":1,"stats":{"Line":2},"fn_name":null},{"line":258,"address":[5974362,5974224,5973809,5974120],"length":1,"stats":{"Line":3},"fn_name":null},{"line":262,"address":[5967775,5969167,5970559],"length":1,"stats":{"Line":3},"fn_name":null},{"line":263,"address":[5969210,5970602,5967818],"length":1,"stats":{"Line":2},"fn_name":null},{"line":264,"address":[5970593,5967809,5969201],"length":1,"stats":{"Line":1},"fn_name":null},{"line":268,"address":[5968083,5969475,5968134,5969526,5970867,5970918],"length":1,"stats":{"Line":7},"fn_name":null},{"line":269,"address":[5969282,5970674,5967890],"length":1,"stats":{"Line":2},"fn_name":null},{"line":270,"address":[5967990,5970774,5969382],"length":1,"stats":{"Line":3},"fn_name":null},{"line":271,"address":[5968063,5969455,5970847],"length":1,"stats":{"Line":3},"fn_name":null},{"line":273,"address":[5968193,5969585,5970977],"length":1,"stats":{"Line":4},"fn_name":null},{"line":274,"address":[5971064,5969672,5968280],"length":1,"stats":{"Line":1},"fn_name":null},{"line":278,"address":[5968393,5971177,5969785],"length":1,"stats":{"Line":3},"fn_name":null},{"line":287,"address":[6150161,6150993,6152241,6151825,6149719,6150192,6148897,6151856,6151409,6148512,6150577,6149758,6149313,6149344,6151024,6151440,6148928,6150608,6149776],"length":1,"stats":{"Line":1},"fn_name":"call, gotham_restful::routing::MaybeMatchAcceptHeader>, (borrow_bag::handle::Handle, ())>, borrow_bag::handle::Take>, ()), (gotham::pipeline::Pipeline<(gotham_restful::auth::AuthMiddleware, ())>, ()), gotham_restful::endpoint::NoopExtractor, openapi_specification::SecretQuery, fn(&mut gotham::state::State) -> gotham_restful::routing::endpoint_handler::{async_fn_env#0}>, (borrow_bag::handle::Handle, ())>, borrow_bag::handle::Take>, ()), (gotham::pipeline::Pipeline<(gotham_restful::auth::AuthMiddleware, ())>, ())>>"},{"line":292,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":295,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":296,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":299,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":300,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":311,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":312,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":313,"address":[],"length":0,"stats":{"Line":1},"fn_name":null}],"covered":58,"coverable":71},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","cors.rs"],"content":"use gotham::{\n\thandler::HandlerFuture,\n\thelpers::http::response::create_empty_response,\n\thyper::{\n\t\theader::{\n\t\t\tHeaderMap, HeaderName, HeaderValue, ACCESS_CONTROL_ALLOW_CREDENTIALS,\n\t\t\tACCESS_CONTROL_ALLOW_HEADERS, ACCESS_CONTROL_ALLOW_METHODS,\n\t\t\tACCESS_CONTROL_ALLOW_ORIGIN, ACCESS_CONTROL_MAX_AGE, ACCESS_CONTROL_REQUEST_HEADERS,\n\t\t\tACCESS_CONTROL_REQUEST_METHOD, ORIGIN, VARY\n\t\t},\n\t\tBody, Method, Response, StatusCode\n\t},\n\tmiddleware::Middleware,\n\tpipeline::PipelineHandleChain,\n\tprelude::*,\n\trouter::{builder::ExtendRouteMatcher, route::matcher::AccessControlRequestMethodMatcher},\n\tstate::State\n};\nuse std::{panic::RefUnwindSafe, pin::Pin};\n\n/// Specify the allowed origins of the request. It is up to the browser to check the validity of the\n/// origin. This, when sent to the browser, will indicate whether or not the request's origin was\n/// allowed to make the request.\n#[derive(Clone, Debug)]\npub enum Origin {\n\t/// Do not send any `Access-Control-Allow-Origin` headers.\n\tNone,\n\t/// Send `Access-Control-Allow-Origin: *`. Note that browser will not send credentials.\n\tStar,\n\t/// Set the `Access-Control-Allow-Origin` header to a single origin.\n\tSingle(String),\n\t/// Copy the `Origin` header into the `Access-Control-Allow-Origin` header.\n\tCopy\n}\n\nimpl Default for Origin {\n\tfn default() -> Self {\n\t\tSelf::None\n\t}\n}\n\nimpl Origin {\n\t/// Get the header value for the `Access-Control-Allow-Origin` header.\n\tfn header_value(&self, state: &State) -> Option {\n\t\tmatch self {\n\t\t\tSelf::None => None,\n\t\t\tSelf::Star => Some(\"*\".parse().unwrap()),\n\t\t\tSelf::Single(origin) => Some(origin.parse().unwrap()),\n\t\t\tSelf::Copy => {\n\t\t\t\tlet headers = HeaderMap::borrow_from(state);\n\t\t\t\theaders.get(ORIGIN).map(Clone::clone)\n\t\t\t}\n\t\t}\n\t}\n\n\t/// Returns true if the `Vary` header has to include `Origin`.\n\tfn varies(&self) -> bool {\n\t\tmatches!(self, Self::Copy)\n\t}\n}\n\n/// Specify the allowed headers of the request. It is up to the browser to check that only the allowed\n/// headers are sent with the request.\n#[derive(Clone, Debug)]\npub enum Headers {\n\t/// Do not send any `Access-Control-Allow-Headers` headers.\n\tNone,\n\t/// Set the `Access-Control-Allow-Headers` header to the following header list. If empty, this\n\t/// is treated as if it was [None].\n\tList(Vec),\n\t/// Copy the `Access-Control-Request-Headers` header into the `Access-Control-Allow-Header`\n\t/// header.\n\tCopy\n}\n\nimpl Default for Headers {\n\tfn default() -> Self {\n\t\tSelf::None\n\t}\n}\n\nimpl Headers {\n\t/// Get the header value for the `Access-Control-Allow-Headers` header.\n\tfn header_value(&self, state: &State) -> Option {\n\t\tmatch self {\n\t\t\tSelf::None => None,\n\t\t\tSelf::List(list) => Some(list.join(\",\").parse().unwrap()),\n\t\t\tSelf::Copy => {\n\t\t\t\tlet headers = HeaderMap::borrow_from(state);\n\t\t\t\theaders\n\t\t\t\t\t.get(ACCESS_CONTROL_REQUEST_HEADERS)\n\t\t\t\t\t.map(Clone::clone)\n\t\t\t}\n\t\t}\n\t}\n\n\t/// Returns true if the `Vary` header has to include `Origin`.\n\tfn varies(&self) -> bool {\n\t\tmatches!(self, Self::Copy)\n\t}\n}\n\n/// This is the configuration that the CORS handler will follow. Its default configuration is basically\n/// not to touch any responses, resulting in the browser's default behaviour.\n///\n/// To change settings, you need to put this type into gotham's [State]:\n///\n/// ```rust,no_run\n/// # use gotham::{router::builder::*, pipeline::*, state::State};\n/// # use gotham_restful::{*, cors::Origin};\n/// # #[cfg_attr(feature = \"cargo-clippy\", allow(clippy::needless_doctest_main))]\n/// fn main() {\n/// \tlet cors = CorsConfig {\n/// \t\torigin: Origin::Star,\n/// \t\t..Default::default()\n/// \t};\n/// \tlet (chain, pipelines) = single_pipeline(new_pipeline().add(cors).build());\n/// \tgotham::start(\n/// \t\t\"127.0.0.1:8080\",\n/// \t\tbuild_router(chain, pipelines, |route| {\n/// \t\t\t// your routing logic\n/// \t\t})\n/// \t);\n/// }\n/// ```\n///\n/// This easy approach allows you to have one global cors configuration. If you prefer to have separate\n/// configurations for different scopes, you need to register the middleware inside your routing logic:\n///\n/// ```rust,no_run\n/// # use gotham::{router::builder::*, pipeline::*, state::State};\n/// # use gotham_restful::{*, cors::Origin};\n/// let pipelines = new_pipeline_set();\n///\n/// // The first cors configuration\n/// let cors_a = CorsConfig {\n/// \torigin: Origin::Star,\n/// \t..Default::default()\n/// };\n/// let (pipelines, chain_a) = pipelines.add(new_pipeline().add(cors_a).build());\n///\n/// // The second cors configuration\n/// let cors_b = CorsConfig {\n/// \torigin: Origin::Copy,\n/// \t..Default::default()\n/// };\n/// let (pipelines, chain_b) = pipelines.add(new_pipeline().add(cors_b).build());\n///\n/// let pipeline_set = finalize_pipeline_set(pipelines);\n/// gotham::start(\n/// \t\"127.0.0.1:8080\",\n/// \tbuild_router((), pipeline_set, |route| {\n/// \t\t// routing without any cors config\n/// \t\troute.with_pipeline_chain((chain_a, ()), |route| {\n/// \t\t\t// routing with cors config a\n/// \t\t});\n/// \t\troute.with_pipeline_chain((chain_b, ()), |route| {\n/// \t\t\t// routing with cors config b\n/// \t\t});\n/// \t})\n/// );\n/// ```\n#[derive(Clone, Debug, Default, NewMiddleware, StateData)]\npub struct CorsConfig {\n\t/// The allowed origins.\n\tpub origin: Origin,\n\t/// The allowed headers.\n\tpub headers: Headers,\n\t/// The amount of seconds that the preflight request can be cached.\n\tpub max_age: u64,\n\t/// Whether or not the request may be made with supplying credentials.\n\tpub credentials: bool\n}\n\nimpl Middleware for CorsConfig {\n\tfn call(self, mut state: State, chain: Chain) -> Pin>\n\twhere\n\t\tChain: FnOnce(State) -> Pin>\n\t{\n\t\tstate.put(self);\n\t\tchain(state)\n\t}\n}\n\n/// Handle CORS for a non-preflight request. This means manipulating the `res` HTTP headers so that\n/// the response is aligned with the `state`'s [CorsConfig].\n///\n/// If you are using the [Resource](crate::Resource) type (which is the recommended way), you'll never\n/// have to call this method. However, if you are writing your own handler method, you might want to\n/// call this after your request to add the required CORS headers.\n///\n/// For further information on CORS, read .\npub fn handle_cors(state: &State, res: &mut Response) {\n\tlet config = CorsConfig::try_borrow_from(state);\n\tif let Some(cfg) = config {\n\t\tlet headers = res.headers_mut();\n\n\t\t// non-preflight requests require the Access-Control-Allow-Origin header\n\t\tif let Some(header) = cfg.origin.header_value(state) {\n\t\t\theaders.insert(ACCESS_CONTROL_ALLOW_ORIGIN, header);\n\t\t}\n\n\t\t// if the origin is copied over, we should tell the browser by specifying the Vary header\n\t\tif cfg.origin.varies() {\n\t\t\tlet vary = headers\n\t\t\t\t.get(VARY)\n\t\t\t\t.map(|vary| format!(\"{},origin\", vary.to_str().unwrap()));\n\t\t\theaders.insert(VARY, vary.as_deref().unwrap_or(\"origin\").parse().unwrap());\n\t\t}\n\n\t\t// if we allow credentials, tell the browser\n\t\tif cfg.credentials {\n\t\t\theaders.insert(\n\t\t\t\tACCESS_CONTROL_ALLOW_CREDENTIALS,\n\t\t\t\tHeaderValue::from_static(\"true\")\n\t\t\t);\n\t\t}\n\t}\n}\n\n/// Add CORS routing for your path. This is required for handling preflight requests.\n///\n/// Example:\n///\n/// ```rust,no_run\n/// # use gotham::{hyper::{Body, Method, Response}, router::builder::*};\n/// # use gotham_restful::*;\n/// build_simple_router(|router| {\n/// \t// The handler that needs preflight handling\n/// \trouter.post(\"/foo\").to(|state| {\n/// \t\tlet mut res: Response = unimplemented!();\n/// \t\thandle_cors(&state, &mut res);\n/// \t\t(state, res)\n/// \t});\n/// \t// Add preflight handling\n/// \trouter.cors(\"/foo\", Method::POST);\n/// });\n/// ```\npub trait CorsRoute\nwhere\n\tC: PipelineHandleChain

+ Copy + Send + Sync + 'static,\n\tP: RefUnwindSafe + Send + Sync + 'static\n{\n\t/// Handle a preflight request on `path` for `method`. To configure the behaviour, use\n\t/// [CorsConfig].\n\tfn cors(&mut self, path: &str, method: Method);\n}\n\npub(crate) fn cors_preflight_handler(state: State) -> (State, Response) {\n\tlet config = CorsConfig::try_borrow_from(&state);\n\n\t// prepare the response\n\tlet mut res = create_empty_response(&state, StatusCode::NO_CONTENT);\n\tlet headers = res.headers_mut();\n\tlet mut vary: Vec = Vec::new();\n\n\t// copy the request method over to the response\n\tlet method = HeaderMap::borrow_from(&state)\n\t\t.get(ACCESS_CONTROL_REQUEST_METHOD)\n\t\t.unwrap()\n\t\t.clone();\n\theaders.insert(ACCESS_CONTROL_ALLOW_METHODS, method);\n\tvary.push(ACCESS_CONTROL_REQUEST_METHOD);\n\n\tif let Some(cfg) = config {\n\t\t// if we allow any headers, copy them over\n\t\tif let Some(header) = cfg.headers.header_value(&state) {\n\t\t\theaders.insert(ACCESS_CONTROL_ALLOW_HEADERS, header);\n\t\t}\n\n\t\t// if the headers are copied over, we should tell the browser by specifying the Vary header\n\t\tif cfg.headers.varies() {\n\t\t\tvary.push(ACCESS_CONTROL_REQUEST_HEADERS);\n\t\t}\n\n\t\t// set the max age for the preflight cache\n\t\tif let Some(age) = config.map(|cfg| cfg.max_age) {\n\t\t\theaders.insert(ACCESS_CONTROL_MAX_AGE, age.into());\n\t\t}\n\t}\n\n\t// make sure the browser knows that this request was based on the method\n\theaders.insert(VARY, vary.join(\",\").parse().unwrap());\n\n\thandle_cors(&state, &mut res);\n\t(state, res)\n}\n\nimpl CorsRoute for D\nwhere\n\tD: DrawRoutes,\n\tC: PipelineHandleChain

+ Copy + Send + Sync + 'static,\n\tP: RefUnwindSafe + Send + Sync + 'static\n{\n\tfn cors(&mut self, path: &str, method: Method) {\n\t\tlet matcher = AccessControlRequestMethodMatcher::new(method);\n\t\tself.options(path)\n\t\t\t.extend_route_matcher(matcher)\n\t\t\t.to(cors_preflight_handler);\n\t}\n}\n","traces":[{"line":37,"address":[6396960],"length":1,"stats":{"Line":1},"fn_name":"default"},{"line":38,"address":[6396963],"length":1,"stats":{"Line":3},"fn_name":null},{"line":44,"address":[6396976],"length":1,"stats":{"Line":1},"fn_name":null},{"line":45,"address":[6397018],"length":1,"stats":{"Line":3},"fn_name":null},{"line":46,"address":[6397054],"length":1,"stats":{"Line":1},"fn_name":null},{"line":47,"address":[6397063],"length":1,"stats":{"Line":1},"fn_name":null},{"line":48,"address":[6397139],"length":1,"stats":{"Line":1},"fn_name":null},{"line":50,"address":[6397225],"length":1,"stats":{"Line":1},"fn_name":null},{"line":51,"address":[6397242],"length":1,"stats":{"Line":1},"fn_name":null},{"line":57,"address":[6397344],"length":1,"stats":{"Line":1},"fn_name":null},{"line":58,"address":[6397349],"length":1,"stats":{"Line":3},"fn_name":null},{"line":77,"address":[6397376],"length":1,"stats":{"Line":1},"fn_name":"default"},{"line":78,"address":[6397379],"length":1,"stats":{"Line":3},"fn_name":null},{"line":84,"address":[6397816,6397392],"length":1,"stats":{"Line":1},"fn_name":null},{"line":85,"address":[6397435],"length":1,"stats":{"Line":3},"fn_name":null},{"line":86,"address":[6397472],"length":1,"stats":{"Line":1},"fn_name":null},{"line":87,"address":[6397682,6397486],"length":1,"stats":{"Line":1},"fn_name":null},{"line":89,"address":[6397565],"length":1,"stats":{"Line":1},"fn_name":null},{"line":90,"address":[6397642],"length":1,"stats":{"Line":1},"fn_name":null},{"line":91,"address":[6397582],"length":1,"stats":{"Line":1},"fn_name":null},{"line":98,"address":[6397856],"length":1,"stats":{"Line":1},"fn_name":null},{"line":99,"address":[6397861],"length":1,"stats":{"Line":1},"fn_name":null},{"line":176,"address":[6652028,6652504,6651856,6652280,6652056,6652080,6652304,6652252,6652476],"length":1,"stats":{"Line":3},"fn_name":"call, gotham_restful::routing::MaybeMatchAcceptHeader>, (borrow_bag::handle::Handle, borrow_bag::handle::Take>, ()), (gotham::pipeline::Pipeline<(gotham_restful::cors::CorsConfig, ())>, ()), gotham_restful::endpoint::NoopExtractor, gotham_restful::endpoint::NoopExtractor, fn(&mut gotham::state::State) -> gotham_restful::routing::endpoint_handler::{async_fn_env#0}>, (borrow_bag::handle::Handle, borrow_bag::handle::Take>, ()), (gotham::pipeline::Pipeline<(gotham_restful::cors::CorsConfig, ())>, ())>>"},{"line":180,"address":[],"length":0,"stats":{"Line":3},"fn_name":null},{"line":181,"address":[],"length":0,"stats":{"Line":10},"fn_name":null},{"line":193,"address":[6397888,6398911,6398945],"length":1,"stats":{"Line":7},"fn_name":"handle_cors"},{"line":194,"address":[6397921],"length":1,"stats":{"Line":5},"fn_name":null},{"line":195,"address":[6397955],"length":1,"stats":{"Line":7},"fn_name":null},{"line":196,"address":[6398004],"length":1,"stats":{"Line":1},"fn_name":null},{"line":199,"address":[6398090,6398033],"length":1,"stats":{"Line":4},"fn_name":null},{"line":200,"address":[6398123],"length":1,"stats":{"Line":1},"fn_name":null},{"line":204,"address":[6398269],"length":1,"stats":{"Line":3},"fn_name":null},{"line":205,"address":[6398352],"length":1,"stats":{"Line":1},"fn_name":null},{"line":206,"address":[6398322],"length":1,"stats":{"Line":1},"fn_name":null},{"line":207,"address":[6399116,6398992,6399025],"length":1,"stats":{"Line":3},"fn_name":"{closure#0}"},{"line":208,"address":[6398395,6398956],"length":1,"stats":{"Line":1},"fn_name":null},{"line":212,"address":[6398302],"length":1,"stats":{"Line":1},"fn_name":null},{"line":213,"address":[6398841],"length":1,"stats":{"Line":1},"fn_name":null},{"line":214,"address":[6398737],"length":1,"stats":{"Line":1},"fn_name":null},{"line":215,"address":[6398775],"length":1,"stats":{"Line":1},"fn_name":null},{"line":249,"address":[6401126,6400524,6399200],"length":1,"stats":{"Line":1},"fn_name":"cors_preflight_handler"},{"line":250,"address":[6399236,6399353],"length":1,"stats":{"Line":4},"fn_name":null},{"line":253,"address":[6399361],"length":1,"stats":{"Line":3},"fn_name":null},{"line":254,"address":[6399393,6399463],"length":1,"stats":{"Line":4},"fn_name":null},{"line":255,"address":[6399479],"length":1,"stats":{"Line":1},"fn_name":null},{"line":258,"address":[6399491,6399579],"length":1,"stats":{"Line":6},"fn_name":null},{"line":259,"address":[6399549],"length":1,"stats":{"Line":1},"fn_name":null},{"line":262,"address":[6399652],"length":1,"stats":{"Line":1},"fn_name":null},{"line":263,"address":[6399736],"length":1,"stats":{"Line":3},"fn_name":null},{"line":265,"address":[6399789],"length":1,"stats":{"Line":1},"fn_name":null},{"line":267,"address":[6399852,6399925],"length":1,"stats":{"Line":4},"fn_name":null},{"line":268,"address":[6400019,6400111],"length":1,"stats":{"Line":2},"fn_name":null},{"line":272,"address":[6400153,6400187],"length":1,"stats":{"Line":2},"fn_name":null},{"line":273,"address":[6400218],"length":1,"stats":{"Line":1},"fn_name":null},{"line":277,"address":[6401168,6400193,6400283,6401173],"length":1,"stats":{"Line":7},"fn_name":"{closure#0}"},{"line":278,"address":[6400330],"length":1,"stats":{"Line":1},"fn_name":null},{"line":283,"address":[6401082,6399859,6400535],"length":1,"stats":{"Line":3},"fn_name":null},{"line":285,"address":[6400897],"length":1,"stats":{"Line":1},"fn_name":null},{"line":286,"address":[6400909],"length":1,"stats":{"Line":2},"fn_name":null},{"line":295,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":296,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":297,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":298,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":299,"address":[],"length":0,"stats":{"Line":0},"fn_name":null}],"covered":59,"coverable":64},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","endpoint.rs"],"content":"use crate::{IntoResponse, RequestBody};\nuse futures_util::future::BoxFuture;\nuse gotham::{\n\textractor::{PathExtractor, QueryStringExtractor},\n\thyper::{Body, Method, Response},\n\trouter::response::StaticResponseExtender,\n\tstate::{State, StateData}\n};\n#[cfg(feature = \"openapi\")]\nuse openapi_type::{OpenapiType, Visitor};\nuse serde::{Deserialize, Deserializer};\nuse std::borrow::Cow;\n\n/// A no-op extractor that can be used as a default type for [Endpoint::Placeholders] and\n/// [Endpoint::Params].\n#[derive(Debug, Clone, Copy)]\npub struct NoopExtractor;\n\nimpl<'de> Deserialize<'de> for NoopExtractor {\n\tfn deserialize>(_: D) -> Result {\n\t\tOk(Self)\n\t}\n}\n\n#[cfg(feature = \"openapi\")]\nimpl OpenapiType for NoopExtractor {\n\tfn visit_type(visitor: &mut V) {\n\t\twarn!(\n\t\t\t\"You're asking for the OpenAPI Schema for gotham_restful::NoopExtractor. This is probably not what you want.\"\n\t\t);\n\t\tvisitor.visit_unit();\n\t}\n}\n\nimpl StateData for NoopExtractor {}\n\nimpl StaticResponseExtender for NoopExtractor {\n\ttype ResBody = Body;\n\tfn extend(_: &mut State, _: &mut Response) {}\n}\n\n// TODO: Specify default types once https://github.com/rust-lang/rust/issues/29661 lands.\n#[_private_openapi_trait(EndpointWithSchema)]\npub trait Endpoint {\n\t/// The HTTP Verb of this endpoint.\n\tfn http_method() -> Method;\n\t/// The URI that this endpoint listens on in gotham's format.\n\tfn uri() -> Cow<'static, str>;\n\n\t/// The verb used for generating an operation id if [Self::operation_id] returns [None].\n\t/// For example `read`, `read_all`, `create`, `update` etc.\n\t#[openapi_only]\n\tfn operation_verb() -> Option<&'static str>;\n\n\t/// The output type that provides the response.\n\t#[openapi_bound(Output: crate::ResponseSchema)]\n\ttype Output: IntoResponse + Send;\n\n\t/// Returns `true` _iff_ the URI contains placeholders. `false` by default.\n\tfn has_placeholders() -> bool {\n\t\tfalse\n\t}\n\t/// The type that parses the URI placeholders. Use [NoopExtractor] if `has_placeholders()`\n\t/// returns `false`.\n\t#[openapi_bound(Placeholders: OpenapiType)]\n\ttype Placeholders: PathExtractor + Clone + Sync;\n\n\t/// Returns `true` _iff_ the request parameters should be parsed. `false` by default.\n\tfn needs_params() -> bool {\n\t\tfalse\n\t}\n\t/// The type that parses the request parameters. Use [NoopExtractor] if `needs_params()`\n\t/// returns `false`.\n\t#[openapi_bound(Params: OpenapiType)]\n\ttype Params: QueryStringExtractor + Clone + Sync;\n\n\t/// Returns `true` _iff_ the request body should be parsed. `false` by default.\n\tfn needs_body() -> bool {\n\t\tfalse\n\t}\n\t/// The type to parse the body into. Use `()` if `needs_body()` returns `false`.\n\ttype Body: RequestBody + Send;\n\n\t/// Returns `true` if the request wants to know the auth status of the client. `false` by default.\n\tfn wants_auth() -> bool {\n\t\tfalse\n\t}\n\n\t/// Replace the automatically generated operation id with a custom one. Only relevant for the\n\t/// OpenAPI Specification.\n\t#[openapi_only]\n\tfn operation_id() -> Option {\n\t\tNone\n\t}\n\n\t/// Add a description to the openapi specification. Usually taken from the rustdoc comment\n\t/// when using the proc macro.\n\t#[openapi_only]\n\tfn description() -> Option {\n\t\tNone\n\t}\n\n\t/// The handler for this endpoint.\n\tfn handle(\n\t\tstate: &mut State,\n\t\tplaceholders: Self::Placeholders,\n\t\tparams: Self::Params,\n\t\tbody: Option\n\t) -> BoxFuture<'_, Self::Output>;\n}\n\n#[cfg(feature = \"openapi\")]\nimpl Endpoint for E {\n\tfn http_method() -> Method {\n\t\tE::http_method()\n\t}\n\tfn uri() -> Cow<'static, str> {\n\t\tE::uri()\n\t}\n\n\ttype Output = E::Output;\n\n\tfn has_placeholders() -> bool {\n\t\tE::has_placeholders()\n\t}\n\ttype Placeholders = E::Placeholders;\n\n\tfn needs_params() -> bool {\n\t\tE::needs_params()\n\t}\n\ttype Params = E::Params;\n\n\tfn needs_body() -> bool {\n\t\tE::needs_body()\n\t}\n\ttype Body = E::Body;\n\n\tfn wants_auth() -> bool {\n\t\tE::wants_auth()\n\t}\n\n\tfn handle<'a>(\n\t\tstate: &'a mut State,\n\t\tplaceholders: Self::Placeholders,\n\t\tparams: Self::Params,\n\t\tbody: Option\n\t) -> BoxFuture<'a, Self::Output> {\n\t\tE::handle(state, placeholders, params, body)\n\t}\n}\n","traces":[{"line":20,"address":[],"length":0,"stats":{"Line":10},"fn_name":null},{"line":21,"address":[6248659,6248697],"length":1,"stats":{"Line":10},"fn_name":null},{"line":27,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":28,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":31,"address":[7748400],"length":1,"stats":{"Line":0},"fn_name":null},{"line":39,"address":[7748544,7748554],"length":1,"stats":{"Line":0},"fn_name":"extend"},{"line":60,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":61,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":69,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":70,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":78,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":79,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":85,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":86,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":92,"address":[6787536],"length":1,"stats":{"Line":6},"fn_name":"operation_id"},{"line":93,"address":[6787539],"length":1,"stats":{"Line":6},"fn_name":null},{"line":99,"address":[6787520],"length":1,"stats":{"Line":7},"fn_name":"description"},{"line":100,"address":[6787523],"length":1,"stats":{"Line":7},"fn_name":null},{"line":114,"address":[6790416],"length":1,"stats":{"Line":30},"fn_name":"http_method"},{"line":115,"address":[],"length":0,"stats":{"Line":30},"fn_name":null},{"line":117,"address":[],"length":0,"stats":{"Line":30},"fn_name":null},{"line":118,"address":[],"length":0,"stats":{"Line":30},"fn_name":null},{"line":123,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":124,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":128,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":129,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":133,"address":[],"length":0,"stats":{"Line":21},"fn_name":null},{"line":134,"address":[],"length":0,"stats":{"Line":21},"fn_name":null},{"line":138,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":139,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":142,"address":[6790480],"length":1,"stats":{"Line":21},"fn_name":"handle"},{"line":148,"address":[],"length":0,"stats":{"Line":21},"fn_name":null}],"covered":14,"coverable":32},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","lib.rs"],"content":"#![warn(missing_debug_implementations, rust_2018_idioms, unreachable_pub)]\n#![forbid(unsafe_code)]\n// deny warnings in CI\n#![cfg_attr(gotham_restful_deny_warnings, deny(warnings))]\n// clippy doesn't like our code style\n#![cfg_attr(feature = \"cargo-clippy\", allow(clippy::tabs_in_doc_comments))]\n// intra-doc links only fully work when OpenAPI is enabled\n#![cfg_attr(feature = \"openapi\", deny(rustdoc::broken_intra_doc_links))]\n#![cfg_attr(not(feature = \"openapi\"), allow(rustdoc::broken_intra_doc_links))]\n\n//! This crate is an extension to the popular [gotham web framework][gotham] for Rust. It allows you to\n//! create resources with assigned endpoints that aim to be a more convenient way of creating handlers\n//! for requests.\n//!\n//! # Features\n//!\n//! - Automatically parse **JSON** request and produce response bodies\n//! - Allow using **raw** request and response bodies\n//! - Convenient **macros** to create responses that can be registered with gotham's router\n//! - Auto-Generate an **OpenAPI** specification for your API\n//! - Manage **CORS** headers so you don't have to\n//! - Manage **Authentication** with JWT\n//! - Integrate diesel connection pools for easy **database** integration\n//!\n//! # Safety\n//!\n//! This crate is just as safe as you'd expect from anything written in safe Rust - and\n//! `#![forbid(unsafe_code)]` ensures that no unsafe was used.\n//!\n//! # Endpoints\n//!\n//! There are a set of pre-defined endpoints that should cover the majority of REST APIs. However,\n//! it is also possible to define your own endpoints.\n//!\n//! ## Pre-defined Endpoints\n//!\n//! Assuming you assign `/foobar` to your resource, the following pre-defined endpoints exist:\n//!\n//! | Endpoint Name | Required Arguments | HTTP Verb | HTTP Path |\n//! | ------------- | ------------------ | --------- | -------------- |\n//! | read_all | | GET | /foobar |\n//! | read | id | GET | /foobar/:id |\n//! | search | query | GET | /foobar/search |\n//! | create | body | POST | /foobar |\n//! | update_all | body | PUT | /foobar |\n//! | update | id, body | PUT | /foobar/:id |\n//! | delete_all | | DELETE | /foobar |\n//! | delete | id | DELETE | /foobar/:id |\n//!\n//! Each of those endpoints has a macro that creates the neccessary boilerplate for the Resource. A\n//! simple example looks like this:\n//!\n//! ```rust,no_run\n//! # #[macro_use] extern crate gotham_restful_derive;\n//! # use gotham::router::builder::*;\n//! # use gotham_restful::*;\n//! # use serde::{Deserialize, Serialize};\n//! /// Our RESTful resource.\n//! #[derive(Resource)]\n//! #[resource(read)]\n//! struct FooResource;\n//!\n//! /// The return type of the foo read endpoint.\n//! #[derive(Serialize)]\n//! # #[cfg_attr(feature = \"openapi\", derive(openapi_type::OpenapiType))]\n//! struct Foo {\n//! \tid: u64\n//! }\n//!\n//! /// The foo read endpoint.\n//! #[read]\n//! fn read(id: u64) -> Success {\n//! \tFoo { id }.into()\n//! }\n//! # fn main() {\n//! # \tgotham::start(\"127.0.0.1:8080\", build_simple_router(|route| {\n//! # \t\troute.resource::(\"foo\");\n//! # \t})).expect(\"Failed to start gotham\");\n//! # }\n//! ```\n//!\n//! ## Custom Endpoints\n//!\n//! Defining custom endpoints is done with the `#[endpoint]` macro. The syntax is similar to that\n//! of the pre-defined endpoints, but you need to give it more context:\n//!\n//! ```rust,no_run\n//! # #[macro_use] extern crate gotham_restful_derive;\n//! # use gotham::{router::build_simple_router, prelude::*};\n//! # use gotham_restful::*;\n//! # use serde::{Deserialize, Serialize};\n//! use gotham_restful::gotham::hyper::Method;\n//!\n//! #[derive(Resource)]\n//! #[resource(custom_endpoint)]\n//! struct CustomResource;\n//!\n//! /// This type is used to parse path parameters.\n//! #[derive(Clone, Deserialize, StateData, StaticResponseExtender)]\n//! # #[cfg_attr(feature = \"openapi\", derive(openapi_type::OpenapiType))]\n//! struct CustomPath {\n//! \tname: String\n//! }\n//!\n//! #[endpoint(\n//! \turi = \"custom/:name/read\",\n//! \tmethod = \"Method::GET\",\n//! \tparams = false,\n//! \tbody = false\n//! )]\n//! fn custom_endpoint(path: CustomPath) -> Success {\n//! \tpath.name.into()\n//! }\n//! # fn main() {\n//! # \tgotham::start(\"127.0.0.1:8080\", build_simple_router(|route| {\n//! # \t\troute.resource::(\"custom\");\n//! # \t})).expect(\"Failed to start gotham\");\n//! # }\n//! ```\n//!\n//! # Arguments\n//!\n//! Some endpoints require arguments. Those should be\n//! * **id** Should be a deserializable json-primitive like [`i64`] or [`String`].\n//! * **body** Should be any deserializable object, or any type implementing [`RequestBody`].\n//! * **query** Should be any deserializable object whose variables are json-primitives. It will\n//! however not be parsed from json, but from HTTP GET parameters like in `search?id=1`. The\n//! type needs to implement [`QueryStringExtractor`](gotham::extractor::QueryStringExtractor).\n//!\n//! Additionally, all handlers may take a reference to gotham's [`State`]. Please note that for async\n//! handlers, it needs to be a mutable reference until rustc's lifetime checks across await bounds\n//! improve.\n//!\n//! # Uploads and Downloads\n//!\n//! By default, every request body is parsed from json, and every respone is converted to json using\n//! [serde_json]. However, you may also use raw bodies. This is an example where the request body\n//! is simply returned as the response again, no json parsing involved:\n//!\n//! ```rust,no_run\n//! # #[macro_use] extern crate gotham_restful_derive;\n//! # use gotham::{mime::{self, Mime}, router::builder::*};\n//! # use gotham_restful::*;\n//! # use serde::{Deserialize, Serialize};\n//! #[derive(Resource)]\n//! #[resource(create)]\n//! struct ImageResource;\n//!\n//! #[derive(FromBody, RequestBody)]\n//! #[supported_types(mime::IMAGE_GIF, mime::IMAGE_JPEG, mime::IMAGE_PNG)]\n//! struct RawImage {\n//! \tcontent: Vec,\n//! \tcontent_type: Mime\n//! }\n//!\n//! #[create]\n//! fn create(body: RawImage) -> Raw> {\n//! \tRaw::new(body.content, body.content_type)\n//! }\n//! # fn main() {\n//! # \tgotham::start(\"127.0.0.1:8080\", build_simple_router(|route| {\n//! # \t\troute.resource::(\"image\");\n//! # \t})).expect(\"Failed to start gotham\");\n//! # }\n//! ```\n//!\n//! # Custom HTTP Headers\n//!\n//! You can read request headers from the state as you would in any other gotham handler, and specify\n//! custom response headers using [Response::header].\n//!\n//! ```rust,no_run\n//! # #[macro_use] extern crate gotham_restful_derive;\n//! # use gotham::hyper::header::{ACCEPT, HeaderMap, VARY};\n//! # use gotham::{router::builder::*, state::State};\n//! # use gotham_restful::*;\n//! #[derive(Resource)]\n//! #[resource(read_all)]\n//! struct FooResource;\n//!\n//! #[read_all]\n//! async fn read_all(state: &mut State) -> NoContent {\n//! \tlet headers: &HeaderMap = state.borrow();\n//! \tlet accept = &headers[ACCEPT];\n//! # drop(accept);\n//!\n//! \tlet mut res = NoContent::default();\n//! \tres.header(VARY, \"accept\".parse().unwrap());\n//! \tres\n//! }\n//! # fn main() {\n//! # \tgotham::start(\"127.0.0.1:8080\", build_simple_router(|route| {\n//! # \t\troute.resource::(\"foo\");\n//! # \t})).expect(\"Failed to start gotham\");\n//! # }\n//! ```\n//!\n//! # Features\n//!\n//! To make life easier for common use-cases, this create offers a few features that might be helpful\n//! when you implement your web server. The complete feature list is\n//! - [`auth`](#authentication-feature) Advanced JWT middleware\n//! - [`cors`](#cors-feature) CORS handling for all endpoint handlers\n//! - [`database`](#database-feature) diesel middleware support\n//! - `errorlog` log errors returned from endpoint handlers\n//! - `full` enables all features except `without-openapi`\n//! - [`openapi`](#openapi-feature) router additions to generate an openapi spec\n//! - `without-openapi` (**default**) disables `openapi` support.\n//!\n//! ## Authentication Feature\n//!\n//! In order to enable authentication support, enable the `auth` feature gate. This allows you to\n//! register a middleware that can automatically check for the existence of an JWT authentication\n//! token. Besides being supported by the endpoint macros, it supports to lookup the required JWT secret\n//! with the JWT data, hence you can use several JWT secrets and decide on the fly which secret to use.\n//! None of this is currently supported by gotham's own JWT middleware.\n//!\n//! A simple example that uses only a single secret looks like this:\n//!\n//! ```rust,no_run\n//! # #[macro_use] extern crate gotham_restful_derive;\n//! # #[cfg(feature = \"auth\")]\n//! # mod auth_feature_enabled {\n//! # use gotham::{router::builder::*, pipeline::*, state::State};\n//! # use gotham_restful::*;\n//! # use serde::{Deserialize, Serialize};\n//! #[derive(Resource)]\n//! #[resource(read)]\n//! struct SecretResource;\n//!\n//! #[derive(Serialize)]\n//! # #[cfg_attr(feature = \"openapi\", derive(openapi_type::OpenapiType))]\n//! struct Secret {\n//! \tid: u64,\n//! \tintended_for: String\n//! }\n//!\n//! #[derive(Deserialize, Clone)]\n//! struct AuthData {\n//! \tsub: String,\n//! \texp: u64\n//! }\n//!\n//! #[read]\n//! fn read(auth: AuthStatus, id: u64) -> AuthSuccess {\n//! \tlet intended_for = auth.ok()?.sub;\n//! \tOk(Secret { id, intended_for })\n//! }\n//!\n//! fn main() {\n//! \tlet auth: AuthMiddleware = AuthMiddleware::new(\n//! \t\tAuthSource::AuthorizationHeader,\n//! \t\tAuthValidation::default(),\n//! \t\tStaticAuthHandler::from_array(b\"zlBsA2QXnkmpe0QTh8uCvtAEa4j33YAc\")\n//! \t);\n//! \tlet (chain, pipelines) = single_pipeline(new_pipeline().add(auth).build());\n//! \tgotham::start(\n//! \t\t\"127.0.0.1:8080\",\n//! \t\tbuild_router(chain, pipelines, |route| {\n//! \t\t\troute.resource::(\"secret\");\n//! \t\t})\n//! \t)\n//! \t.expect(\"Failed to start gotham\");\n//! }\n//! # }\n//! ```\n//!\n//! ## CORS Feature\n//!\n//! The cors feature allows an easy usage of this web server from other origins. By default, only\n//! the `Access-Control-Allow-Methods` header is touched. To change the behaviour, add your desired\n//! configuration as a middleware.\n//!\n//! A simple example that allows authentication from every origin (note that `*` always disallows\n//! authentication), and every content type, looks like this:\n//!\n//! ```rust,no_run\n//! # #[macro_use] extern crate gotham_restful_derive;\n//! # #[cfg(feature = \"cors\")]\n//! # mod cors_feature_enabled {\n//! # use gotham::{hyper::header::*, router::builder::*, pipeline::*, state::State};\n//! # use gotham_restful::{*, cors::*};\n//! # use serde::{Deserialize, Serialize};\n//! #[derive(Resource)]\n//! #[resource(read_all)]\n//! struct FooResource;\n//!\n//! #[read_all]\n//! fn read_all() {\n//! \t// your handler\n//! }\n//!\n//! fn main() {\n//! \tlet cors = CorsConfig {\n//! \t\torigin: Origin::Copy,\n//! \t\theaders: Headers::List(vec![CONTENT_TYPE]),\n//! \t\tmax_age: 0,\n//! \t\tcredentials: true\n//! \t};\n//! \tlet (chain, pipelines) = single_pipeline(new_pipeline().add(cors).build());\n//! \tgotham::start(\n//! \t\t\"127.0.0.1:8080\",\n//! \t\tbuild_router(chain, pipelines, |route| {\n//! \t\t\troute.resource::(\"foo\");\n//! \t\t})\n//! \t)\n//! \t.expect(\"Failed to start gotham\");\n//! }\n//! # }\n//! ```\n//!\n//! The cors feature can also be used for non-resource handlers. Take a look at [`CorsRoute`]\n//! for an example.\n//!\n//! ## Database Feature\n//!\n//! The database feature allows an easy integration of [diesel] into your handler functions. Please\n//! note however that due to the way gotham's diesel middleware implementation, it is not possible\n//! to run async code while holding a database connection. If you need to combine async and database,\n//! you'll need to borrow the connection from the [`State`] yourself and return a boxed future.\n//!\n//! A simple non-async example looks like this:\n//!\n//! ```rust,no_run\n//! # #[macro_use] extern crate diesel;\n//! # #[macro_use] extern crate gotham_restful_derive;\n//! # #[cfg(feature = \"database\")]\n//! # mod database_feature_enabled {\n//! # use diesel::{table, PgConnection, QueryResult, RunQueryDsl};\n//! # use gotham::{router::builder::*, pipeline::*, state::State};\n//! # use gotham_middleware_diesel::DieselMiddleware;\n//! # use gotham_restful::*;\n//! # use serde::{Deserialize, Serialize};\n//! # use std::env;\n//! # table! {\n//! # foo (id) {\n//! # id -> Int8,\n//! # value -> Text,\n//! # }\n//! # }\n//! #[derive(Resource)]\n//! #[resource(read_all)]\n//! struct FooResource;\n//!\n//! #[derive(Queryable, Serialize)]\n//! # #[cfg_attr(feature = \"openapi\", derive(openapi_type::OpenapiType))]\n//! struct Foo {\n//! \tid: i64,\n//! \tvalue: String\n//! }\n//!\n//! #[read_all]\n//! fn read_all(conn: &mut PgConnection) -> QueryResult> {\n//! \tfoo::table.load(conn)\n//! }\n//!\n//! type Repo = gotham_middleware_diesel::Repo;\n//!\n//! fn main() {\n//! \tlet repo = Repo::new(&env::var(\"DATABASE_URL\").unwrap());\n//! \tlet diesel = DieselMiddleware::new(repo);\n//!\n//! \tlet (chain, pipelines) = single_pipeline(new_pipeline().add(diesel).build());\n//! \tgotham::start(\n//! \t\t\"127.0.0.1:8080\",\n//! \t\tbuild_router(chain, pipelines, |route| {\n//! \t\t\troute.resource::(\"foo\");\n//! \t\t})\n//! \t)\n//! \t.expect(\"Failed to start gotham\");\n//! }\n//! # }\n//! ```\n//!\n//! ## OpenAPI Feature\n//!\n//! The OpenAPI feature is probably the most powerful one of this crate. Definitely read this section\n//! carefully both as a binary as well as a library author to avoid unwanted suprises.\n//!\n//! In order to automatically create an openapi specification, gotham-restful needs knowledge over\n//! all routes and the types returned. `serde` does a great job at serialization but doesn't give\n//! enough type information, so all types used in the router need to implement\n//! [`OpenapiType`](openapi_type::OpenapiType). This can be derived for almoust any type and there\n//! should be no need to implement it manually. A simple example looks like this:\n//!\n//! ```rust,no_run\n//! # #[macro_use] extern crate gotham_restful_derive;\n//! # #[cfg(feature = \"openapi\")]\n//! # mod openapi_feature_enabled {\n//! # use gotham::{router::builder::*, state::State};\n//! # use gotham_restful::*;\n//! # use openapi_type::OpenapiType;\n//! # use serde::{Deserialize, Serialize};\n//! #[derive(Resource)]\n//! #[resource(read_all)]\n//! struct FooResource;\n//!\n//! #[derive(OpenapiType, Serialize)]\n//! struct Foo {\n//! \tbar: String\n//! }\n//!\n//! #[read_all]\n//! fn read_all() -> Success {\n//! \tFoo {\n//! \t\tbar: \"Hello World\".to_owned()\n//! \t}\n//! \t.into()\n//! }\n//!\n//! fn main() {\n//! \tgotham::start(\n//! \t\t\"127.0.0.1:8080\",\n//! \t\tbuild_simple_router(|route| {\n//! \t\t\tlet info = OpenapiInfo {\n//! \t\t\t\ttitle: \"My Foo API\".to_owned(),\n//! \t\t\t\tversion: \"0.1.0\".to_owned(),\n//! \t\t\t\turls: vec![\"https://example.org/foo/api/v1\".to_owned()]\n//! \t\t\t};\n//! \t\t\troute.with_openapi(info, |mut route| {\n//! \t\t\t\troute.resource::(\"foo\");\n//! \t\t\t\troute.openapi_spec(\"openapi\");\n//! \t\t\t\troute.openapi_doc(\"/\");\n//! \t\t\t});\n//! \t\t})\n//! \t)\n//! \t.expect(\"Failed to start gotham\");\n//! }\n//! # }\n//! ```\n//!\n//! Above example adds the resource as before, but adds two other endpoints as well: `/openapi` and `/`.\n//! The first one will return the generated openapi specification in JSON format, allowing you to easily\n//! generate clients in different languages without worying to exactly replicate your api in each of those\n//! languages. The second one will return documentation in HTML format, so you can easily view your\n//! api and share it with other people.\n//!\n//! ### Gotchas\n//!\n//! The openapi feature has some gotchas you should be aware of.\n//!\n//! - The name of a struct is used as a \"link\" in the openapi specification. Therefore, if you have two\n//! structs with the same name in your project, the openapi specification will be invalid as only one\n//! of the two will make it into the spec.\n//! - By default, the `without-openapi` feature of this crate is enabled. Disabling it in favour of the\n//! `openapi` feature will add additional type bounds and method requirements to some of the traits and\n//! \ttypes in this crate, for example instead of [`Endpoint`] you now have to implement\n//! \t[`EndpointWithSchema`]. This means that some code might only compile on either feature, but not\n//! on both. If you are writing a library that uses gotham-restful, it is strongly recommended to pass\n//! \tboth features through and conditionally enable the openapi code, like this:\n//!\n//! ```rust\n//! # #[macro_use] extern crate gotham_restful;\n//! # use serde::{Deserialize, Serialize};\n//! #[derive(Deserialize, Serialize)]\n//! #[cfg_attr(feature = \"openapi\", derive(openapi_type::OpenapiType))]\n//! struct Foo;\n//! ```\n//!\n//! [diesel]: https://diesel.rs/\n//! [`State`]: gotham::state::State\n\n#[cfg(all(feature = \"openapi\", feature = \"without-openapi\"))]\ncompile_error!(\"The 'openapi' and 'without-openapi' features cannot be combined\");\n\n#[cfg(all(not(feature = \"openapi\"), not(feature = \"without-openapi\")))]\ncompile_error!(\"Either the 'openapi' or 'without-openapi' feature needs to be enabled\");\n\n// weird proc macro issue\nextern crate self as gotham_restful;\n\n#[macro_use]\nextern crate gotham_restful_derive;\n#[macro_use]\nextern crate log;\n#[macro_use]\nextern crate serde;\n\n#[cfg(test)]\n#[macro_use]\nextern crate pretty_assertions;\n\n#[doc(no_inline)]\npub use gotham;\n\npub use gotham_restful_derive::*;\n\n/// Not public API\n#[doc(hidden)]\npub mod private {\n\tpub use crate::routing::PathExtractor as IdPlaceholder;\n\tpub use futures_util::future::{BoxFuture, FutureExt};\n\t#[cfg(feature = \"database\")]\n\tpub use gotham_middleware_diesel::Repo;\n\t#[cfg(feature = \"openapi\")]\n\tpub use openapi_type::{OpenapiSchema, OpenapiType, Visitor};\n\tpub use serde_json;\n\n\t#[cfg(feature = \"openapi\")]\n\tuse gotham::hyper::StatusCode;\n\t#[cfg(feature = \"auth\")]\n\tuse gotham::state::{FromState, State};\n\n\t/// This method is used by the endpoint macro to generate a good error message\n\t/// when the used AuthData type does not implement Clone.\n\t#[cfg(feature = \"auth\")]\n\t#[inline]\n\tpub fn clone_from_state(state: &State) -> T\n\twhere\n\t\tT: FromState + Clone\n\t{\n\t\tT::borrow_from(state).clone()\n\t}\n\n\t/// This trait is used by the endpoint macro to generate a good error message\n\t/// when the schema function has the wrong signature.\n\t#[cfg(feature = \"openapi\")]\n\tpub trait CustomSchema {\n\t\tfn schema(self, code: StatusCode) -> OpenapiSchema;\n\t}\n\n\t#[cfg(feature = \"openapi\")]\n\timpl CustomSchema for F\n\twhere\n\t\tF: FnOnce(StatusCode) -> OpenapiSchema\n\t{\n\t\t#[inline]\n\t\tfn schema(self, code: StatusCode) -> OpenapiSchema {\n\t\t\tself(code)\n\t\t}\n\t}\n\n\t/// This trait is used by the endpoint macro to generate a good error message\n\t/// when the status_codes function has the wrong signature.\n\t#[cfg(feature = \"openapi\")]\n\tpub trait CustomStatusCodes {\n\t\tfn status_codes(self) -> Vec;\n\t}\n\n\t#[cfg(feature = \"openapi\")]\n\timpl CustomStatusCodes for F\n\twhere\n\t\tF: FnOnce() -> Vec\n\t{\n\t\t#[inline]\n\t\tfn status_codes(self) -> Vec {\n\t\t\tself()\n\t\t}\n\t}\n}\n\n#[cfg(feature = \"auth\")]\nmod auth;\n#[cfg(feature = \"auth\")]\npub use auth::{\n\tAuthHandler, AuthMiddleware, AuthSource, AuthStatus, AuthValidation, StaticAuthHandler\n};\n\n#[cfg(feature = \"cors\")]\npub mod cors;\n#[cfg(feature = \"cors\")]\npub use cors::{handle_cors, CorsConfig, CorsRoute};\n\n#[cfg(feature = \"openapi\")]\nmod openapi;\n#[cfg(feature = \"openapi\")]\npub use openapi::{builder::OpenapiInfo, router::GetOpenapi};\n\nmod endpoint;\n#[cfg(feature = \"openapi\")]\npub use endpoint::EndpointWithSchema;\npub use endpoint::{Endpoint, NoopExtractor};\n\nmod response;\npub use response::{\n\tAuthError, AuthErrorOrOther, AuthResult, AuthSuccess, IntoResponse, IntoResponseError,\n\tNoContent, Raw, Redirect, Response, Success\n};\n#[cfg(feature = \"openapi\")]\npub use response::{IntoResponseWithSchema, ResponseSchema};\n\nmod routing;\npub use routing::{DrawResourceRoutes, DrawResources};\n#[cfg(feature = \"openapi\")]\npub use routing::{DrawResourceRoutesWithSchema, DrawResourcesWithSchema, WithOpenapi};\n\nmod types;\npub use types::{FromBody, RequestBody, ResponseBody};\n\n/// This trait must be implemented for every resource. It allows you to register the different\n/// endpoints that can be handled by this resource to be registered with the underlying router.\n///\n/// It is not recommended to implement this yourself, just use `#[derive(Resource)]`.\n#[_private_openapi_trait(ResourceWithSchema)]\npub trait Resource {\n\t/// Register all methods handled by this resource with the underlying router.\n\t#[openapi_bound(D: crate::DrawResourceRoutesWithSchema)]\n\t#[non_openapi_bound(D: crate::DrawResourceRoutes)]\n\tfn setup(route: D);\n}\n","traces":[{"line":463,"address":[15357421],"length":1,"stats":{"Line":0},"fn_name":null},{"line":464,"address":[17188331],"length":1,"stats":{"Line":7},"fn_name":null},{"line":466,"address":[13805381],"length":1,"stats":{"Line":9},"fn_name":null},{"line":467,"address":[14188747],"length":1,"stats":{"Line":0},"fn_name":null},{"line":489,"address":[18612977],"length":1,"stats":{"Line":0},"fn_name":null},{"line":508,"address":[18613357],"length":1,"stats":{"Line":14},"fn_name":null},{"line":512,"address":[10054564],"length":1,"stats":{"Line":0},"fn_name":null},{"line":518,"address":[18613392],"length":1,"stats":{"Line":0},"fn_name":null},{"line":523,"address":[15743696],"length":1,"stats":{"Line":6},"fn_name":null},{"line":528,"address":[6694129],"length":1,"stats":{"Line":9},"fn_name":null},{"line":529,"address":[15743854],"length":1,"stats":{"Line":7},"fn_name":null},{"line":536,"address":[15744012],"length":1,"stats":{"Line":0},"fn_name":null},{"line":541,"address":[15133728],"length":1,"stats":{"Line":0},"fn_name":"next"},{"line":546,"address":[9281232,9281264],"length":1,"stats":{"Line":1},"fn_name":"read_i16"},{"line":547,"address":[9281278,9281246],"length":1,"stats":{"Line":1},"fn_name":null},{"line":552,"address":[14189040],"length":1,"stats":{"Line":0},"fn_name":null},{"line":559,"address":[9335299,9335210],"length":1,"stats":{"Line":0},"fn_name":null},{"line":564,"address":[9335484,9335505],"length":1,"stats":{"Line":0},"fn_name":null}],"covered":8,"coverable":18},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","openapi","builder.rs"],"content":"use openapi_type::{\n\tindexmap::IndexMap,\n\topenapiv3::{\n\t\tself, Components, OpenAPI, PathItem, ReferenceOr,\n\t\tReferenceOr::{Item, Reference},\n\t\tSchema, Server\n\t},\n\tOpenapiSchema\n};\nuse parking_lot::RwLock;\nuse std::sync::Arc;\n\n#[derive(Clone, Debug)]\npub struct OpenapiInfo {\n\tpub title: String,\n\tpub version: String,\n\tpub urls: Vec\n}\n\n#[derive(Clone, Debug)]\npub(crate) struct OpenapiBuilder {\n\tpub(crate) openapi: Arc>\n}\n\nimpl OpenapiBuilder {\n\tpub(crate) fn new(info: OpenapiInfo) -> Self {\n\t\tSelf {\n\t\t\topenapi: Arc::new(RwLock::new(OpenAPI {\n\t\t\t\topenapi: \"3.0.2\".to_string(),\n\t\t\t\tinfo: openapiv3::Info {\n\t\t\t\t\ttitle: info.title,\n\t\t\t\t\tversion: info.version,\n\t\t\t\t\t..Default::default()\n\t\t\t\t},\n\t\t\t\tservers: info\n\t\t\t\t\t.urls\n\t\t\t\t\t.into_iter()\n\t\t\t\t\t.map(|url| Server {\n\t\t\t\t\t\turl,\n\t\t\t\t\t\t..Default::default()\n\t\t\t\t\t})\n\t\t\t\t\t.collect(),\n\t\t\t\t..Default::default()\n\t\t\t}))\n\t\t}\n\t}\n\n\t/// Remove path from the OpenAPI spec, or return an empty one if not included. This is handy if you need to\n\t/// modify the path and add it back after the modification\n\tpub(crate) fn remove_path(&mut self, path: &str) -> PathItem {\n\t\tlet mut openapi = self.openapi.write();\n\t\tmatch openapi.paths.paths.swap_remove(path) {\n\t\t\tSome(Item(item)) => item,\n\t\t\t_ => PathItem::default()\n\t\t}\n\t}\n\n\tpub(crate) fn add_path(&mut self, path: Path, item: PathItem) {\n\t\tlet mut openapi = self.openapi.write();\n\t\topenapi.paths.paths.insert(path.to_string(), Item(item));\n\t}\n\n\tfn add_schema_impl(&mut self, name: String, mut schema: OpenapiSchema) {\n\t\tself.add_schema_dependencies(&mut schema.dependencies);\n\n\t\tlet mut openapi = self.openapi.write();\n\t\tmatch &mut openapi.components {\n\t\t\tSome(comp) => {\n\t\t\t\tcomp.schemas.insert(name, Item(schema.schema));\n\t\t\t},\n\t\t\tNone => {\n\t\t\t\tlet mut comp = Components::default();\n\t\t\t\tcomp.schemas.insert(name, Item(schema.schema));\n\t\t\t\topenapi.components = Some(comp);\n\t\t\t}\n\t\t};\n\t}\n\n\tfn add_schema_dependencies(&mut self, dependencies: &mut IndexMap) {\n\t\tlet keys: Vec = dependencies.keys().map(|k| k.to_string()).collect();\n\t\tfor dep in keys {\n\t\t\tlet dep_schema = dependencies.swap_remove(&dep);\n\t\t\tif let Some(dep_schema) = dep_schema {\n\t\t\t\tself.add_schema_impl(dep, dep_schema);\n\t\t\t}\n\t\t}\n\t}\n\n\tpub(crate) fn add_schema(&mut self, mut schema: OpenapiSchema) -> ReferenceOr {\n\t\tmatch schema.schema.schema_data.title.clone() {\n\t\t\tSome(name) => {\n\t\t\t\tlet reference = Reference {\n\t\t\t\t\treference: format!(\"#/components/schemas/{name}\")\n\t\t\t\t};\n\t\t\t\tself.add_schema_impl(name, schema);\n\t\t\t\treference\n\t\t\t},\n\t\t\tNone => {\n\t\t\t\tself.add_schema_dependencies(&mut schema.dependencies);\n\t\t\t\tItem(schema.schema)\n\t\t\t}\n\t\t}\n\t}\n}\n\n#[cfg(test)]\n#[allow(dead_code)]\nmod test {\n\tuse super::*;\n\tuse openapi_type::OpenapiType;\n\n\t#[derive(OpenapiType)]\n\tstruct Message {\n\t\tmsg: String\n\t}\n\n\t#[derive(OpenapiType)]\n\tstruct Messages {\n\t\tmsgs: Vec\n\t}\n\n\tfn info() -> OpenapiInfo {\n\t\tOpenapiInfo {\n\t\t\ttitle: \"TEST CASE\".to_owned(),\n\t\t\tversion: \"1.2.3\".to_owned(),\n\t\t\turls: vec![\n\t\t\t\t\"http://localhost:1234\".to_owned(),\n\t\t\t\t\"https://example.org\".to_owned(),\n\t\t\t]\n\t\t}\n\t}\n\n\tfn openapi(builder: OpenapiBuilder) -> OpenAPI {\n\t\tArc::try_unwrap(builder.openapi).unwrap().into_inner()\n\t}\n\n\t#[test]\n\tfn new_builder() {\n\t\tlet info = info();\n\t\tlet builder = OpenapiBuilder::new(info.clone());\n\t\tlet openapi = openapi(builder);\n\n\t\tassert_eq!(info.title, openapi.info.title);\n\t\tassert_eq!(info.version, openapi.info.version);\n\t\tassert_eq!(info.urls.len(), openapi.servers.len());\n\t}\n\n\t#[test]\n\tfn add_schema() {\n\t\tlet mut builder = OpenapiBuilder::new(info());\n\t\tbuilder.add_schema(>::schema());\n\t\tlet openapi = openapi(builder);\n\n\t\tassert_eq!(\n\t\t\topenapi.components.clone().unwrap_or_default().schemas[\"Message\"],\n\t\t\tReferenceOr::Item(Message::schema().schema)\n\t\t);\n\t\tassert_eq!(\n\t\t\topenapi.components.clone().unwrap_or_default().schemas[\"Messages\"],\n\t\t\tReferenceOr::Item(Messages::schema().schema)\n\t\t);\n\t}\n}\n","traces":[{"line":26,"address":[6056299,6054464,6056102],"length":1,"stats":{"Line":4},"fn_name":null},{"line":28,"address":[6216184,6215689,6214859],"length":1,"stats":{"Line":12},"fn_name":null},{"line":50,"address":[6217733,6217104,6217697],"length":1,"stats":{"Line":2},"fn_name":null},{"line":51,"address":[6217227],"length":1,"stats":{"Line":2},"fn_name":null},{"line":52,"address":[6217261,6217337],"length":1,"stats":{"Line":4},"fn_name":null},{"line":53,"address":[6217426],"length":1,"stats":{"Line":1},"fn_name":null},{"line":54,"address":[6057106,6056999],"length":1,"stats":{"Line":4},"fn_name":null},{"line":58,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":59,"address":[],"length":0,"stats":{"Line":4},"fn_name":null},{"line":60,"address":[],"length":0,"stats":{"Line":4},"fn_name":null},{"line":63,"address":[6057376,6058645,6058480],"length":1,"stats":{"Line":2},"fn_name":null},{"line":64,"address":[6217865],"length":1,"stats":{"Line":2},"fn_name":null},{"line":66,"address":[6217976],"length":1,"stats":{"Line":2},"fn_name":null},{"line":67,"address":[6218111,6218038],"length":1,"stats":{"Line":4},"fn_name":null},{"line":68,"address":[6218193],"length":1,"stats":{"Line":2},"fn_name":null},{"line":69,"address":[6218201,6218961],"length":1,"stats":{"Line":4},"fn_name":null},{"line":72,"address":[6218162],"length":1,"stats":{"Line":2},"fn_name":null},{"line":73,"address":[6218375,6218580],"length":1,"stats":{"Line":4},"fn_name":null},{"line":74,"address":[6218599,6218906],"length":1,"stats":{"Line":2},"fn_name":null},{"line":79,"address":[6059311,6058688],"length":1,"stats":{"Line":3},"fn_name":null},{"line":80,"address":[6058734,6059344,6059379],"length":1,"stats":{"Line":7},"fn_name":"{closure#0}"},{"line":81,"address":[6058779,6058937,6059265],"length":1,"stats":{"Line":7},"fn_name":null},{"line":82,"address":[6058990,6059038],"length":1,"stats":{"Line":4},"fn_name":null},{"line":83,"address":[6059046],"length":1,"stats":{"Line":2},"fn_name":null},{"line":84,"address":[6059123,6059206],"length":1,"stats":{"Line":4},"fn_name":null},{"line":89,"address":[6059408,6060165,6060223],"length":1,"stats":{"Line":3},"fn_name":null},{"line":90,"address":[6059451,6059555],"length":1,"stats":{"Line":6},"fn_name":null},{"line":91,"address":[6059605],"length":1,"stats":{"Line":1},"fn_name":null},{"line":93,"address":[6059829],"length":1,"stats":{"Line":1},"fn_name":null},{"line":95,"address":[6059950],"length":1,"stats":{"Line":1},"fn_name":null},{"line":96,"address":[6060096],"length":1,"stats":{"Line":1},"fn_name":null},{"line":99,"address":[6059591],"length":1,"stats":{"Line":3},"fn_name":null},{"line":100,"address":[6059710],"length":1,"stats":{"Line":3},"fn_name":null}],"covered":33,"coverable":33},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","openapi","handler","mod.rs"],"content":"#![cfg_attr(not(feature = \"auth\"), allow(unused_imports))]\nuse super::SECURITY_NAME;\nuse base64::prelude::*;\nuse futures_util::{future, future::FutureExt};\nuse gotham::{\n\tanyhow,\n\thandler::{Handler, HandlerError, HandlerFuture, NewHandler},\n\thelpers::http::response::{create_empty_response, create_response},\n\thyper::{\n\t\theader::{\n\t\t\tHeaderMap, HeaderValue, CACHE_CONTROL, CONTENT_SECURITY_POLICY, ETAG, IF_NONE_MATCH,\n\t\t\tREFERRER_POLICY, X_CONTENT_TYPE_OPTIONS\n\t\t},\n\t\tBody, Response, StatusCode\n\t},\n\tmime::{APPLICATION_JSON, TEXT_HTML_UTF_8, TEXT_PLAIN_UTF_8},\n\tstate::State\n};\nuse gotham_restful_redoc::Redoc;\nuse openapi_type::{\n\tindexmap::IndexMap,\n\topenapiv3::{APIKeyLocation, OpenAPI, ReferenceOr, SecurityScheme}\n};\nuse parking_lot::RwLock;\nuse sha2::{Digest, Sha256};\nuse std::{panic::RefUnwindSafe, pin::Pin, sync::Arc};\n\n#[cfg(feature = \"auth\")]\nfn get_security(state: &State) -> IndexMap> {\n\tuse crate::AuthSource;\n\tuse gotham::state::FromState;\n\n\tlet source = match AuthSource::try_borrow_from(state) {\n\t\tSome(source) => source,\n\t\tNone => return Default::default()\n\t};\n\n\tlet security_scheme = match source {\n\t\tAuthSource::Cookie(name) => SecurityScheme::APIKey {\n\t\t\tlocation: APIKeyLocation::Cookie,\n\t\t\tname: name.to_string(),\n\t\t\tdescription: None\n\t\t},\n\t\tAuthSource::Header(name) => SecurityScheme::APIKey {\n\t\t\tlocation: APIKeyLocation::Header,\n\t\t\tname: name.to_string(),\n\t\t\tdescription: None\n\t\t},\n\t\tAuthSource::AuthorizationHeader => SecurityScheme::HTTP {\n\t\t\tscheme: \"bearer\".to_owned(),\n\t\t\tbearer_format: Some(\"JWT\".to_owned()),\n\t\t\tdescription: None\n\t\t}\n\t};\n\n\tlet mut security_schemes: IndexMap> = Default::default();\n\tsecurity_schemes.insert(SECURITY_NAME.to_owned(), ReferenceOr::Item(security_scheme));\n\n\tsecurity_schemes\n}\n\n#[cfg(not(feature = \"auth\"))]\nfn get_security(_state: &State) -> IndexMap> {\n\tDefault::default()\n}\n\nfn openapi_string(\n\tstate: &State,\n\topenapi: &Arc>\n) -> Result {\n\tlet openapi = openapi.read();\n\n\tlet mut openapi = openapi.clone();\n\tlet security_schemes = get_security(state);\n\tlet mut components = openapi.components.unwrap_or_default();\n\tcomponents.security_schemes = security_schemes;\n\topenapi.components = Some(components);\n\n\tserde_json::to_string(&openapi)\n}\n\nfn create_openapi_response(state: &State, openapi: &Arc>) -> Response {\n\tmatch openapi_string(state, openapi) {\n\t\tOk(body) => {\n\t\t\tlet mut res = create_response(state, StatusCode::OK, APPLICATION_JSON, body);\n\t\t\tlet headers = res.headers_mut();\n\t\t\theaders.insert(X_CONTENT_TYPE_OPTIONS, HeaderValue::from_static(\"nosniff\"));\n\t\t\tres\n\t\t},\n\t\tErr(e) => {\n\t\t\terror!(\"Unable to handle OpenAPI request due to error: {e}\");\n\t\t\tcreate_response(\n\t\t\t\tstate,\n\t\t\t\tStatusCode::INTERNAL_SERVER_ERROR,\n\t\t\t\tTEXT_PLAIN_UTF_8,\n\t\t\t\t\"\"\n\t\t\t)\n\t\t}\n\t}\n}\n\n#[derive(Clone)]\npub(crate) struct OpenapiSpecHandler {\n\topenapi: Arc>\n}\n\n// safety: the handler only ever aquires a read lock, so this usage of\n// RwLock is, in fact, unwind safe\nimpl RefUnwindSafe for OpenapiSpecHandler {}\n\nimpl OpenapiSpecHandler {\n\tpub(crate) fn new(openapi: Arc>) -> Self {\n\t\tSelf { openapi }\n\t}\n}\n\nimpl NewHandler for OpenapiSpecHandler {\n\ttype Instance = Self;\n\n\tfn new_handler(&self) -> anyhow::Result {\n\t\tOk(self.clone())\n\t}\n}\n\nimpl Handler for OpenapiSpecHandler {\n\tfn handle(self, mut state: State) -> Pin> {\n\t\tlet res = create_openapi_response(&mut state, &self.openapi);\n\t\tfuture::ok((state, res)).boxed()\n\t}\n}\n\n#[derive(Clone)]\npub(crate) struct OpenapiDocHandler {\n\topenapi: Arc>\n}\n\n// safety: the handler only ever aquires a read lock, so this usage of\n// RwLock is, in fact, unwind safe\nimpl RefUnwindSafe for OpenapiDocHandler {}\n\nimpl OpenapiDocHandler {\n\tpub(crate) fn new(openapi: Arc>) -> Self {\n\t\tSelf { openapi }\n\t}\n}\n\nimpl NewHandler for OpenapiDocHandler {\n\ttype Instance = Self;\n\n\tfn new_handler(&self) -> anyhow::Result {\n\t\tOk(self.clone())\n\t}\n}\n\nfn redoc_handler(\n\tstate: &State,\n\topenapi: &Arc>\n) -> Result, HandlerError> {\n\tlet spec = openapi_string(state, openapi)?;\n\tlet Redoc { html, script_hash } = gotham_restful_redoc::html(spec);\n\n\tlet mut etag = Sha256::new();\n\tetag.update(&html);\n\tlet etag = format!(\"\\\"{}\\\"\", BASE64_STANDARD.encode(etag.finalize()));\n\n\tif state\n\t\t.borrow::()\n\t\t.get(IF_NONE_MATCH)\n\t\t.map_or(false, |header| header.as_bytes() == etag.as_bytes())\n\t{\n\t\tlet res = create_empty_response(state, StatusCode::NOT_MODIFIED);\n\t\treturn Ok(res);\n\t}\n\n\tlet mut res = create_response(state, StatusCode::OK, TEXT_HTML_UTF_8, html);\n\tlet headers = res.headers_mut();\n\theaders.insert(\n\t\tCACHE_CONTROL,\n\t\tHeaderValue::from_static(\"public,max-age=2592000\")\n\t);\n\theaders.insert(\n\t\tCONTENT_SECURITY_POLICY,\n\t\tformat!(\n\t\t\t\"default-src 'none';base-uri 'none';script-src 'unsafe-inline' https://cdn.jsdelivr.net 'sha256-{script_hash}' 'strict-dynamic';style-src 'unsafe-inline' https://fonts.googleapis.com;font-src https://fonts.gstatic.com;connect-src 'self';img-src blob: data:\",\n\t\t).parse().unwrap()\n\t);\n\theaders.insert(ETAG, etag.parse().unwrap());\n\theaders.insert(REFERRER_POLICY, HeaderValue::from_static(\"no-referrer\"));\n\theaders.insert(X_CONTENT_TYPE_OPTIONS, HeaderValue::from_static(\"nosniff\"));\n\tOk(res)\n}\n\nimpl Handler for OpenapiDocHandler {\n\tfn handle(self, state: State) -> Pin> {\n\t\tmatch redoc_handler(&state, &self.openapi) {\n\t\t\tOk(res) => future::ok((state, res)).boxed(),\n\t\t\tErr(err) => future::err((state, err)).boxed()\n\t\t}\n\t}\n}\n","traces":[{"line":29,"address":[6281936,6283035],"length":1,"stats":{"Line":2},"fn_name":"get_security"},{"line":33,"address":[6281974,6282099],"length":1,"stats":{"Line":2},"fn_name":null},{"line":34,"address":[6282031],"length":1,"stats":{"Line":1},"fn_name":null},{"line":35,"address":[6282023],"length":1,"stats":{"Line":1},"fn_name":null},{"line":38,"address":[6282049],"length":1,"stats":{"Line":1},"fn_name":null},{"line":41,"address":[6282126],"length":1,"stats":{"Line":0},"fn_name":null},{"line":46,"address":[6282293],"length":1,"stats":{"Line":0},"fn_name":null},{"line":50,"address":[6282432],"length":1,"stats":{"Line":1},"fn_name":null},{"line":51,"address":[6282457,6282550],"length":1,"stats":{"Line":2},"fn_name":null},{"line":56,"address":[6282484],"length":1,"stats":{"Line":1},"fn_name":null},{"line":57,"address":[6282802,6282870],"length":1,"stats":{"Line":2},"fn_name":null},{"line":59,"address":[6283004],"length":1,"stats":{"Line":1},"fn_name":null},{"line":67,"address":[6284468,6283088,6284000],"length":1,"stats":{"Line":2},"fn_name":"openapi_string"},{"line":71,"address":[6283154],"length":1,"stats":{"Line":2},"fn_name":null},{"line":73,"address":[6283268,6283209],"length":1,"stats":{"Line":4},"fn_name":null},{"line":74,"address":[6283296,6283344],"length":1,"stats":{"Line":4},"fn_name":null},{"line":75,"address":[6283352,6283453],"length":1,"stats":{"Line":4},"fn_name":null},{"line":76,"address":[6283469],"length":1,"stats":{"Line":2},"fn_name":null},{"line":77,"address":[6283725],"length":1,"stats":{"Line":2},"fn_name":null},{"line":79,"address":[6283857],"length":1,"stats":{"Line":2},"fn_name":null},{"line":82,"address":[6284496,6285115],"length":1,"stats":{"Line":2},"fn_name":"create_openapi_response"},{"line":83,"address":[6284534],"length":1,"stats":{"Line":2},"fn_name":null},{"line":84,"address":[6284587],"length":1,"stats":{"Line":2},"fn_name":null},{"line":85,"address":[6284610],"length":1,"stats":{"Line":2},"fn_name":null},{"line":86,"address":[6284745,6284868],"length":1,"stats":{"Line":4},"fn_name":null},{"line":87,"address":[6284876,6285093],"length":1,"stats":{"Line":2},"fn_name":null},{"line":88,"address":[6285062],"length":1,"stats":{"Line":2},"fn_name":null},{"line":90,"address":[6284761],"length":1,"stats":{"Line":0},"fn_name":null},{"line":91,"address":[6285186,6285377,6284774,6285512],"length":1,"stats":{"Line":0},"fn_name":null},{"line":95,"address":[6285206],"length":1,"stats":{"Line":0},"fn_name":null},{"line":112,"address":[6285664],"length":1,"stats":{"Line":2},"fn_name":null},{"line":120,"address":[6285680],"length":1,"stats":{"Line":2},"fn_name":"new_handler"},{"line":121,"address":[6285689],"length":1,"stats":{"Line":2},"fn_name":null},{"line":126,"address":[6285728,6286024],"length":1,"stats":{"Line":2},"fn_name":"handle"},{"line":127,"address":[6285771],"length":1,"stats":{"Line":2},"fn_name":null},{"line":128,"address":[6285745,6285824],"length":1,"stats":{"Line":4},"fn_name":null},{"line":142,"address":[6286064],"length":1,"stats":{"Line":0},"fn_name":null},{"line":150,"address":[6286080],"length":1,"stats":{"Line":0},"fn_name":"new_handler"},{"line":151,"address":[6286089],"length":1,"stats":{"Line":0},"fn_name":null},{"line":155,"address":[6289152,6286128,6289381],"length":1,"stats":{"Line":0},"fn_name":"redoc_handler"},{"line":159,"address":[6286443,6286172],"length":1,"stats":{"Line":0},"fn_name":null},{"line":160,"address":[6286517,6286368],"length":1,"stats":{"Line":0},"fn_name":null},{"line":162,"address":[6286589],"length":1,"stats":{"Line":0},"fn_name":null},{"line":163,"address":[6286668],"length":1,"stats":{"Line":0},"fn_name":null},{"line":164,"address":[6286923,6286675],"length":1,"stats":{"Line":0},"fn_name":null},{"line":166,"address":[6287297,6287252,6287157],"length":1,"stats":{"Line":0},"fn_name":null},{"line":168,"address":[6287222],"length":1,"stats":{"Line":0},"fn_name":null},{"line":169,"address":[6289449,6289424,6287289],"length":1,"stats":{"Line":0},"fn_name":"{closure#0}"},{"line":171,"address":[6287512],"length":1,"stats":{"Line":0},"fn_name":null},{"line":172,"address":[6289279],"length":1,"stats":{"Line":0},"fn_name":null},{"line":175,"address":[6287337],"length":1,"stats":{"Line":0},"fn_name":null},{"line":176,"address":[6287539,6287612],"length":1,"stats":{"Line":0},"fn_name":null},{"line":177,"address":[6287731],"length":1,"stats":{"Line":0},"fn_name":null},{"line":178,"address":[6287620],"length":1,"stats":{"Line":0},"fn_name":null},{"line":179,"address":[6287658],"length":1,"stats":{"Line":0},"fn_name":null},{"line":181,"address":[6288214],"length":1,"stats":{"Line":0},"fn_name":null},{"line":182,"address":[6287801],"length":1,"stats":{"Line":0},"fn_name":null},{"line":183,"address":[6287968,6288156],"length":1,"stats":{"Line":0},"fn_name":null},{"line":187,"address":[6288347,6289185],"length":1,"stats":{"Line":0},"fn_name":null},{"line":188,"address":[6288589,6289163],"length":1,"stats":{"Line":0},"fn_name":null},{"line":189,"address":[6289130,6288770],"length":1,"stats":{"Line":0},"fn_name":null},{"line":190,"address":[6288993],"length":1,"stats":{"Line":0},"fn_name":null},{"line":194,"address":[6290115,6289520],"length":1,"stats":{"Line":0},"fn_name":"handle"},{"line":195,"address":[6289988,6289537,6289611],"length":1,"stats":{"Line":0},"fn_name":null},{"line":196,"address":[6289678,6289939],"length":1,"stats":{"Line":0},"fn_name":null},{"line":197,"address":[6289808,6290036],"length":1,"stats":{"Line":0},"fn_name":null}],"covered":31,"coverable":66},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","openapi","mod.rs"],"content":"const SECURITY_NAME: &str = \"authToken\";\n\npub(crate) mod builder;\npub(crate) mod handler;\npub(crate) mod operation;\npub(crate) mod router;\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","openapi","operation.rs"],"content":"use super::SECURITY_NAME;\nuse crate::{response::OrAllTypes, EndpointWithSchema, IntoResponse, RequestBody};\nuse gotham::{hyper::StatusCode, mime::Mime};\nuse openapi_type::{\n\tindexmap::IndexMap,\n\topenapiv3::{\n\t\tMediaType, Operation, Parameter, ParameterData, ParameterSchemaOrContent, ReferenceOr,\n\t\tReferenceOr::Item, RequestBody as OARequestBody, Response, Responses, Schema, SchemaKind,\n\t\tStatusCode as OAStatusCode, Type\n\t},\n\tOpenapiSchema\n};\nuse std::collections::HashMap;\n\nfn new_parameter_data(\n\tname: String,\n\trequired: bool,\n\tschema: ReferenceOr>\n) -> ParameterData {\n\tParameterData {\n\t\tname,\n\t\tdescription: None,\n\t\trequired,\n\t\tdeprecated: None,\n\t\tformat: ParameterSchemaOrContent::Schema(schema.unbox()),\n\t\texample: None,\n\t\texamples: Default::default(),\n\t\texplode: None,\n\t\textensions: Default::default()\n\t}\n}\n\n#[derive(Default)]\nstruct OperationParams {\n\tpath_params: Option,\n\tquery_params: Option\n}\n\nimpl OperationParams {\n\t// TODO shouldn't this be a custom openapi_type::Visitor\n\t// rather than this hacky code?\n\tfn add_path_params(\n\t\tpath_params: Option,\n\t\tparams: &mut Vec>\n\t) {\n\t\tlet path_params = match path_params {\n\t\t\tSome(pp) => pp.schema,\n\t\t\tNone => return\n\t\t};\n\t\tlet path_params = match path_params.schema_kind {\n\t\t\tSchemaKind::Type(Type::Object(ty)) => ty,\n\t\t\t_ => panic!(\"Path Parameters needs to be a plain struct\")\n\t\t};\n\t\tfor (name, schema) in path_params.properties {\n\t\t\tlet required = path_params.required.contains(&name);\n\t\t\tparams.push(Item(Parameter::Path {\n\t\t\t\tparameter_data: new_parameter_data(name, required, schema),\n\t\t\t\tstyle: Default::default()\n\t\t\t}))\n\t\t}\n\t}\n\n\t// TODO shouldn't this be a custom openapi_type::Visitor\n\t// rather than this hacky code?\n\tfn add_query_params(\n\t\tquery_params: Option,\n\t\tparams: &mut Vec>\n\t) {\n\t\tlet query_params = match query_params {\n\t\t\tSome(qp) => qp.schema,\n\t\t\tNone => return\n\t\t};\n\t\tlet query_params = match query_params.schema_kind {\n\t\t\tSchemaKind::Type(Type::Object(ty)) => ty,\n\t\t\t_ => panic!(\"Query Parameters needs to be a plain struct\")\n\t\t};\n\t\tfor (name, schema) in query_params.properties {\n\t\t\tlet required = query_params.required.contains(&name);\n\t\t\tparams.push(Item(Parameter::Query {\n\t\t\t\tparameter_data: new_parameter_data(name, required, schema),\n\t\t\t\tallow_reserved: false,\n\t\t\t\tstyle: Default::default(),\n\t\t\t\tallow_empty_value: None\n\t\t\t}))\n\t\t}\n\t}\n\n\tfn into_params(self) -> Vec> {\n\t\tlet mut params: Vec> = Vec::new();\n\t\tSelf::add_path_params(self.path_params, &mut params);\n\t\tSelf::add_query_params(self.query_params, &mut params);\n\t\tparams\n\t}\n}\n\npub(crate) struct OperationDescription {\n\toperation_id: Option,\n\tdescription: Option,\n\n\taccepted_types: Option>,\n\tresponses: HashMap>,\n\tparams: OperationParams,\n\tbody_schema: Option>,\n\tsupported_types: Option>,\n\trequires_auth: bool\n}\n\nimpl OperationDescription {\n\t/// Create a new operation description for the given endpoint type and schema. If the endpoint\n\t/// does not specify an operation id, the path is used to generate one.\n\tpub(crate) fn new(\n\t\tresponses: HashMap>,\n\t\tpath: &str\n\t) -> Self {\n\t\tlet operation_id = E::operation_id().or_else(|| {\n\t\t\tE::operation_verb()\n\t\t\t\t.map(|verb| format!(\"{verb}_{}\", path.replace(\"/\", \"_\").trim_start_matches('_')))\n\t\t});\n\t\tSelf {\n\t\t\toperation_id,\n\t\t\tdescription: E::description(),\n\n\t\t\taccepted_types: E::Output::accepted_types(),\n\t\t\tresponses,\n\t\t\tparams: Default::default(),\n\t\t\tbody_schema: None,\n\t\t\tsupported_types: None,\n\t\t\trequires_auth: E::wants_auth()\n\t\t}\n\t}\n\n\tpub(crate) fn set_path_params(&mut self, params: OpenapiSchema) {\n\t\tself.params.path_params = Some(params);\n\t}\n\n\tpub(crate) fn set_query_params(&mut self, params: OpenapiSchema) {\n\t\tself.params.query_params = Some(params);\n\t}\n\n\tpub(crate) fn set_body(&mut self, schema: ReferenceOr) {\n\t\tself.body_schema = Some(schema);\n\t\tself.supported_types = Body::supported_types();\n\t}\n\n\tfn schema_to_content(\n\t\ttypes: Vec,\n\t\tschema: ReferenceOr\n\t) -> IndexMap {\n\t\tlet mut content: IndexMap = IndexMap::new();\n\t\tfor ty in types {\n\t\t\tcontent.insert(ty.to_string(), MediaType {\n\t\t\t\tschema: Some(schema.clone()),\n\t\t\t\t..Default::default()\n\t\t\t});\n\t\t}\n\t\tcontent\n\t}\n\n\tpub(crate) fn into_operation(self) -> Operation {\n\t\t// this is unfortunately neccessary to prevent rust from complaining about partially moving self\n\t\tlet (\n\t\t\toperation_id,\n\t\t\tdescription,\n\t\t\taccepted_types,\n\t\t\tresponses,\n\t\t\tparams,\n\t\t\tbody_schema,\n\t\t\tsupported_types,\n\t\t\trequires_auth\n\t\t) = (\n\t\t\tself.operation_id,\n\t\t\tself.description,\n\t\t\tself.accepted_types,\n\t\t\tself.responses,\n\t\t\tself.params,\n\t\t\tself.body_schema,\n\t\t\tself.supported_types,\n\t\t\tself.requires_auth\n\t\t);\n\n\t\tlet responses: IndexMap> = responses\n\t\t\t.into_iter()\n\t\t\t.map(|(code, schema)| {\n\t\t\t\tlet content =\n\t\t\t\t\tSelf::schema_to_content(accepted_types.clone().or_all_types(), schema);\n\t\t\t\t(\n\t\t\t\t\tOAStatusCode::Code(code.as_u16()),\n\t\t\t\t\tItem(Response {\n\t\t\t\t\t\tdescription: code\n\t\t\t\t\t\t\t.canonical_reason()\n\t\t\t\t\t\t\t.map(|d| d.to_string())\n\t\t\t\t\t\t\t.unwrap_or_default(),\n\t\t\t\t\t\tcontent,\n\t\t\t\t\t\t..Default::default()\n\t\t\t\t\t})\n\t\t\t\t)\n\t\t\t})\n\t\t\t.collect();\n\n\t\tlet request_body = body_schema.map(|schema| {\n\t\t\tItem(OARequestBody {\n\t\t\t\tcontent: Self::schema_to_content(supported_types.or_all_types(), schema),\n\t\t\t\trequired: true,\n\t\t\t\t..Default::default()\n\t\t\t})\n\t\t});\n\n\t\tlet mut security = None;\n\t\tif requires_auth {\n\t\t\tlet mut sec = IndexMap::new();\n\t\t\tsec.insert(SECURITY_NAME.to_owned(), Vec::new());\n\t\t\tsecurity = Some(vec![sec]);\n\t\t}\n\n\t\tOperation {\n\t\t\ttags: Vec::new(),\n\t\t\toperation_id,\n\t\t\tdescription,\n\t\t\tparameters: params.into_params(),\n\t\t\trequest_body,\n\t\t\tresponses: Responses {\n\t\t\t\tresponses,\n\t\t\t\t..Default::default()\n\t\t\t},\n\t\t\tdeprecated: false,\n\t\t\tsecurity,\n\t\t\t..Default::default()\n\t\t}\n\t}\n}\n\n#[cfg(test)]\nmod test {\n\tuse super::*;\n\tuse crate::{NoContent, Raw, ResponseSchema};\n\n\t#[test]\n\tfn no_content_schema_to_content() {\n\t\tlet types = NoContent::accepted_types();\n\t\tlet schema = ::schema(StatusCode::NO_CONTENT);\n\t\tlet content =\n\t\t\tOperationDescription::schema_to_content(types.or_all_types(), Item(schema.schema));\n\t\tassert!(content.is_empty());\n\t}\n\n\t#[test]\n\tfn raw_schema_to_content() {\n\t\tlet types = Raw::<&str>::accepted_types();\n\t\tlet schema = as ResponseSchema>::schema(StatusCode::OK);\n\t\tlet content =\n\t\t\tOperationDescription::schema_to_content(types.or_all_types(), Item(schema.schema));\n\t\tassert_eq!(content.len(), 1);\n\t\tlet json = serde_json::to_string(&content.values().nth(0).unwrap()).unwrap();\n\t\tassert_eq!(json, r#\"{\"schema\":{\"type\":\"string\",\"format\":\"binary\"}}\"#);\n\t}\n}\n","traces":[{"line":15,"address":[6227997,6228043,6227440],"length":1,"stats":{"Line":1},"fn_name":"new_parameter_data"},{"line":25,"address":[6227523,6227596],"length":1,"stats":{"Line":2},"fn_name":null},{"line":27,"address":[6227606],"length":1,"stats":{"Line":1},"fn_name":null},{"line":29,"address":[6227677],"length":1,"stats":{"Line":1},"fn_name":null},{"line":42,"address":[6229208,6228064,6229177],"length":1,"stats":{"Line":2},"fn_name":null},{"line":46,"address":[6228104],"length":1,"stats":{"Line":2},"fn_name":null},{"line":47,"address":[6228164],"length":1,"stats":{"Line":1},"fn_name":null},{"line":50,"address":[6228234,6228272],"length":1,"stats":{"Line":2},"fn_name":null},{"line":51,"address":[6228330],"length":1,"stats":{"Line":1},"fn_name":null},{"line":54,"address":[6228552,6228405,6229601],"length":1,"stats":{"Line":3},"fn_name":null},{"line":55,"address":[6228803,6229278],"length":1,"stats":{"Line":2},"fn_name":null},{"line":56,"address":[6229481],"length":1,"stats":{"Line":1},"fn_name":null},{"line":57,"address":[6229305],"length":1,"stats":{"Line":1},"fn_name":null},{"line":58,"address":[6229422],"length":1,"stats":{"Line":1},"fn_name":null},{"line":65,"address":[6229856,6231000,6230969],"length":1,"stats":{"Line":2},"fn_name":null},{"line":69,"address":[6229896],"length":1,"stats":{"Line":2},"fn_name":null},{"line":70,"address":[6229956],"length":1,"stats":{"Line":1},"fn_name":null},{"line":73,"address":[6230026,6230064],"length":1,"stats":{"Line":2},"fn_name":null},{"line":74,"address":[6230122],"length":1,"stats":{"Line":1},"fn_name":null},{"line":77,"address":[6230197,6230344,6231423],"length":1,"stats":{"Line":3},"fn_name":null},{"line":78,"address":[6231070,6230595],"length":1,"stats":{"Line":2},"fn_name":null},{"line":79,"address":[6231281],"length":1,"stats":{"Line":1},"fn_name":null},{"line":80,"address":[6231097],"length":1,"stats":{"Line":1},"fn_name":null},{"line":82,"address":[6231214],"length":1,"stats":{"Line":1},"fn_name":null},{"line":83,"address":[6231273],"length":1,"stats":{"Line":1},"fn_name":null},{"line":88,"address":[6232008,6231969,6231664],"length":1,"stats":{"Line":2},"fn_name":null},{"line":89,"address":[6231686],"length":1,"stats":{"Line":2},"fn_name":null},{"line":90,"address":[6231776],"length":1,"stats":{"Line":2},"fn_name":null},{"line":91,"address":[6231868],"length":1,"stats":{"Line":2},"fn_name":null},{"line":92,"address":[6231935],"length":1,"stats":{"Line":2},"fn_name":null},{"line":111,"address":[6546143,6546069,6545296],"length":1,"stats":{"Line":8},"fn_name":null},{"line":115,"address":[],"length":0,"stats":{"Line":22},"fn_name":null},{"line":116,"address":[],"length":0,"stats":{"Line":12},"fn_name":null},{"line":117,"address":[],"length":0,"stats":{"Line":22},"fn_name":null},{"line":121,"address":[],"length":0,"stats":{"Line":8},"fn_name":null},{"line":123,"address":[],"length":0,"stats":{"Line":8},"fn_name":null},{"line":125,"address":[],"length":0,"stats":{"Line":8},"fn_name":null},{"line":128,"address":[],"length":0,"stats":{"Line":8},"fn_name":null},{"line":132,"address":[6232048,6232127],"length":1,"stats":{"Line":1},"fn_name":null},{"line":133,"address":[6232085,6232169],"length":1,"stats":{"Line":2},"fn_name":null},{"line":136,"address":[6232192,6232285],"length":1,"stats":{"Line":1},"fn_name":null},{"line":137,"address":[6232229,6232327],"length":1,"stats":{"Line":2},"fn_name":null},{"line":140,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":141,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":142,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":145,"address":[6232368,6233609],"length":1,"stats":{"Line":3},"fn_name":null},{"line":149,"address":[6232410],"length":1,"stats":{"Line":3},"fn_name":null},{"line":150,"address":[6232484,6232573],"length":1,"stats":{"Line":6},"fn_name":null},{"line":151,"address":[6232847,6233203],"length":1,"stats":{"Line":6},"fn_name":null},{"line":152,"address":[6233113,6233025],"length":1,"stats":{"Line":6},"fn_name":null},{"line":153,"address":[6233123],"length":1,"stats":{"Line":3},"fn_name":null},{"line":156,"address":[6232867],"length":1,"stats":{"Line":3},"fn_name":null},{"line":159,"address":[6233664,6237369,6237629],"length":1,"stats":{"Line":2},"fn_name":null},{"line":161,"address":[6233731,6234085],"length":1,"stats":{"Line":4},"fn_name":null},{"line":162,"address":[6234332],"length":1,"stats":{"Line":2},"fn_name":null},{"line":163,"address":[6234372],"length":1,"stats":{"Line":2},"fn_name":null},{"line":164,"address":[6234412],"length":1,"stats":{"Line":2},"fn_name":null},{"line":165,"address":[6234444],"length":1,"stats":{"Line":2},"fn_name":null},{"line":166,"address":[6234500],"length":1,"stats":{"Line":2},"fn_name":null},{"line":167,"address":[6234533],"length":1,"stats":{"Line":2},"fn_name":null},{"line":168,"address":[6234551],"length":1,"stats":{"Line":2},"fn_name":null},{"line":169,"address":[6234591],"length":1,"stats":{"Line":2},"fn_name":null},{"line":171,"address":[6233811],"length":1,"stats":{"Line":2},"fn_name":null},{"line":172,"address":[6233841],"length":1,"stats":{"Line":2},"fn_name":null},{"line":173,"address":[6233871],"length":1,"stats":{"Line":2},"fn_name":null},{"line":174,"address":[6233901],"length":1,"stats":{"Line":2},"fn_name":null},{"line":175,"address":[6233981],"length":1,"stats":{"Line":2},"fn_name":null},{"line":176,"address":[6233993],"length":1,"stats":{"Line":2},"fn_name":null},{"line":177,"address":[6234045],"length":1,"stats":{"Line":2},"fn_name":null},{"line":178,"address":[6234075],"length":1,"stats":{"Line":2},"fn_name":null},{"line":181,"address":[6234609,6234745],"length":1,"stats":{"Line":4},"fn_name":null},{"line":183,"address":[6238016,6234737,6238059,6239193,6239138],"length":1,"stats":{"Line":6},"fn_name":"{closure#0}"},{"line":185,"address":[6238119,6238194],"length":1,"stats":{"Line":4},"fn_name":null},{"line":187,"address":[6238340,6238282],"length":1,"stats":{"Line":4},"fn_name":null},{"line":188,"address":[6238579],"length":1,"stats":{"Line":2},"fn_name":null},{"line":189,"address":[6238358],"length":1,"stats":{"Line":2},"fn_name":null},{"line":191,"address":[6239232,6239254],"length":1,"stats":{"Line":4},"fn_name":"{closure#0}"},{"line":193,"address":[6238432],"length":1,"stats":{"Line":2},"fn_name":null},{"line":194,"address":[6238528],"length":1,"stats":{"Line":2},"fn_name":null},{"line":200,"address":[6239280,6234807,6239765],"length":1,"stats":{"Line":3},"fn_name":"{closure#1}"},{"line":201,"address":[6239535,6239302],"length":1,"stats":{"Line":2},"fn_name":null},{"line":202,"address":[6239410,6239318],"length":1,"stats":{"Line":2},"fn_name":null},{"line":204,"address":[6239479],"length":1,"stats":{"Line":1},"fn_name":null},{"line":208,"address":[6234971],"length":1,"stats":{"Line":2},"fn_name":null},{"line":209,"address":[6234983,6235652],"length":1,"stats":{"Line":3},"fn_name":null},{"line":210,"address":[6235017],"length":1,"stats":{"Line":1},"fn_name":null},{"line":211,"address":[6235068,6235141,6237726],"length":1,"stats":{"Line":2},"fn_name":null},{"line":212,"address":[6235290],"length":1,"stats":{"Line":1},"fn_name":null},{"line":216,"address":[6234987],"length":1,"stats":{"Line":2},"fn_name":null},{"line":219,"address":[6235737],"length":1,"stats":{"Line":2},"fn_name":null},{"line":221,"address":[6236057],"length":1,"stats":{"Line":2},"fn_name":null}],"covered":91,"coverable":91},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","openapi","router.rs"],"content":"use super::{\n\tbuilder::OpenapiBuilder,\n\thandler::{OpenapiDocHandler, OpenapiSpecHandler},\n\toperation::OperationDescription\n};\nuse crate::{routing::*, EndpointWithSchema, ResourceWithSchema, ResponseSchema};\nuse gotham::{\n\thyper::{Method, StatusCode},\n\tpipeline::PipelineHandleChain,\n\tprelude::*,\n\trouter::builder::{RouterBuilder, ScopeBuilder}\n};\nuse lazy_regex::regex_replace_all;\nuse openapi_type::OpenapiType;\nuse std::{collections::HashMap, panic::RefUnwindSafe};\n\n/// This trait adds the `openapi_spec` and `openapi_doc` method to an OpenAPI-aware router.\npub trait GetOpenapi {\n\t/// Register a GET route to `path` that returns the OpenAPI specification in JSON format.\n\tfn openapi_spec(&mut self, path: &str);\n\n\t/// Register a GET route to `path` that returns the OpenAPI documentation in HTML format.\n\tfn openapi_doc(&mut self, path: &str);\n}\n\n#[derive(Debug)]\npub struct OpenapiRouter<'a, D> {\n\tpub(crate) router: &'a mut D,\n\tpub(crate) scope: Option<&'a str>,\n\tpub(crate) openapi_builder: &'a mut OpenapiBuilder\n}\n\nmacro_rules! implOpenapiRouter {\n\t($implType:ident) => {\n\t\timpl<'a, 'b, C, P> OpenapiRouter<'a, $implType<'b, C, P>>\n\t\twhere\n\t\t\tC: PipelineHandleChain

+ Copy + Send + Sync + 'static,\n\t\t\tP: RefUnwindSafe + Send + Sync + 'static\n\t\t{\n\t\t\tpub fn scope(&mut self, path: &str, callback: F)\n\t\t\twhere\n\t\t\t\tF: FnOnce(&mut OpenapiRouter<'_, ScopeBuilder<'_, C, P>>)\n\t\t\t{\n\t\t\t\tlet mut openapi_builder = self.openapi_builder.clone();\n\t\t\t\tlet new_scope = self\n\t\t\t\t\t.scope\n\t\t\t\t\t.map(|scope| format!(\"{scope}/{path}\").replace(\"//\", \"/\"));\n\t\t\t\tself.router.scope(path, |router| {\n\t\t\t\t\tlet mut router = OpenapiRouter {\n\t\t\t\t\t\trouter,\n\t\t\t\t\t\tscope: Some(new_scope.as_ref().map(String::as_ref).unwrap_or(path)),\n\t\t\t\t\t\topenapi_builder: &mut openapi_builder\n\t\t\t\t\t};\n\t\t\t\t\tcallback(&mut router);\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\timpl<'a, 'b, C, P> GetOpenapi for OpenapiRouter<'a, $implType<'b, C, P>>\n\t\twhere\n\t\t\tC: PipelineHandleChain

+ Copy + Send + Sync + 'static,\n\t\t\tP: RefUnwindSafe + Send + Sync + 'static\n\t\t{\n\t\t\tfn openapi_spec(&mut self, path: &str) {\n\t\t\t\tself.router\n\t\t\t\t\t.get(path)\n\t\t\t\t\t.to_new_handler(OpenapiSpecHandler::new(\n\t\t\t\t\t\tself.openapi_builder.openapi.clone()\n\t\t\t\t\t));\n\t\t\t}\n\n\t\t\tfn openapi_doc(&mut self, path: &str) {\n\t\t\t\tself.router\n\t\t\t\t\t.get(path)\n\t\t\t\t\t.to_new_handler(OpenapiDocHandler::new(self.openapi_builder.openapi.clone()));\n\t\t\t}\n\t\t}\n\n\t\timpl<'a, 'b, C, P> DrawResourcesWithSchema for OpenapiRouter<'a, $implType<'b, C, P>>\n\t\twhere\n\t\t\tC: PipelineHandleChain

+ Copy + Send + Sync + 'static,\n\t\t\tP: RefUnwindSafe + Send + Sync + 'static\n\t\t{\n\t\t\tfn resource(&mut self, mut path: &str) {\n\t\t\t\tif path.starts_with('/') {\n\t\t\t\t\tpath = &path[1..];\n\t\t\t\t}\n\t\t\t\tR::setup((self, path));\n\t\t\t}\n\t\t}\n\n\t\timpl<'a, 'b, C, P> DrawResourceRoutesWithSchema\n\t\t\tfor (&mut OpenapiRouter<'a, $implType<'b, C, P>>, &str)\n\t\twhere\n\t\t\tC: PipelineHandleChain

+ Copy + Send + Sync + 'static,\n\t\t\tP: RefUnwindSafe + Send + Sync + 'static\n\t\t{\n\t\t\tfn endpoint(&mut self) {\n\t\t\t\tlet mut responses: HashMap = HashMap::new();\n\t\t\t\tfor code in E::Output::status_codes() {\n\t\t\t\t\tresponses.insert(\n\t\t\t\t\t\tcode,\n\t\t\t\t\t\t(self.0).openapi_builder.add_schema(E::Output::schema(code))\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tlet mut path = format!(\"{}/{}\", self.0.scope.unwrap_or_default(), self.1);\n\t\t\t\tlet mut descr = OperationDescription::new::(responses, &path);\n\t\t\t\tif E::has_placeholders() {\n\t\t\t\t\tdescr.set_path_params(E::Placeholders::schema());\n\t\t\t\t}\n\t\t\t\tif E::needs_params() {\n\t\t\t\t\tdescr.set_query_params(E::Params::schema());\n\t\t\t\t}\n\t\t\t\tif E::needs_body() {\n\t\t\t\t\tlet body_schema = (self.0).openapi_builder.add_schema(E::Body::schema());\n\t\t\t\t\tdescr.set_body::(body_schema);\n\t\t\t\t}\n\n\t\t\t\tlet uri: &str = &E::uri();\n\t\t\t\tlet uri =\n\t\t\t\t\tregex_replace_all!(r#\"(^|/):([^/]+)(/|$)\"#, uri, |_, prefix, name, suffix| {\n\t\t\t\t\t\tformat!(\"{prefix}{{{name}}}{suffix}\")\n\t\t\t\t\t});\n\t\t\t\tif !uri.is_empty() {\n\t\t\t\t\tpath = format!(\"{path}/{uri}\");\n\t\t\t\t}\n\n\t\t\t\tlet op = descr.into_operation();\n\t\t\t\tlet mut item = (self.0).openapi_builder.remove_path(&path);\n\t\t\t\tmatch E::http_method() {\n\t\t\t\t\tMethod::GET => item.get = Some(op),\n\t\t\t\t\tMethod::PUT => item.put = Some(op),\n\t\t\t\t\tMethod::POST => item.post = Some(op),\n\t\t\t\t\tMethod::DELETE => item.delete = Some(op),\n\t\t\t\t\tMethod::OPTIONS => item.options = Some(op),\n\t\t\t\t\tMethod::HEAD => item.head = Some(op),\n\t\t\t\t\tMethod::PATCH => item.patch = Some(op),\n\t\t\t\t\tMethod::TRACE => item.trace = Some(op),\n\t\t\t\t\tmethod => {\n\t\t\t\t\t\twarn!(\"Ignoring unsupported method '{method}' in OpenAPI Specification\")\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\t(self.0).openapi_builder.add_path(path, item);\n\n\t\t\t\t(&mut *(self.0).router, self.1).endpoint::()\n\t\t\t}\n\t\t}\n\t};\n}\n\nimplOpenapiRouter!(RouterBuilder);\nimplOpenapiRouter!(ScopeBuilder);\n","traces":[{"line":40,"address":[6846064,6846386,6847136,6847458],"length":1,"stats":{"Line":2},"fn_name":null},{"line":44,"address":[6847163,6846091,6846165,6847237],"length":1,"stats":{"Line":4},"fn_name":null},{"line":45,"address":[6846170,6846188,6847242,6847260],"length":1,"stats":{"Line":4},"fn_name":null},{"line":47,"address":[6847921,6846796,6846704,6847776,6847868,6846183,6846849,6847255],"length":1,"stats":{"Line":5},"fn_name":"{closure#0}<(), (), openapi_supports_scope::openapi_supports_scope::{closure#0}::{closure#0}::{closure#0}::{closure_env#0}>"},{"line":48,"address":[6846673,6847320,6846416,6846248,6847488,6847745],"length":1,"stats":{"Line":4},"fn_name":"{closure#1}<(), (), openapi_supports_scope::openapi_supports_scope::{closure#0}::{closure#0}::{closure#0}::{closure_env#0}>"},{"line":49,"address":[6846608,6846441,6847680,6847513],"length":1,"stats":{"Line":4},"fn_name":null},{"line":51,"address":[6846451,6846513,6847585,6847523],"length":1,"stats":{"Line":4},"fn_name":null},{"line":52,"address":[6847676,6846604],"length":1,"stats":{"Line":2},"fn_name":null},{"line":54,"address":[6847710,6846638],"length":1,"stats":{"Line":2},"fn_name":null},{"line":64,"address":[6854592,6854772,6854748],"length":1,"stats":{"Line":2},"fn_name":"openapi_spec<(), ()>"},{"line":65,"address":[6854622,6854721],"length":1,"stats":{"Line":4},"fn_name":null},{"line":67,"address":[6854700],"length":1,"stats":{"Line":2},"fn_name":null},{"line":68,"address":[6854650],"length":1,"stats":{"Line":2},"fn_name":null},{"line":84,"address":[6854784,6854928],"length":1,"stats":{"Line":6},"fn_name":"resource<(), (), openapi_supports_scope::FooResource>"},{"line":85,"address":[6854952,6854808,6855069,6854925],"length":1,"stats":{"Line":7},"fn_name":null},{"line":86,"address":[6855022,6854878],"length":1,"stats":{"Line":1},"fn_name":null},{"line":88,"address":[6854982,6854838],"length":1,"stats":{"Line":6},"fn_name":null},{"line":98,"address":[6862112,6867575,6860535,6855072,6861161,6868201],"length":1,"stats":{"Line":9},"fn_name":"endpoint<(), (), openapi_supports_scope::read_all___gotham_restful_endpoint>"},{"line":99,"address":[6855125,6862165],"length":1,"stats":{"Line":9},"fn_name":null},{"line":100,"address":[6855274,6862314,6862378,6855338],"length":1,"stats":{"Line":18},"fn_name":null},{"line":101,"address":[6861105,6868145],"length":1,"stats":{"Line":9},"fn_name":null},{"line":103,"address":[6855561,6861070,6862601,6868110],"length":1,"stats":{"Line":18},"fn_name":null},{"line":106,"address":[6855605,6862645,6855897,6862937,6855790,6862830],"length":1,"stats":{"Line":27},"fn_name":null},{"line":107,"address":[6856031,6863071,6868061,6861021],"length":1,"stats":{"Line":9},"fn_name":null},{"line":108,"address":[6856292,6863332,6856230,6863270],"length":1,"stats":{"Line":18},"fn_name":null},{"line":109,"address":[6856312,6863352],"length":1,"stats":{"Line":4},"fn_name":null},{"line":111,"address":[6863407,6856367,6863338,6856298],"length":1,"stats":{"Line":18},"fn_name":null},{"line":112,"address":[6863427,6856387],"length":1,"stats":{"Line":1},"fn_name":null},{"line":114,"address":[6863413,6856373,6856442,6863482],"length":1,"stats":{"Line":18},"fn_name":null},{"line":115,"address":[6856471,6863511],"length":1,"stats":{"Line":2},"fn_name":null},{"line":116,"address":[6856556,6863596],"length":1,"stats":{"Line":2},"fn_name":null},{"line":119,"address":[6856456,6856660,6863496,6863605,6863700,6856565],"length":1,"stats":{"Line":27},"fn_name":null},{"line":121,"address":[6422233,6421888,6422013,6422208,6422333,6422491,6421913,6422171],"length":1,"stats":{"Line":62},"fn_name":"{closure#0}"},{"line":122,"address":[6861954,6869042],"length":1,"stats":{"Line":4},"fn_name":null},{"line":124,"address":[6856764,6856859,6857438,6863804,6863899,6864478],"length":1,"stats":{"Line":23},"fn_name":null},{"line":125,"address":[6857186,6864226],"length":1,"stats":{"Line":5},"fn_name":null},{"line":128,"address":[6857451,6856967,6864007,6864491],"length":1,"stats":{"Line":18},"fn_name":null},{"line":129,"address":[6857459,6864499,6864610,6857570],"length":1,"stats":{"Line":18},"fn_name":null},{"line":130,"address":[6857669,6864757,6857717,6864709],"length":1,"stats":{"Line":18},"fn_name":null},{"line":131,"address":[6865017,6865927,6858887,6857977],"length":1,"stats":{"Line":7},"fn_name":null},{"line":132,"address":[6859098,6858213,6865253,6866138],"length":1,"stats":{"Line":1},"fn_name":null},{"line":133,"address":[6865135,6858984,6866024,6858095],"length":1,"stats":{"Line":0},"fn_name":null},{"line":134,"address":[6858331,6865371,6859212,6866252],"length":1,"stats":{"Line":0},"fn_name":null},{"line":135,"address":[6864899,6858743,6857859,6865783],"length":1,"stats":{"Line":0},"fn_name":null},{"line":136,"address":[6866366,6865483,6858443,6859326],"length":1,"stats":{"Line":0},"fn_name":null},{"line":137,"address":[6859554,6866594,6858643,6865683],"length":1,"stats":{"Line":1},"fn_name":null},{"line":138,"address":[6859440,6865583,6866480,6858543],"length":1,"stats":{"Line":0},"fn_name":null},{"line":139,"address":[6864811,6857771],"length":1,"stats":{"Line":0},"fn_name":null},{"line":140,"address":[6857811,6866961,6859789,6864851,6866759,6859921,6866829,6859719],"length":1,"stats":{"Line":0},"fn_name":null},{"line":143,"address":[6860091,6867131],"length":1,"stats":{"Line":9},"fn_name":null},{"line":145,"address":[6867343,6860303],"length":1,"stats":{"Line":9},"fn_name":null}],"covered":44,"coverable":51},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","response","auth_result.rs"],"content":"use crate::{IntoResponseError, Response};\nuse gotham::{hyper::StatusCode, mime::TEXT_PLAIN_UTF_8};\nuse gotham_restful_derive::ResourceError;\n#[cfg(feature = \"openapi\")]\nuse openapi_type::{OpenapiSchema, OpenapiType};\n\n/// This is an error type that always yields a _403 Forbidden_ response. This type\n/// is best used in combination with [`AuthSuccess`] or [`AuthResult`].\n#[derive(Clone, Debug)]\npub struct AuthError(String);\n\nimpl AuthError {\n\tpub fn new>(msg: T) -> Self {\n\t\tSelf(msg.into())\n\t}\n}\n\nimpl IntoResponseError for AuthError {\n\t// TODO why does this need to be serde_json::Error ?!?\n\ttype Err = serde_json::Error;\n\n\tfn into_response_error(self) -> Result {\n\t\tOk(Response::new(\n\t\t\tStatusCode::FORBIDDEN,\n\t\t\tself.0,\n\t\t\tSome(TEXT_PLAIN_UTF_8)\n\t\t))\n\t}\n\n\t#[cfg(feature = \"openapi\")]\n\tfn status_codes() -> Vec {\n\t\tvec![StatusCode::FORBIDDEN]\n\t}\n\n\t#[cfg(feature = \"openapi\")]\n\tfn schema(code: StatusCode) -> OpenapiSchema {\n\t\tassert_eq!(code, StatusCode::FORBIDDEN);\n\t\t as OpenapiType>::schema()\n\t}\n}\n\n/// This return type can be used to wrap any type implementing [IntoResponse](crate::IntoResponse)\n/// that can only be returned if the client is authenticated. Otherwise, an empty _403 Forbidden_\n/// response will be issued.\n///\n/// Use can look something like this (assuming the `auth` feature is enabled):\n///\n/// ```rust\n/// # #[macro_use] extern crate gotham_restful_derive;\n/// # #[cfg(feature = \"auth\")]\n/// # mod auth_feature_enabled {\n/// # use gotham::state::State;\n/// # use gotham_restful::*;\n/// # use serde::Deserialize;\n/// #\n/// # #[derive(Resource)]\n/// # #[resource(read_all)]\n/// # struct MyResource;\n/// #\n/// # #[derive(Clone, Deserialize)]\n/// # struct MyAuthData { exp : u64 }\n/// #\n/// #[read_all]\n/// fn read_all(auth: AuthStatus) -> AuthSuccess {\n/// \tlet auth_data = auth.ok()?;\n/// \t// do something\n/// \tOk(NoContent::default())\n/// }\n/// # }\n/// ```\npub type AuthSuccess = Result;\n\n/// This is an error type that either yields a _403 Forbidden_ response if produced\n/// from an authentication error, or delegates to another error type. This type is\n/// best used with [`AuthResult`].\n#[derive(Debug, Clone, ResourceError)]\npub enum AuthErrorOrOther {\n\tForbidden(#[from] AuthError),\n\n\t#[status(INTERNAL_SERVER_ERROR)]\n\t#[display(\"{0}\")]\n\tOther(E)\n}\n\nmod private {\n\tuse gotham::handler::HandlerError;\n\tpub trait Sealed {}\n\timpl> Sealed for E {}\n}\n\nimpl From for AuthErrorOrOther\nwhere\n\t// TODO https://github.com/msrd0/gotham_restful/issues/20\n\tF: private::Sealed + Into\n{\n\tfn from(err: F) -> Self {\n\t\tSelf::Other(err.into())\n\t}\n}\n\n/// This return type can be used to wrap any type implementing [IntoResponse](crate::IntoResponse)\n/// that can only be returned if the client is authenticated. Otherwise, an empty _403 Forbidden_\n/// response will be issued.\n///\n/// Use can look something like this (assuming the `auth` feature is enabled):\n///\n/// ```\n/// # #[macro_use] extern crate gotham_restful_derive;\n/// # #[cfg(feature = \"auth\")]\n/// # mod auth_feature_enabled {\n/// # use gotham::state::State;\n/// # use gotham_restful::*;\n/// # use serde::Deserialize;\n/// # use std::io;\n/// #\n/// # #[derive(Resource)]\n/// # #[resource(read_all)]\n/// # struct MyResource;\n/// #\n/// # #[derive(Clone, Deserialize)]\n/// # struct MyAuthData { exp : u64 }\n/// #\n/// #[read_all]\n/// fn read_all(auth: AuthStatus) -> AuthResult {\n/// \tlet auth_data = auth.ok()?;\n/// \t// do something\n/// \tOk(NoContent::default().into())\n/// }\n/// # }\n/// ```\npub type AuthResult = Result>;\n","traces":[{"line":13,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":14,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":22,"address":[7643984],"length":1,"stats":{"Line":0},"fn_name":"into_response_error"},{"line":23,"address":[8651207],"length":1,"stats":{"Line":0},"fn_name":null},{"line":25,"address":[7835265],"length":1,"stats":{"Line":0},"fn_name":null},{"line":26,"address":[6097652],"length":1,"stats":{"Line":0},"fn_name":null},{"line":31,"address":[6097776],"length":1,"stats":{"Line":1},"fn_name":"status_codes"},{"line":32,"address":[7835512,7835437],"length":1,"stats":{"Line":1},"fn_name":null},{"line":36,"address":[6316160],"length":1,"stats":{"Line":1},"fn_name":"schema"},{"line":38,"address":[6098181],"length":1,"stats":{"Line":1},"fn_name":null},{"line":96,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":97,"address":[],"length":0,"stats":{"Line":0},"fn_name":null}],"covered":4,"coverable":12},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","response","mod.rs"],"content":"use futures_util::future::{self, BoxFuture, FutureExt};\nuse gotham::{\n\thandler::HandlerError,\n\thyper::{\n\t\theader::{HeaderMap, HeaderName, HeaderValue},\n\t\tBody, StatusCode\n\t},\n\tmime::{Mime, APPLICATION_JSON, STAR_STAR}\n};\n#[cfg(feature = \"openapi\")]\nuse openapi_type::{OpenapiSchema, OpenapiType};\nuse serde::Serialize;\n#[cfg(feature = \"errorlog\")]\nuse std::fmt::Display;\nuse std::{convert::Infallible, fmt::Debug, future::Future, pin::Pin};\n\nmod auth_result;\n#[allow(unreachable_pub)]\npub use auth_result::{AuthError, AuthErrorOrOther, AuthResult, AuthSuccess};\n\nmod no_content;\n#[allow(unreachable_pub)]\npub use no_content::NoContent;\n\nmod raw;\n#[allow(unreachable_pub)]\npub use raw::Raw;\n\nmod redirect;\n#[allow(unreachable_pub)]\npub use redirect::Redirect;\n\nmod result;\n#[allow(unreachable_pub)]\npub use result::IntoResponseError;\n\nmod success;\n#[allow(unreachable_pub)]\npub use success::Success;\n\npub(crate) trait OrAllTypes {\n\tfn or_all_types(self) -> Vec;\n}\n\nimpl OrAllTypes for Option> {\n\tfn or_all_types(self) -> Vec {\n\t\tself.unwrap_or_else(|| vec![STAR_STAR])\n\t}\n}\n\n/// A response, used to create the final gotham response from.\n///\n/// This type is not meant to be used as the return type of endpoint handlers. While it can be\n/// freely used without the `openapi` feature, it is more complicated to use when you enable it,\n/// since this type does not store any schema information. You can attach schema information\n/// like so:\n///\n/// ```rust\n/// # #[cfg(feature = \"openapi\")] mod example {\n/// # use gotham::hyper::StatusCode;\n/// # use gotham_restful::*;\n/// # use openapi_type::*;\n/// fn schema(code: StatusCode) -> OpenapiSchema {\n/// \tassert_eq!(code, StatusCode::ACCEPTED);\n/// \t<()>::schema()\n/// }\n///\n/// fn status_codes() -> Vec {\n/// \tvec![StatusCode::ACCEPTED]\n/// }\n///\n/// #[create(schema = \"schema\", status_codes = \"status_codes\")]\n/// fn create(body: Raw>) {}\n/// # }\n/// ```\n#[derive(Debug)]\npub struct Response {\n\tpub(crate) status: StatusCode,\n\tpub(crate) body: Body,\n\tpub(crate) mime: Option,\n\tpub(crate) headers: HeaderMap\n}\n\nimpl Response {\n\t/// Create a new [Response] from raw data.\n\t#[must_use = \"Creating a response is pointless if you don't use it\"]\n\tpub fn new>(status: StatusCode, body: B, mime: Option) -> Self {\n\t\tSelf {\n\t\t\tstatus,\n\t\t\tbody: body.into(),\n\t\t\tmime,\n\t\t\theaders: Default::default()\n\t\t}\n\t}\n\n\t/// Create a [Response] with mime type json from already serialized data.\n\t#[must_use = \"Creating a response is pointless if you don't use it\"]\n\tpub fn json>(status: StatusCode, body: B) -> Self {\n\t\tSelf {\n\t\t\tstatus,\n\t\t\tbody: body.into(),\n\t\t\tmime: Some(APPLICATION_JSON),\n\t\t\theaders: Default::default()\n\t\t}\n\t}\n\n\t/// Create a _204 No Content_ [Response].\n\t#[must_use = \"Creating a response is pointless if you don't use it\"]\n\tpub fn no_content() -> Self {\n\t\tSelf {\n\t\t\tstatus: StatusCode::NO_CONTENT,\n\t\t\tbody: Body::empty(),\n\t\t\tmime: None,\n\t\t\theaders: Default::default()\n\t\t}\n\t}\n\n\t/// Create an empty _403 Forbidden_ [Response].\n\t#[must_use = \"Creating a response is pointless if you don't use it\"]\n\tpub fn forbidden() -> Self {\n\t\tSelf {\n\t\t\tstatus: StatusCode::FORBIDDEN,\n\t\t\tbody: Body::empty(),\n\t\t\tmime: None,\n\t\t\theaders: Default::default()\n\t\t}\n\t}\n\n\t/// Return the status code of this [Response].\n\tpub fn status(&self) -> StatusCode {\n\t\tself.status\n\t}\n\n\t/// Return the mime type of this [Response].\n\tpub fn mime(&self) -> Option<&Mime> {\n\t\tself.mime.as_ref()\n\t}\n\n\t/// Add an HTTP header to the [Response].\n\tpub fn header(&mut self, name: HeaderName, value: HeaderValue) {\n\t\tself.headers.insert(name, value);\n\t}\n\n\tpub(crate) fn with_headers(mut self, headers: HeaderMap) -> Self {\n\t\tself.headers = headers;\n\t\tself\n\t}\n\n\t#[cfg(test)]\n\tpub(crate) fn full_body(\n\t\tmut self\n\t) -> Result, ::Error> {\n\t\tuse futures_executor::block_on;\n\t\tuse gotham::hyper::body::to_bytes;\n\n\t\tlet bytes: &[u8] = &block_on(to_bytes(&mut self.body))?;\n\t\tOk(bytes.to_vec())\n\t}\n}\n\nimpl IntoResponse for Response {\n\ttype Err = Infallible;\n\n\tfn into_response(self) -> BoxFuture<'static, Result> {\n\t\tfuture::ok(self).boxed()\n\t}\n}\n\n/// This trait needs to be implemented by every type returned from an endpoint to\n/// to provide the response.\npub trait IntoResponse {\n\ttype Err: Into + Send + Sync + 'static;\n\n\t/// Turn this into a response that can be returned to the browser. This api will likely\n\t/// change in the future.\n\tfn into_response(self) -> BoxFuture<'static, Result>;\n\n\t/// Return a list of supported mime types.\n\tfn accepted_types() -> Option> {\n\t\tNone\n\t}\n}\n\n/// Additional details for [IntoResponse] to be used with an OpenAPI-aware router.\n#[cfg(feature = \"openapi\")]\npub trait ResponseSchema {\n\t/// All status codes returned by this response. Returns `[StatusCode::OK]` by default.\n\tfn status_codes() -> Vec {\n\t\tvec![StatusCode::OK]\n\t}\n\n\t/// Return the schema of the response for the given status code. The code may\n\t/// only be one that was previously returned by [Self::status_codes]. The\n\t/// implementation should panic if that is not the case.\n\tfn schema(code: StatusCode) -> OpenapiSchema;\n}\n\n#[cfg(feature = \"openapi\")]\nmod private {\n\tpub trait Sealed {}\n}\n\n/// A trait provided to convert a resource's result to json, and provide an OpenAPI schema to the\n/// router. This trait is implemented for all types that implement [IntoResponse] and\n/// [ResponseSchema].\n#[cfg(feature = \"openapi\")]\npub trait IntoResponseWithSchema: IntoResponse + ResponseSchema + private::Sealed {}\n\n#[cfg(feature = \"openapi\")]\nimpl private::Sealed for R {}\n\n#[cfg(feature = \"openapi\")]\nimpl IntoResponseWithSchema for R {}\n\n/// The default json returned on an 500 Internal Server Error.\n#[derive(Debug, Serialize)]\n#[cfg_attr(feature = \"openapi\", derive(OpenapiType))]\npub(crate) struct ResourceError {\n\t/// This is always `true` and can be used to detect an error response without looking at the\n\t/// HTTP status code.\n\terror: bool,\n\t/// The error message.\n\tmessage: String\n}\n\nimpl From for ResourceError {\n\tfn from(message: T) -> Self {\n\t\tSelf {\n\t\t\terror: true,\n\t\t\tmessage: message.to_string()\n\t\t}\n\t}\n}\n\n#[cfg(feature = \"errorlog\")]\nfn errorlog(e: E) {\n\terror!(\"The handler encountered an error: {e}\");\n}\n\n#[cfg(not(feature = \"errorlog\"))]\nfn errorlog(_e: E) {}\n\nfn handle_error(e: E) -> Pin> + Send>>\nwhere\n\tE: Debug + IntoResponseError\n{\n\tlet msg = format!(\"{e:?}\");\n\tlet res = e.into_response_error();\n\tmatch &res {\n\t\tOk(res) if res.status.is_server_error() => errorlog(msg),\n\t\tErr(err) => {\n\t\t\terrorlog(msg);\n\t\t\terrorlog(format!(\"{err:?}\"));\n\t\t},\n\t\t_ => {}\n\t};\n\tfuture::ready(res).boxed()\n}\n\nimpl IntoResponse for Pin + Send>>\nwhere\n\tRes: IntoResponse + 'static\n{\n\ttype Err = Res::Err;\n\n\tfn into_response(self) -> Pin> + Send>> {\n\t\tself.then(IntoResponse::into_response).boxed()\n\t}\n\n\tfn accepted_types() -> Option> {\n\t\tRes::accepted_types()\n\t}\n}\n\n#[cfg(feature = \"openapi\")]\nimpl ResponseSchema for Pin + Send>>\nwhere\n\tRes: ResponseSchema\n{\n\tfn status_codes() -> Vec {\n\t\tRes::status_codes()\n\t}\n\n\tfn schema(code: StatusCode) -> OpenapiSchema {\n\t\tRes::schema(code)\n\t}\n}\n\n#[cfg(test)]\nmod test {\n\tuse super::*;\n\tuse futures_executor::block_on;\n\tuse thiserror::Error;\n\n\t#[derive(Debug, Default, Deserialize, Serialize)]\n\t#[cfg_attr(feature = \"openapi\", derive(openapi_type::OpenapiType))]\n\tstruct Msg {\n\t\tmsg: String\n\t}\n\n\t#[derive(Debug, Default, Error)]\n\t#[error(\"An Error\")]\n\tstruct MsgError;\n\n\t#[test]\n\tfn result_from_future() {\n\t\tlet nc = NoContent::default();\n\t\tlet res = block_on(nc.into_response()).unwrap();\n\n\t\tlet fut_nc = async move { NoContent::default() }.boxed();\n\t\tlet fut_res = block_on(fut_nc.into_response()).unwrap();\n\n\t\tassert_eq!(res.status, fut_res.status);\n\t\tassert_eq!(res.mime, fut_res.mime);\n\t\tassert_eq!(res.full_body().unwrap(), fut_res.full_body().unwrap());\n\t}\n}\n","traces":[{"line":46,"address":[6140320],"length":1,"stats":{"Line":3},"fn_name":"or_all_types"},{"line":47,"address":[6060272,6060289],"length":1,"stats":{"Line":9},"fn_name":"{closure#0}"},{"line":87,"address":[6061328,6060805,6060835,6061681,6061711,6061294,6060448,6060880,6061264],"length":1,"stats":{"Line":8},"fn_name":null},{"line":90,"address":[6060511,6061396,6060971],"length":1,"stats":{"Line":9},"fn_name":null},{"line":92,"address":[6061522,6061105,6060646],"length":1,"stats":{"Line":9},"fn_name":null},{"line":98,"address":[6062161,6061744,6062134],"length":1,"stats":{"Line":2},"fn_name":null},{"line":101,"address":[6061784],"length":1,"stats":{"Line":2},"fn_name":null},{"line":102,"address":[6061798],"length":1,"stats":{"Line":2},"fn_name":null},{"line":103,"address":[6061975],"length":1,"stats":{"Line":3},"fn_name":null},{"line":109,"address":[6062368,6062395,6062176],"length":1,"stats":{"Line":3},"fn_name":null},{"line":112,"address":[6062198],"length":1,"stats":{"Line":4},"fn_name":null},{"line":114,"address":[6062212],"length":1,"stats":{"Line":4},"fn_name":null},{"line":120,"address":[6062416,6062608,6062635],"length":1,"stats":{"Line":0},"fn_name":null},{"line":123,"address":[6062438],"length":1,"stats":{"Line":0},"fn_name":null},{"line":125,"address":[6062452],"length":1,"stats":{"Line":0},"fn_name":null},{"line":130,"address":[6062656],"length":1,"stats":{"Line":1},"fn_name":null},{"line":131,"address":[6062661],"length":1,"stats":{"Line":1},"fn_name":null},{"line":135,"address":[6062672],"length":1,"stats":{"Line":1},"fn_name":null},{"line":136,"address":[6062677],"length":1,"stats":{"Line":1},"fn_name":null},{"line":140,"address":[6062688],"length":1,"stats":{"Line":2},"fn_name":null},{"line":141,"address":[6062706],"length":1,"stats":{"Line":2},"fn_name":null},{"line":144,"address":[6062752,6062957],"length":1,"stats":{"Line":4},"fn_name":null},{"line":145,"address":[6062910,6062784],"length":1,"stats":{"Line":8},"fn_name":null},{"line":146,"address":[6062937],"length":1,"stats":{"Line":4},"fn_name":null},{"line":150,"address":[6062992,6063391,6063414],"length":1,"stats":{"Line":1},"fn_name":null},{"line":156,"address":[6063079,6063289,6063022],"length":1,"stats":{"Line":6},"fn_name":null},{"line":157,"address":[6063305],"length":1,"stats":{"Line":2},"fn_name":null},{"line":164,"address":[6063440],"length":1,"stats":{"Line":0},"fn_name":"into_response"},{"line":165,"address":[6063460],"length":1,"stats":{"Line":0},"fn_name":null},{"line":179,"address":[6023904],"length":1,"stats":{"Line":7},"fn_name":"accepted_types>"},{"line":180,"address":[6023907],"length":1,"stats":{"Line":7},"fn_name":null},{"line":188,"address":[6023920],"length":1,"stats":{"Line":4},"fn_name":"status_codes>"},{"line":189,"address":[6024007,6023933],"length":1,"stats":{"Line":4},"fn_name":null},{"line":227,"address":[6063628,6063504],"length":1,"stats":{"Line":2},"fn_name":"from"},{"line":230,"address":[6063533],"length":1,"stats":{"Line":2},"fn_name":null},{"line":236,"address":[6064051,6063664],"length":1,"stats":{"Line":1},"fn_name":"errorlog"},{"line":237,"address":[6063942,6063757,6063676,6063824],"length":1,"stats":{"Line":3},"fn_name":null},{"line":243,"address":[6065036,6067104,6068060,6066044,6064080,6067082,6068090,6067052,6065066,6066074,6065088,6066096],"length":1,"stats":{"Line":1},"fn_name":"handle_error"},{"line":247,"address":[6066258,6064242,6065250,6067266],"length":1,"stats":{"Line":1},"fn_name":null},{"line":248,"address":[6065353,6065417,6064345,6064409,6066361,6067433,6067369,6066425],"length":1,"stats":{"Line":2},"fn_name":null},{"line":249,"address":[6064417,6066433,6065425,6067441],"length":1,"stats":{"Line":1},"fn_name":null},{"line":250,"address":[6065699,6066547,6067715,6065539,6064531,6066707,6064691,6067555],"length":1,"stats":{"Line":2},"fn_name":null},{"line":251,"address":[6064581,6067605,6066597,6065589],"length":1,"stats":{"Line":0},"fn_name":null},{"line":252,"address":[6065605,6064597,6067621,6066613],"length":1,"stats":{"Line":0},"fn_name":null},{"line":253,"address":[6064837,6067861,6066853,6065845],"length":1,"stats":{"Line":0},"fn_name":null},{"line":255,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":257,"address":[6067111,6067481,6066103,6064457,6065951,6064943,6066473,6065465,6066959,6064087,6067967,6065095],"length":1,"stats":{"Line":3},"fn_name":null},{"line":266,"address":[6239808],"length":1,"stats":{"Line":1},"fn_name":"into_response"},{"line":267,"address":[6239838],"length":1,"stats":{"Line":1},"fn_name":null},{"line":270,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":271,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":280,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":281,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":284,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":285,"address":[],"length":0,"stats":{"Line":0},"fn_name":null}],"covered":40,"coverable":55},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","response","no_content.rs"],"content":"use super::{handle_error, IntoResponse};\n#[cfg(feature = \"openapi\")]\nuse crate::ResponseSchema;\nuse crate::{IntoResponseError, Response};\nuse futures_util::{future, future::FutureExt};\n#[cfg(feature = \"openapi\")]\nuse gotham::hyper::StatusCode;\nuse gotham::{\n\thyper::header::{HeaderMap, HeaderValue, IntoHeaderName},\n\tmime::Mime\n};\n#[cfg(feature = \"openapi\")]\nuse openapi_type::{OpenapiSchema, OpenapiType};\nuse std::{fmt::Debug, future::Future, pin::Pin};\n\n/// This is the return type of a resource that doesn't actually return something. It will result\n/// in a _204 No Content_ answer by default. You don't need to use this type directly if using\n/// the function attributes:\n///\n/// ```\n/// # #[macro_use] extern crate gotham_restful_derive;\n/// # mod doc_tests_are_broken {\n/// # use gotham::state::State;\n/// # use gotham_restful::*;\n/// #\n/// # #[derive(Resource)]\n/// # #[resource(read_all)]\n/// # struct MyResource;\n/// #\n/// #[read_all]\n/// fn read_all() {\n/// \t// do something\n/// }\n/// # }\n/// ```\n#[derive(Clone, Debug, Default)]\npub struct NoContent {\n\theaders: HeaderMap\n}\n\nimpl From<()> for NoContent {\n\tfn from(_: ()) -> Self {\n\t\tSelf::default()\n\t}\n}\n\nimpl NoContent {\n\t/// Set a custom HTTP header. If a header with this name was set before, its value is being updated.\n\tpub fn header(&mut self, name: K, value: HeaderValue) {\n\t\tself.headers.insert(name, value);\n\t}\n\n\t/// Allow manipulating HTTP headers.\n\tpub fn headers_mut(&mut self) -> &mut HeaderMap {\n\t\t&mut self.headers\n\t}\n}\n\nimpl IntoResponse for NoContent {\n\t// TODO this shouldn't be a serde_json::Error\n\ttype Err = serde_json::Error; // just for easier handling of `Result`\n\n\t/// This will always be a _204 No Content_ together with an empty string.\n\tfn into_response(self) -> Pin> + Send>> {\n\t\tfuture::ok(Response::no_content().with_headers(self.headers)).boxed()\n\t}\n\n\tfn accepted_types() -> Option> {\n\t\tSome(Vec::new())\n\t}\n}\n\n#[cfg(feature = \"openapi\")]\nimpl ResponseSchema for NoContent {\n\tfn status_codes() -> Vec {\n\t\tvec![StatusCode::NO_CONTENT]\n\t}\n\n\t/// Returns the schema of the `()` type.\n\tfn schema(code: StatusCode) -> OpenapiSchema {\n\t\tassert_eq!(code, StatusCode::NO_CONTENT);\n\t\t<()>::schema()\n\t}\n}\n\nimpl IntoResponse for Result\nwhere\n\tE: Debug + IntoResponseError\n{\n\ttype Err = serde_json::Error;\n\n\tfn into_response(\n\t\tself\n\t) -> Pin> + Send>> {\n\t\tmatch self {\n\t\t\tOk(nc) => nc.into_response(),\n\t\t\tErr(e) => handle_error(e)\n\t\t}\n\t}\n\n\tfn accepted_types() -> Option> {\n\t\tNoContent::accepted_types()\n\t}\n}\n\n#[cfg(feature = \"openapi\")]\nimpl ResponseSchema for Result\nwhere\n\tE: Debug + IntoResponseError\n{\n\tfn status_codes() -> Vec {\n\t\tlet mut status_codes = E::status_codes();\n\t\tstatus_codes.push(StatusCode::NO_CONTENT);\n\t\tstatus_codes\n\t}\n\n\tfn schema(code: StatusCode) -> OpenapiSchema {\n\t\tmatch code {\n\t\t\tStatusCode::NO_CONTENT => ::schema(StatusCode::NO_CONTENT),\n\t\t\tcode => E::schema(code)\n\t\t}\n\t}\n}\n\n#[cfg(test)]\nmod test {\n\tuse super::*;\n\tuse futures_executor::block_on;\n\tuse gotham::hyper::{header::ACCESS_CONTROL_ALLOW_ORIGIN, StatusCode};\n\tuse thiserror::Error;\n\n\t#[derive(Debug, Default, Error)]\n\t#[error(\"An Error\")]\n\tstruct MsgError;\n\n\t#[test]\n\tfn no_content_has_empty_response() {\n\t\tlet no_content = NoContent::default();\n\t\tlet res = block_on(no_content.into_response()).expect(\"didn't expect error response\");\n\t\tassert_eq!(res.status, StatusCode::NO_CONTENT);\n\t\tassert_eq!(res.mime, None);\n\t\tassert_eq!(res.full_body().unwrap(), &[] as &[u8]);\n\n\t\t#[cfg(feature = \"openapi\")]\n\t\tassert_eq!(NoContent::status_codes(), vec![StatusCode::NO_CONTENT]);\n\t}\n\n\t#[test]\n\tfn no_content_result() {\n\t\tlet no_content: Result = Ok(NoContent::default());\n\t\tlet res = block_on(no_content.into_response()).expect(\"didn't expect error response\");\n\t\tassert_eq!(res.status, StatusCode::NO_CONTENT);\n\t\tassert_eq!(res.mime, None);\n\t\tassert_eq!(res.full_body().unwrap(), &[] as &[u8]);\n\n\t\t#[cfg(feature = \"openapi\")]\n\t\tassert_eq!(>::status_codes(), vec![\n\t\t\tStatusCode::INTERNAL_SERVER_ERROR,\n\t\t\tStatusCode::NO_CONTENT\n\t\t]);\n\t}\n\n\t#[test]\n\tfn no_content_custom_headers() {\n\t\tlet mut no_content = NoContent::default();\n\t\tno_content.header(ACCESS_CONTROL_ALLOW_ORIGIN, HeaderValue::from_static(\"*\"));\n\t\tlet res = block_on(no_content.into_response()).expect(\"didn't expect error response\");\n\t\tlet cors = res.headers.get(ACCESS_CONTROL_ALLOW_ORIGIN);\n\t\tassert_eq!(cors.map(|value| value.to_str().unwrap()), Some(\"*\"));\n\t}\n}\n","traces":[{"line":42,"address":[6383152],"length":1,"stats":{"Line":0},"fn_name":"from"},{"line":43,"address":[6383164],"length":1,"stats":{"Line":0},"fn_name":null},{"line":49,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":50,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":54,"address":[6383184],"length":1,"stats":{"Line":0},"fn_name":null},{"line":64,"address":[6022209,6021952,6022240],"length":1,"stats":{"Line":2},"fn_name":"into_response"},{"line":65,"address":[6383293,6383212],"length":1,"stats":{"Line":6},"fn_name":null},{"line":68,"address":[6383520],"length":1,"stats":{"Line":5},"fn_name":"accepted_types"},{"line":69,"address":[6383533],"length":1,"stats":{"Line":3},"fn_name":null},{"line":75,"address":[6022320],"length":1,"stats":{"Line":2},"fn_name":"status_codes"},{"line":76,"address":[6022333,6022407],"length":1,"stats":{"Line":2},"fn_name":null},{"line":80,"address":[6383696],"length":1,"stats":{"Line":2},"fn_name":"schema"},{"line":82,"address":[6022725],"length":1,"stats":{"Line":2},"fn_name":null},{"line":92,"address":[6290352],"length":1,"stats":{"Line":1},"fn_name":"into_response"},{"line":95,"address":[6290442,6290364],"length":1,"stats":{"Line":2},"fn_name":null},{"line":96,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":97,"address":[6290427],"length":1,"stats":{"Line":0},"fn_name":null},{"line":101,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":102,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":111,"address":[6290464,6290579],"length":1,"stats":{"Line":1},"fn_name":"status_codes"},{"line":112,"address":[6290488],"length":1,"stats":{"Line":1},"fn_name":null},{"line":113,"address":[6290503],"length":1,"stats":{"Line":1},"fn_name":null},{"line":114,"address":[6290548],"length":1,"stats":{"Line":1},"fn_name":null},{"line":117,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":118,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":119,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":120,"address":[],"length":0,"stats":{"Line":0},"fn_name":null}],"covered":17,"coverable":27},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","response","raw.rs"],"content":"use super::{handle_error, IntoResponse, IntoResponseError};\nuse crate::{types::ResourceType, FromBody, RequestBody, Response};\n#[cfg(feature = \"openapi\")]\nuse crate::{IntoResponseWithSchema, ResponseSchema};\nuse futures_core::future::Future;\nuse futures_util::{future, future::FutureExt};\nuse gotham::{\n\thyper::{\n\t\tbody::{Body, Bytes},\n\t\tStatusCode\n\t},\n\tmime::Mime\n};\n#[cfg(feature = \"openapi\")]\nuse openapi_type::{OpenapiSchema, OpenapiType, Visitor};\nuse serde_json::error::Error as SerdeJsonError;\nuse std::{convert::Infallible, fmt::Debug, pin::Pin};\n\n/// This type can be used both as a raw request body, as well as as a raw response. However, all types\n/// of request bodies are accepted by this type. It is therefore recommended to derive your own type\n/// from [RequestBody] and only use this when you need to return a raw response. This is a usage\n/// example that simply returns its body:\n///\n/// ```rust,no_run\n/// # #[macro_use] extern crate gotham_restful_derive;\n/// # use gotham::router::builder::*;\n/// # use gotham_restful::*;\n/// #[derive(Resource)]\n/// #[resource(create)]\n/// struct ImageResource;\n///\n/// #[create]\n/// fn create(body: Raw>) -> Raw> {\n/// \tbody\n/// }\n/// # fn main() {\n/// # \tgotham::start(\"127.0.0.1:8080\", build_simple_router(|route| {\n/// # \t\troute.resource::(\"img\");\n/// # \t}));\n/// # }\n/// ```\n#[derive(Debug)]\npub struct Raw {\n\tpub raw: T,\n\tpub mime: Mime\n}\n\nimpl Raw {\n\tpub fn new(raw: T, mime: Mime) -> Self {\n\t\tSelf { raw, mime }\n\t}\n}\n\nimpl AsMut for Raw\nwhere\n\tT: AsMut\n{\n\tfn as_mut(&mut self) -> &mut U {\n\t\tself.raw.as_mut()\n\t}\n}\n\nimpl AsRef for Raw\nwhere\n\tT: AsRef\n{\n\tfn as_ref(&self) -> &U {\n\t\tself.raw.as_ref()\n\t}\n}\n\nimpl Clone for Raw {\n\tfn clone(&self) -> Self {\n\t\tSelf {\n\t\t\traw: self.raw.clone(),\n\t\t\tmime: self.mime.clone()\n\t\t}\n\t}\n}\n\nimpl From<&'a [u8]>> FromBody for Raw {\n\ttype Err = Infallible;\n\n\tfn from_body(body: Bytes, mime: Mime) -> Result {\n\t\tOk(Self::new(body.as_ref().into(), mime))\n\t}\n}\n\nimpl RequestBody for Raw where Raw: FromBody + ResourceType {}\n\n#[cfg(feature = \"openapi\")]\nimpl OpenapiType for Raw {\n\tfn visit_type(visitor: &mut V) {\n\t\tvisitor.visit_binary()\n\t}\n}\n\nimpl> IntoResponse for Raw\nwhere\n\tSelf: Send\n{\n\ttype Err = SerdeJsonError; // just for easier handling of `Result, E>`\n\n\tfn into_response(\n\t\tself\n\t) -> Pin> + Send>> {\n\t\tfuture::ok(Response::new(StatusCode::OK, self.raw, Some(self.mime))).boxed()\n\t}\n}\n\n#[cfg(feature = \"openapi\")]\nimpl> ResponseSchema for Raw\nwhere\n\tSelf: Send\n{\n\tfn schema(code: StatusCode) -> OpenapiSchema {\n\t\tassert_eq!(code, StatusCode::OK);\n\t\t::schema()\n\t}\n}\n\nimpl IntoResponse for Result, E>\nwhere\n\tRaw: IntoResponse,\n\tE: Debug + IntoResponseError as IntoResponse>::Err>\n{\n\ttype Err = E::Err;\n\n\tfn into_response(self) -> Pin> + Send>> {\n\t\tmatch self {\n\t\t\tOk(raw) => raw.into_response(),\n\t\t\tErr(e) => handle_error(e)\n\t\t}\n\t}\n}\n\n#[cfg(feature = \"openapi\")]\nimpl ResponseSchema for Result, E>\nwhere\n\tRaw: IntoResponseWithSchema,\n\tE: Debug + IntoResponseError as IntoResponse>::Err>\n{\n\tfn status_codes() -> Vec {\n\t\tlet mut status_codes = E::status_codes();\n\t\tstatus_codes.push(StatusCode::OK);\n\t\tstatus_codes\n\t}\n\n\tfn schema(code: StatusCode) -> OpenapiSchema {\n\t\tmatch code {\n\t\t\tStatusCode::OK => as ResponseSchema>::schema(StatusCode::OK),\n\t\t\tcode => E::schema(code)\n\t\t}\n\t}\n}\n\n#[cfg(test)]\nmod test {\n\tuse super::*;\n\tuse futures_executor::block_on;\n\tuse gotham::mime::TEXT_PLAIN;\n\tuse thiserror::Error;\n\n\t#[derive(Debug, Default, Error)]\n\t#[error(\"An Error\")]\n\tstruct MsgError;\n\n\t#[test]\n\tfn raw_response() {\n\t\tlet msg = \"Test\";\n\t\tlet raw = Raw::new(msg, TEXT_PLAIN);\n\t\tlet res = block_on(raw.into_response()).expect(\"didn't expect error response\");\n\t\tassert_eq!(res.status, StatusCode::OK);\n\t\tassert_eq!(res.mime, Some(TEXT_PLAIN));\n\t\tassert_eq!(res.full_body().unwrap(), msg.as_bytes());\n\n\t\t#[cfg(feature = \"openapi\")]\n\t\tassert_eq!(>::status_codes(), vec![StatusCode::OK]);\n\t}\n\n\t#[test]\n\tfn raw_result() {\n\t\tlet msg = \"Test\";\n\t\tlet raw: Result, MsgError> = Ok(Raw::new(msg, TEXT_PLAIN));\n\t\tlet res = block_on(raw.into_response()).expect(\"didn't expect error response\");\n\t\tassert_eq!(res.status, StatusCode::OK);\n\t\tassert_eq!(res.mime, Some(TEXT_PLAIN));\n\t\tassert_eq!(res.full_body().unwrap(), msg.as_bytes());\n\n\t\t#[cfg(feature = \"openapi\")]\n\t\tassert_eq!(, MsgError>>::status_codes(), vec![\n\t\t\tStatusCode::INTERNAL_SERVER_ERROR,\n\t\t\tStatusCode::OK\n\t\t]);\n\t}\n}\n","traces":[{"line":49,"address":[],"length":0,"stats":{"Line":7},"fn_name":null},{"line":58,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":59,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":67,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":68,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":73,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":75,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":76,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":84,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":85,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":93,"address":[6022816,6022832],"length":1,"stats":{"Line":4},"fn_name":"visit_type<&str, openapi_type::visitor::openapi::OpenapiVisitor>"},{"line":94,"address":[6204885],"length":1,"stats":{"Line":4},"fn_name":null},{"line":104,"address":[6022848],"length":1,"stats":{"Line":5},"fn_name":"into_response<&str>"},{"line":107,"address":[6022855],"length":1,"stats":{"Line":5},"fn_name":null},{"line":116,"address":[6023104],"length":1,"stats":{"Line":3},"fn_name":"schema<&str>"},{"line":118,"address":[],"length":0,"stats":{"Line":3},"fn_name":null},{"line":129,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":130,"address":[6290620,6290698],"length":1,"stats":{"Line":2},"fn_name":null},{"line":131,"address":[6290646],"length":1,"stats":{"Line":1},"fn_name":null},{"line":132,"address":[6290683],"length":1,"stats":{"Line":0},"fn_name":null},{"line":143,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":144,"address":[6290744],"length":1,"stats":{"Line":1},"fn_name":null},{"line":145,"address":[6290759],"length":1,"stats":{"Line":1},"fn_name":null},{"line":146,"address":[6290804],"length":1,"stats":{"Line":1},"fn_name":null},{"line":149,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":150,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":151,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":152,"address":[],"length":0,"stats":{"Line":0},"fn_name":null}],"covered":16,"coverable":28},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","response","redirect.rs"],"content":"use super::{handle_error, IntoResponse};\nuse crate::{IntoResponseError, Response};\n#[cfg(feature = \"openapi\")]\nuse crate::{NoContent, ResponseSchema};\nuse futures_util::future::{BoxFuture, FutureExt, TryFutureExt};\nuse gotham::hyper::{\n\theader::{InvalidHeaderValue, LOCATION},\n\tBody, StatusCode\n};\n#[cfg(feature = \"openapi\")]\nuse openapi_type::OpenapiSchema;\nuse std::{error::Error as StdError, fmt::Debug};\nuse thiserror::Error;\n\n/// This is the return type of a resource that only returns a redirect. It will result\n/// in a _303 See Other_ answer, meaning the redirect will always result in a GET request\n/// on the target.\n///\n/// ```\n/// # #[macro_use] extern crate gotham_restful_derive;\n/// # mod doc_tests_are_broken {\n/// # use gotham::state::State;\n/// # use gotham_restful::*;\n/// #\n/// # #[derive(Resource)]\n/// # #[resource(read_all)]\n/// # struct MyResource;\n/// #\n/// #[read_all]\n/// fn read_all() -> Redirect {\n/// \tRedirect {\n/// \t\tto: \"http://localhost:8080/cool/new/location\".to_owned()\n/// \t}\n/// }\n/// # }\n/// ```\n#[derive(Clone, Debug, Default)]\npub struct Redirect {\n\tpub to: String\n}\n\nimpl IntoResponse for Redirect {\n\ttype Err = InvalidHeaderValue;\n\n\tfn into_response(self) -> BoxFuture<'static, Result> {\n\t\tasync move {\n\t\t\tlet mut res = Response::new(StatusCode::SEE_OTHER, Body::empty(), None);\n\t\t\tres.header(LOCATION, self.to.parse()?);\n\t\t\tOk(res)\n\t\t}\n\t\t.boxed()\n\t}\n}\n\n#[cfg(feature = \"openapi\")]\nimpl ResponseSchema for Redirect {\n\tfn status_codes() -> Vec {\n\t\tvec![StatusCode::SEE_OTHER]\n\t}\n\n\tfn schema(code: StatusCode) -> OpenapiSchema {\n\t\tassert_eq!(code, StatusCode::SEE_OTHER);\n\t\t::schema(StatusCode::NO_CONTENT)\n\t}\n}\n\n// private type due to parent mod\n#[derive(Debug, Error)]\npub enum RedirectError {\n\t#[error(\"{0}\")]\n\tInvalidLocation(#[from] InvalidHeaderValue),\n\t#[error(\"{0}\")]\n\tOther(#[source] E)\n}\n\n#[allow(ambiguous_associated_items)] // an enum variant is not a type. never.\nimpl IntoResponse for Result\nwhere\n\tE: Debug + IntoResponseError,\n\t::Err: StdError + Sync\n{\n\ttype Err = RedirectError<::Err>;\n\n\tfn into_response(self) -> BoxFuture<'static, Result> {\n\t\tmatch self {\n\t\t\tOk(nc) => nc.into_response().map_err(Into::into).boxed(),\n\t\t\tErr(e) => handle_error(e).map_err(RedirectError::Other).boxed()\n\t\t}\n\t}\n}\n\n#[cfg(feature = \"openapi\")]\nimpl ResponseSchema for Result\nwhere\n\tE: Debug + IntoResponseError,\n\t::Err: StdError + Sync\n{\n\tfn status_codes() -> Vec {\n\t\tlet mut status_codes = E::status_codes();\n\t\tstatus_codes.push(StatusCode::SEE_OTHER);\n\t\tstatus_codes\n\t}\n\n\tfn schema(code: StatusCode) -> OpenapiSchema {\n\t\tmatch code {\n\t\t\tStatusCode::SEE_OTHER => ::schema(StatusCode::SEE_OTHER),\n\t\t\tcode => E::schema(code)\n\t\t}\n\t}\n}\n\n#[cfg(test)]\nmod test {\n\tuse super::*;\n\tuse futures_executor::block_on;\n\tuse gotham::hyper::StatusCode;\n\tuse thiserror::Error;\n\n\t#[derive(Debug, Default, Error)]\n\t#[error(\"An Error\")]\n\tstruct MsgError;\n\n\t#[test]\n\tfn redirect_response() {\n\t\tlet redir = Redirect {\n\t\t\tto: \"http://localhost/foo\".to_owned()\n\t\t};\n\t\tlet res = block_on(redir.into_response()).expect(\"didn't expect error response\");\n\t\tassert_eq!(res.status, StatusCode::SEE_OTHER);\n\t\tassert_eq!(res.mime, None);\n\t\tassert_eq!(\n\t\t\tres.headers.get(LOCATION).map(|hdr| hdr.to_str().unwrap()),\n\t\t\tSome(\"http://localhost/foo\")\n\t\t);\n\t\tassert_eq!(res.full_body().unwrap(), &[] as &[u8]);\n\n\t\t#[cfg(feature = \"openapi\")]\n\t\tassert_eq!(Redirect::status_codes(), vec![StatusCode::SEE_OTHER]);\n\t}\n\n\t#[test]\n\tfn redirect_result() {\n\t\tlet redir: Result = Ok(Redirect {\n\t\t\tto: \"http://localhost/foo\".to_owned()\n\t\t});\n\t\tlet res = block_on(redir.into_response()).expect(\"didn't expect error response\");\n\t\tassert_eq!(res.status, StatusCode::SEE_OTHER);\n\t\tassert_eq!(res.mime, None);\n\t\tassert_eq!(\n\t\t\tres.headers.get(LOCATION).map(|hdr| hdr.to_str().unwrap()),\n\t\t\tSome(\"http://localhost/foo\")\n\t\t);\n\t\tassert_eq!(res.full_body().unwrap(), &[] as &[u8]);\n\n\t\t#[cfg(feature = \"openapi\")]\n\t\tassert_eq!(>::status_codes(), vec![\n\t\t\tStatusCode::INTERNAL_SERVER_ERROR,\n\t\t\tStatusCode::SEE_OTHER\n\t\t]);\n\t}\n}\n","traces":[{"line":45,"address":[6320048],"length":1,"stats":{"Line":1},"fn_name":"into_response"},{"line":46,"address":[8629563,8629319,8628644,8628688,8628718,8628775,8629523],"length":1,"stats":{"Line":3},"fn_name":"{async_block#0}"},{"line":47,"address":[6293520,6293606],"length":1,"stats":{"Line":4},"fn_name":null},{"line":48,"address":[6320291,6320802,6320158,6320892,6320937],"length":1,"stats":{"Line":2},"fn_name":null},{"line":49,"address":[7813421],"length":1,"stats":{"Line":2},"fn_name":null},{"line":57,"address":[6294400],"length":1,"stats":{"Line":1},"fn_name":"status_codes"},{"line":58,"address":[7813864,7813789],"length":1,"stats":{"Line":1},"fn_name":null},{"line":61,"address":[6294512],"length":1,"stats":{"Line":0},"fn_name":"schema"},{"line":63,"address":[7814034],"length":1,"stats":{"Line":0},"fn_name":null},{"line":84,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":85,"address":[6291007,6290872],"length":1,"stats":{"Line":2},"fn_name":null},{"line":86,"address":[6290900],"length":1,"stats":{"Line":1},"fn_name":null},{"line":87,"address":[6290970],"length":1,"stats":{"Line":0},"fn_name":null},{"line":98,"address":[6291024,6291139],"length":1,"stats":{"Line":1},"fn_name":"status_codes"},{"line":99,"address":[6291048],"length":1,"stats":{"Line":1},"fn_name":null},{"line":100,"address":[6291063],"length":1,"stats":{"Line":1},"fn_name":null},{"line":101,"address":[6291108],"length":1,"stats":{"Line":1},"fn_name":null},{"line":104,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":105,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":106,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":107,"address":[],"length":0,"stats":{"Line":0},"fn_name":null}],"covered":14,"coverable":21},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","response","result.rs"],"content":"use super::{handle_error, IntoResponse, ResourceError};\n#[cfg(feature = \"openapi\")]\nuse crate::ResponseSchema;\nuse crate::{Response, ResponseBody, Success};\nuse futures_core::future::Future;\nuse gotham::{\n\tanyhow::Error,\n\thyper::StatusCode,\n\tmime::{Mime, APPLICATION_JSON}\n};\n#[cfg(feature = \"openapi\")]\nuse openapi_type::{OpenapiSchema, OpenapiType};\nuse std::{fmt::Debug, pin::Pin};\n\npub trait IntoResponseError {\n\ttype Err: Debug + Send + 'static;\n\n\tfn into_response_error(self) -> Result;\n\n\t#[cfg(feature = \"openapi\")]\n\tfn status_codes() -> Vec;\n\n\t#[cfg(feature = \"openapi\")]\n\tfn schema(code: StatusCode) -> OpenapiSchema;\n}\n\nimpl IntoResponseError for E\nwhere\n\tE: Into\n{\n\ttype Err = serde_json::Error;\n\n\tfn into_response_error(self) -> Result {\n\t\tlet err: Error = self.into();\n\t\tlet err: ResourceError = err.into();\n\t\tOk(Response::json(\n\t\t\tStatusCode::INTERNAL_SERVER_ERROR,\n\t\t\tserde_json::to_string(&err)?\n\t\t))\n\t}\n\n\t#[cfg(feature = \"openapi\")]\n\tfn status_codes() -> Vec {\n\t\tvec![StatusCode::INTERNAL_SERVER_ERROR]\n\t}\n\n\t#[cfg(feature = \"openapi\")]\n\tfn schema(code: StatusCode) -> OpenapiSchema {\n\t\tassert_eq!(code, StatusCode::INTERNAL_SERVER_ERROR);\n\t\tResourceError::schema()\n\t}\n}\n\nimpl IntoResponse for Result\nwhere\n\tR: ResponseBody,\n\tE: Debug + IntoResponseError\n{\n\ttype Err = E::Err;\n\n\tfn into_response(self) -> Pin> + Send>> {\n\t\tmatch self {\n\t\t\tOk(r) => Success::from(r).into_response(),\n\t\t\tErr(e) => handle_error(e)\n\t\t}\n\t}\n\n\tfn accepted_types() -> Option> {\n\t\tSome(vec![APPLICATION_JSON])\n\t}\n}\n\n#[cfg(feature = \"openapi\")]\nimpl ResponseSchema for Result\nwhere\n\tR: ResponseBody,\n\tE: Debug + IntoResponseError\n{\n\tfn status_codes() -> Vec {\n\t\tlet mut status_codes = E::status_codes();\n\t\tstatus_codes.push(StatusCode::OK);\n\t\tstatus_codes\n\t}\n\n\tfn schema(code: StatusCode) -> OpenapiSchema {\n\t\tmatch code {\n\t\t\tStatusCode::OK => R::schema(),\n\t\t\tcode => E::schema(code)\n\t\t}\n\t}\n}\n\n#[cfg(test)]\nmod test {\n\tuse super::*;\n\tuse crate::response::OrAllTypes;\n\tuse futures_executor::block_on;\n\tuse thiserror::Error;\n\n\t#[derive(Debug, Default, Deserialize, Serialize)]\n\t#[cfg_attr(feature = \"openapi\", derive(openapi_type::OpenapiType))]\n\tstruct Msg {\n\t\tmsg: String\n\t}\n\n\t#[derive(Debug, Default, Error)]\n\t#[error(\"An Error\")]\n\tstruct MsgError;\n\n\t#[test]\n\tfn result_ok() {\n\t\tlet ok: Result = Ok(Msg::default());\n\t\tlet res = block_on(ok.into_response()).expect(\"didn't expect error response\");\n\t\tassert_eq!(res.status, StatusCode::OK);\n\t\tassert_eq!(res.mime, Some(APPLICATION_JSON));\n\t\tassert_eq!(res.full_body().unwrap(), br#\"{\"msg\":\"\"}\"#);\n\t}\n\n\t#[test]\n\tfn result_err() {\n\t\tlet err: Result = Err(MsgError);\n\t\tlet res = block_on(err.into_response()).expect(\"didn't expect error response\");\n\t\tassert_eq!(res.status, StatusCode::INTERNAL_SERVER_ERROR);\n\t\tassert_eq!(res.mime, Some(APPLICATION_JSON));\n\t\tassert_eq!(\n\t\t\tres.full_body().unwrap(),\n\t\t\tformat!(r#\"{{\"error\":true,\"message\":\"{}\"}}\"#, MsgError).as_bytes()\n\t\t);\n\t}\n\n\t#[test]\n\tfn success_accepts_json() {\n\t\tassert!(\n\t\t\t>::accepted_types()\n\t\t\t\t.or_all_types()\n\t\t\t\t.contains(&APPLICATION_JSON)\n\t\t)\n\t}\n}\n","traces":[{"line":33,"address":[6098547,6098208],"length":1,"stats":{"Line":2},"fn_name":"into_response_error"},{"line":34,"address":[5689638],"length":1,"stats":{"Line":2},"fn_name":null},{"line":35,"address":[5921418],"length":1,"stats":{"Line":2},"fn_name":null},{"line":36,"address":[6098497,6098418],"length":1,"stats":{"Line":4},"fn_name":null},{"line":37,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":38,"address":[5921480,5921436,5921597],"length":1,"stats":{"Line":4},"fn_name":null},{"line":43,"address":[5689488],"length":1,"stats":{"Line":3},"fn_name":"status_codes"},{"line":44,"address":[5921757,5921831],"length":1,"stats":{"Line":3},"fn_name":null},{"line":48,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":50,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":61,"address":[6291168],"length":1,"stats":{"Line":2},"fn_name":"into_response"},{"line":62,"address":[6291180,6291287],"length":1,"stats":{"Line":3},"fn_name":null},{"line":63,"address":[6291209],"length":1,"stats":{"Line":1},"fn_name":null},{"line":64,"address":[6291272],"length":1,"stats":{"Line":1},"fn_name":null},{"line":68,"address":[6291312],"length":1,"stats":{"Line":3},"fn_name":"accepted_types"},{"line":69,"address":[6291329,6291482],"length":1,"stats":{"Line":3},"fn_name":null},{"line":79,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":80,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":81,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":82,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":85,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":86,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":87,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":88,"address":[],"length":0,"stats":{"Line":2},"fn_name":null}],"covered":21,"coverable":24},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","response","success.rs"],"content":"use super::IntoResponse;\n#[cfg(feature = \"openapi\")]\nuse crate::ResponseSchema;\nuse crate::{Response, ResponseBody};\nuse futures_util::future::{self, FutureExt};\nuse gotham::{\n\thyper::{\n\t\theader::{HeaderMap, HeaderValue, IntoHeaderName},\n\t\tStatusCode\n\t},\n\tmime::{Mime, APPLICATION_JSON}\n};\n#[cfg(feature = \"openapi\")]\nuse openapi_type::OpenapiSchema;\nuse std::{fmt::Debug, future::Future, pin::Pin};\n\n/// This can be returned from a resource when there is no cause of an error.\n///\n/// Usage example:\n///\n/// ```\n/// # #[macro_use] extern crate gotham_restful_derive;\n/// # mod doc_tests_are_broken {\n/// # use gotham::state::State;\n/// # use gotham_restful::*;\n/// # use serde::{Deserialize, Serialize};\n/// #\n/// # #[derive(Resource)]\n/// # #[resource(read_all)]\n/// # struct MyResource;\n/// #\n/// #[derive(Deserialize, Serialize)]\n/// # #[cfg_attr(feature = \"openapi\", derive(openapi_type::OpenapiType))]\n/// struct MyResponse {\n/// \tmessage: &'static str\n/// }\n///\n/// #[read_all]\n/// fn read_all() -> Success {\n/// \tlet res = MyResponse {\n/// \t\tmessage: \"I'm always happy\"\n/// \t};\n/// \tres.into()\n/// }\n/// # }\n/// ```\n#[derive(Clone, Debug, Default)]\npub struct Success {\n\tvalue: T,\n\theaders: HeaderMap\n}\n\nimpl From for Success {\n\tfn from(t: T) -> Self {\n\t\tSelf {\n\t\t\tvalue: t,\n\t\t\theaders: HeaderMap::new()\n\t\t}\n\t}\n}\n\nimpl Success {\n\t/// Set a custom HTTP header. If a header with this name was set before, its value is being updated.\n\tpub fn header(&mut self, name: K, value: HeaderValue) {\n\t\tself.headers.insert(name, value);\n\t}\n\n\t/// Allow manipulating HTTP headers.\n\tpub fn headers_mut(&mut self) -> &mut HeaderMap {\n\t\t&mut self.headers\n\t}\n}\n\nimpl IntoResponse for Success {\n\ttype Err = serde_json::Error;\n\n\tfn into_response(self) -> Pin> + Send>> {\n\t\tlet res = serde_json::to_string(&self.value)\n\t\t\t.map(|body| Response::json(StatusCode::OK, body).with_headers(self.headers));\n\t\tfuture::ready(res).boxed()\n\t}\n\n\tfn accepted_types() -> Option> {\n\t\tSome(vec![APPLICATION_JSON])\n\t}\n}\n\n#[cfg(feature = \"openapi\")]\nimpl ResponseSchema for Success {\n\tfn schema(code: StatusCode) -> OpenapiSchema {\n\t\tassert_eq!(code, StatusCode::OK);\n\t\tT::schema()\n\t}\n}\n\n#[cfg(test)]\nmod test {\n\tuse super::*;\n\tuse crate::response::OrAllTypes;\n\tuse futures_executor::block_on;\n\tuse gotham::hyper::header::ACCESS_CONTROL_ALLOW_ORIGIN;\n\n\t#[derive(Debug, Default, Serialize)]\n\t#[cfg_attr(feature = \"openapi\", derive(openapi_type::OpenapiType))]\n\tstruct Msg {\n\t\tmsg: String\n\t}\n\n\t#[test]\n\tfn success_always_successfull() {\n\t\tlet success: Success = Msg::default().into();\n\t\tlet res = block_on(success.into_response()).expect(\"didn't expect error response\");\n\t\tassert_eq!(res.status, StatusCode::OK);\n\t\tassert_eq!(res.mime, Some(APPLICATION_JSON));\n\t\tassert_eq!(res.full_body().unwrap(), br#\"{\"msg\":\"\"}\"#);\n\t\t#[cfg(feature = \"openapi\")]\n\t\tassert_eq!(>::status_codes(), vec![StatusCode::OK]);\n\t}\n\n\t#[test]\n\tfn success_custom_headers() {\n\t\tlet mut success: Success = Msg::default().into();\n\t\tsuccess.header(ACCESS_CONTROL_ALLOW_ORIGIN, HeaderValue::from_static(\"*\"));\n\t\tlet res = block_on(success.into_response()).expect(\"didn't expect error response\");\n\t\tlet cors = res.headers.get(ACCESS_CONTROL_ALLOW_ORIGIN);\n\t\tassert_eq!(cors.map(|value| value.to_str().unwrap()), Some(\"*\"));\n\t}\n\n\t#[test]\n\tfn success_accepts_json() {\n\t\tassert!(\n\t\t\t>::accepted_types()\n\t\t\t\t.or_all_types()\n\t\t\t\t.contains(&APPLICATION_JSON)\n\t\t)\n\t}\n}\n","traces":[{"line":54,"address":[6549038,6548800,6548896,6548752],"length":1,"stats":{"Line":3},"fn_name":"from"},{"line":57,"address":[6138529,6138705],"length":1,"stats":{"Line":3},"fn_name":null},{"line":64,"address":[6138848],"length":1,"stats":{"Line":1},"fn_name":null},{"line":65,"address":[6138866],"length":1,"stats":{"Line":1},"fn_name":null},{"line":69,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":70,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":77,"address":[6551836,6551533,6551857,6551232,6551502,6551552],"length":1,"stats":{"Line":2},"fn_name":"into_response"},{"line":78,"address":[6139263,6139428,6139092,6138927],"length":1,"stats":{"Line":6},"fn_name":null},{"line":79,"address":[6139568,6139861,6139328,6138992,6139589,6139840],"length":1,"stats":{"Line":9},"fn_name":"{closure#0}"},{"line":80,"address":[6139112,6139247,6139448,6138911],"length":1,"stats":{"Line":5},"fn_name":null},{"line":83,"address":[6140112],"length":1,"stats":{"Line":1},"fn_name":"accepted_types"},{"line":84,"address":[6140282,6140129],"length":1,"stats":{"Line":1},"fn_name":null},{"line":90,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":92,"address":[],"length":0,"stats":{"Line":0},"fn_name":null}],"covered":10,"coverable":14},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","routing.rs"],"content":"#[cfg(feature = \"openapi\")]\nuse crate::openapi::{\n\tbuilder::{OpenapiBuilder, OpenapiInfo},\n\trouter::OpenapiRouter\n};\nuse crate::{response::ResourceError, Endpoint, FromBody, IntoResponse, Resource, Response};\n#[cfg(feature = \"cors\")]\nuse gotham::router::route::matcher::AccessControlRequestMethodMatcher;\nuse gotham::{\n\thandler::HandlerError,\n\thelpers::http::response::{create_empty_response, create_response},\n\thyper::{body::to_bytes, header::CONTENT_TYPE, Body, HeaderMap, Method, StatusCode},\n\tmime::{Mime, APPLICATION_JSON},\n\tpipeline::PipelineHandleChain,\n\tprelude::*,\n\trouter::{\n\t\tbuilder::{RouterBuilder, ScopeBuilder},\n\t\troute::matcher::{AcceptHeaderRouteMatcher, ContentTypeHeaderRouteMatcher, RouteMatcher},\n\t\tRouteNonMatch\n\t},\n\tstate::{FromState, State}\n};\n#[cfg(feature = \"openapi\")]\nuse openapi_type::OpenapiType;\nuse std::{any::TypeId, panic::RefUnwindSafe};\n\n/// Allow us to extract an id from a path.\n#[derive(Clone, Copy, Debug, Deserialize, StateData, StaticResponseExtender)]\n#[cfg_attr(feature = \"openapi\", derive(OpenapiType))]\npub struct PathExtractor {\n\tpub id: ID\n}\n\n/// This trait adds the `with_openapi` method to gotham's routing. It turns the default\n/// router into one that will only allow RESTful resources, but record them and generate\n/// an OpenAPI specification on request.\n#[cfg(feature = \"openapi\")]\npub trait WithOpenapi {\n\tfn with_openapi(&mut self, info: OpenapiInfo, block: F)\n\twhere\n\t\tF: FnOnce(OpenapiRouter<'_, D>);\n}\n\n/// This trait adds the `resource` method to gotham's routing. It allows you to register\n/// any RESTful [Resource] with a path.\n#[_private_openapi_trait(DrawResourcesWithSchema)]\npub trait DrawResources {\n\t#[openapi_bound(R: crate::ResourceWithSchema)]\n\t#[non_openapi_bound(R: crate::Resource)]\n\tfn resource(&mut self, path: &str);\n}\n\n/// This trait allows to draw routes within an resource. Use this only inside the\n/// [Resource::setup] method.\n#[_private_openapi_trait(DrawResourceRoutesWithSchema)]\npub trait DrawResourceRoutes {\n\t#[openapi_bound(E: crate::EndpointWithSchema)]\n\t#[non_openapi_bound(E: crate::Endpoint)]\n\tfn endpoint(&mut self);\n}\n\nfn response_from(res: Response, state: &State) -> gotham::hyper::Response {\n\tlet mut r = create_empty_response(state, res.status);\n\tlet headers = r.headers_mut();\n\tif let Some(mime) = res.mime {\n\t\theaders.insert(CONTENT_TYPE, mime.as_ref().parse().unwrap());\n\t}\n\tlet mut last_name = None;\n\tfor (name, value) in res.headers {\n\t\tif name.is_some() {\n\t\t\tlast_name = name;\n\t\t}\n\t\t// this unwrap is safe: the first item will always be Some\n\t\tlet name = last_name.clone().unwrap();\n\t\theaders.insert(name, value);\n\t}\n\n\tlet method = Method::borrow_from(state);\n\tif method != Method::HEAD {\n\t\t*r.body_mut() = res.body;\n\t}\n\n\t#[cfg(feature = \"cors\")]\n\tcrate::cors::handle_cors(state, &mut r);\n\n\tr\n}\n\nasync fn endpoint_handler(\n\tstate: &mut State\n) -> Result, HandlerError>\nwhere\n\tE: Endpoint,\n\t::Err: Into\n{\n\ttrace!(\"entering endpoint_handler\");\n\tlet placeholders = E::Placeholders::take_from(state);\n\t// workaround for E::Placeholders and E::Param being the same type\n\t// when fixed remove `Clone` requirement on endpoint\n\tif TypeId::of::() == TypeId::of::() {\n\t\tstate.put(placeholders.clone());\n\t}\n\tlet params = E::Params::take_from(state);\n\n\tlet body = match E::needs_body() {\n\t\ttrue => {\n\t\t\tlet body = to_bytes(Body::take_from(state)).await?;\n\n\t\t\tlet content_type: Mime = match HeaderMap::borrow_from(state).get(CONTENT_TYPE) {\n\t\t\t\tSome(content_type) => content_type.to_str().unwrap().parse().unwrap(),\n\t\t\t\tNone => {\n\t\t\t\t\tdebug!(\"Missing Content-Type: Returning 415 Response\");\n\t\t\t\t\tlet res = create_empty_response(state, StatusCode::UNSUPPORTED_MEDIA_TYPE);\n\t\t\t\t\treturn Ok(res);\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tmatch E::Body::from_body(body, content_type) {\n\t\t\t\tOk(body) => Some(body),\n\t\t\t\tErr(e) => {\n\t\t\t\t\tdebug!(\"Invalid Body: Returning 400 Response\");\n\t\t\t\t\tlet error: ResourceError = e.into();\n\t\t\t\t\tlet json = serde_json::to_string(&error)?;\n\t\t\t\t\tlet res =\n\t\t\t\t\t\tcreate_response(state, StatusCode::BAD_REQUEST, APPLICATION_JSON, json);\n\t\t\t\t\treturn Ok(res);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tfalse => None\n\t};\n\n\tlet out = E::handle(state, placeholders, params, body).await;\n\tlet res = out.into_response().await.map_err(Into::into)?;\n\tdebug!(\"Returning response {res:?}\");\n\tOk(response_from(res, state))\n}\n\n#[derive(Clone)]\nstruct MaybeMatchAcceptHeader {\n\tmatcher: Option\n}\n\nimpl RouteMatcher for MaybeMatchAcceptHeader {\n\tfn is_match(&self, state: &State) -> Result<(), RouteNonMatch> {\n\t\tmatch &self.matcher {\n\t\t\tSome(matcher) => matcher.is_match(state),\n\t\t\tNone => Ok(())\n\t\t}\n\t}\n}\n\nimpl MaybeMatchAcceptHeader {\n\tfn new(types: Option>) -> Self {\n\t\tlet types = match types {\n\t\t\tSome(types) if types.is_empty() => None,\n\t\t\ttypes => types\n\t\t};\n\t\tSelf {\n\t\t\tmatcher: types.map(AcceptHeaderRouteMatcher::new)\n\t\t}\n\t}\n}\n\nimpl From>> for MaybeMatchAcceptHeader {\n\tfn from(types: Option>) -> Self {\n\t\tSelf::new(types)\n\t}\n}\n\n#[derive(Clone)]\nstruct MaybeMatchContentTypeHeader {\n\tmatcher: Option\n}\n\nimpl RouteMatcher for MaybeMatchContentTypeHeader {\n\tfn is_match(&self, state: &State) -> Result<(), RouteNonMatch> {\n\t\tmatch &self.matcher {\n\t\t\tSome(matcher) => matcher.is_match(state),\n\t\t\tNone => Ok(())\n\t\t}\n\t}\n}\n\nimpl MaybeMatchContentTypeHeader {\n\tfn new(types: Option>) -> Self {\n\t\tSelf {\n\t\t\tmatcher: types.map(|types| ContentTypeHeaderRouteMatcher::new(types).allow_no_type())\n\t\t}\n\t}\n}\n\nimpl From>> for MaybeMatchContentTypeHeader {\n\tfn from(types: Option>) -> Self {\n\t\tSelf::new(types)\n\t}\n}\n\nmacro_rules! implDrawResourceRoutes {\n\t($implType:ident) => {\n\t\t#[cfg(feature = \"openapi\")]\n\t\timpl<'a, C, P> WithOpenapi for $implType<'a, C, P>\n\t\twhere\n\t\t\tC: PipelineHandleChain

+ Copy + Send + Sync + 'static,\n\t\t\tP: RefUnwindSafe + Send + Sync + 'static\n\t\t{\n\t\t\tfn with_openapi(&mut self, info: OpenapiInfo, block: F)\n\t\t\twhere\n\t\t\t\tF: FnOnce(OpenapiRouter<'_, $implType<'a, C, P>>)\n\t\t\t{\n\t\t\t\tlet router = OpenapiRouter {\n\t\t\t\t\trouter: self,\n\t\t\t\t\tscope: None,\n\t\t\t\t\topenapi_builder: &mut OpenapiBuilder::new(info)\n\t\t\t\t};\n\t\t\t\tblock(router);\n\t\t\t}\n\t\t}\n\n\t\timpl<'a, C, P> DrawResources for $implType<'a, C, P>\n\t\twhere\n\t\t\tC: PipelineHandleChain

+ Copy + Send + Sync + 'static,\n\t\t\tP: RefUnwindSafe + Send + Sync + 'static\n\t\t{\n\t\t\tfn resource(&mut self, mut path: &str) {\n\t\t\t\tif path.starts_with('/') {\n\t\t\t\t\tpath = &path[1..];\n\t\t\t\t}\n\t\t\t\tR::setup((self, path));\n\t\t\t}\n\t\t}\n\n\t\timpl<'a, C, P> DrawResourceRoutes for (&mut $implType<'a, C, P>, &str)\n\t\twhere\n\t\t\tC: PipelineHandleChain

+ Copy + Send + Sync + 'static,\n\t\t\tP: RefUnwindSafe + Send + Sync + 'static\n\t\t{\n\t\t\tfn endpoint(&mut self) {\n\t\t\t\tlet uri = format!(\"{}/{}\", self.1, E::uri());\n\t\t\t\tdebug!(\"Registering endpoint for {uri}\");\n\t\t\t\tself.0.associate(&uri, |assoc| {\n\t\t\t\t\tassoc\n\t\t\t\t\t\t.request(vec![E::http_method()])\n\t\t\t\t\t\t.add_route_matcher(MaybeMatchAcceptHeader::new(E::Output::accepted_types()))\n\t\t\t\t\t\t.with_path_extractor::()\n\t\t\t\t\t\t.with_query_string_extractor::()\n\t\t\t\t\t\t.to_async_borrowing(endpoint_handler::);\n\n\t\t\t\t\t#[cfg(feature = \"cors\")]\n\t\t\t\t\tif E::http_method() != Method::GET {\n\t\t\t\t\t\tassoc\n\t\t\t\t\t\t\t.options()\n\t\t\t\t\t\t\t.add_route_matcher(AccessControlRequestMethodMatcher::new(\n\t\t\t\t\t\t\t\tE::http_method()\n\t\t\t\t\t\t\t))\n\t\t\t\t\t\t\t.to(crate::cors::cors_preflight_handler);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t};\n}\n\nimplDrawResourceRoutes!(RouterBuilder);\nimplDrawResourceRoutes!(ScopeBuilder);\n","traces":[{"line":62,"address":[6370669,6369808,6368944],"length":1,"stats":{"Line":5},"fn_name":"response_from"},{"line":63,"address":[6368987,6369138],"length":1,"stats":{"Line":10},"fn_name":null},{"line":64,"address":[6369215,6369146],"length":1,"stats":{"Line":10},"fn_name":null},{"line":65,"address":[6369223],"length":1,"stats":{"Line":5},"fn_name":null},{"line":66,"address":[6369789,6369337,6369544],"length":1,"stats":{"Line":4},"fn_name":null},{"line":68,"address":[6369408],"length":1,"stats":{"Line":5},"fn_name":null},{"line":69,"address":[6369420,6369863,6371133],"length":1,"stats":{"Line":10},"fn_name":null},{"line":70,"address":[6370113,6370771,6370957],"length":1,"stats":{"Line":0},"fn_name":null},{"line":71,"address":[6370803],"length":1,"stats":{"Line":0},"fn_name":null},{"line":74,"address":[6370962,6370793],"length":1,"stats":{"Line":0},"fn_name":null},{"line":75,"address":[6370997],"length":1,"stats":{"Line":0},"fn_name":null},{"line":78,"address":[6370132],"length":1,"stats":{"Line":5},"fn_name":null},{"line":79,"address":[6370449,6370161],"length":1,"stats":{"Line":10},"fn_name":null},{"line":80,"address":[6370704,6370226],"length":1,"stats":{"Line":5},"fn_name":null},{"line":84,"address":[6370211],"length":1,"stats":{"Line":5},"fn_name":null},{"line":86,"address":[6370459],"length":1,"stats":{"Line":5},"fn_name":null},{"line":89,"address":[6379440],"length":1,"stats":{"Line":21},"fn_name":"endpoint_handler"},{"line":96,"address":[],"length":0,"stats":{"Line":63},"fn_name":null},{"line":97,"address":[],"length":0,"stats":{"Line":42},"fn_name":null},{"line":100,"address":[],"length":0,"stats":{"Line":42},"fn_name":null},{"line":101,"address":[],"length":0,"stats":{"Line":13},"fn_name":null},{"line":103,"address":[],"length":0,"stats":{"Line":42},"fn_name":null},{"line":105,"address":[],"length":0,"stats":{"Line":42},"fn_name":null},{"line":106,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":107,"address":[],"length":0,"stats":{"Line":16},"fn_name":null},{"line":109,"address":[],"length":0,"stats":{"Line":16},"fn_name":null},{"line":110,"address":[],"length":0,"stats":{"Line":16},"fn_name":null},{"line":111,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":112,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":113,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":114,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":118,"address":[],"length":0,"stats":{"Line":8},"fn_name":null},{"line":119,"address":[],"length":0,"stats":{"Line":8},"fn_name":null},{"line":120,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":121,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":122,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":123,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":124,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":125,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":126,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":130,"address":[],"length":0,"stats":{"Line":13},"fn_name":null},{"line":133,"address":[],"length":0,"stats":{"Line":43},"fn_name":null},{"line":134,"address":[],"length":0,"stats":{"Line":42},"fn_name":null},{"line":135,"address":[],"length":0,"stats":{"Line":63},"fn_name":null},{"line":136,"address":[],"length":0,"stats":{"Line":42},"fn_name":null},{"line":145,"address":[6371360],"length":1,"stats":{"Line":7},"fn_name":"is_match"},{"line":146,"address":[6371393],"length":1,"stats":{"Line":5},"fn_name":null},{"line":147,"address":[6371442],"length":1,"stats":{"Line":0},"fn_name":null},{"line":148,"address":[6371422],"length":1,"stats":{"Line":7},"fn_name":null},{"line":154,"address":[6371919,6371472,6371849],"length":1,"stats":{"Line":8},"fn_name":null},{"line":155,"address":[6371494],"length":1,"stats":{"Line":6},"fn_name":null},{"line":156,"address":[6371555,6371698],"length":1,"stats":{"Line":6},"fn_name":null},{"line":157,"address":[6371579],"length":1,"stats":{"Line":5},"fn_name":null},{"line":160,"address":[6371762],"length":1,"stats":{"Line":8},"fn_name":null},{"line":166,"address":[6371936],"length":1,"stats":{"Line":0},"fn_name":"from"},{"line":167,"address":[6371944],"length":1,"stats":{"Line":0},"fn_name":null},{"line":177,"address":[6371968],"length":1,"stats":{"Line":0},"fn_name":"is_match"},{"line":178,"address":[6372001],"length":1,"stats":{"Line":0},"fn_name":null},{"line":179,"address":[6372047],"length":1,"stats":{"Line":0},"fn_name":null},{"line":180,"address":[6372027],"length":1,"stats":{"Line":0},"fn_name":null},{"line":186,"address":[6372080],"length":1,"stats":{"Line":0},"fn_name":null},{"line":188,"address":[6372094,6372157,6372144],"length":1,"stats":{"Line":0},"fn_name":"{closure#0}"},{"line":194,"address":[6372208],"length":1,"stats":{"Line":0},"fn_name":"from"},{"line":195,"address":[6372216],"length":1,"stats":{"Line":0},"fn_name":null},{"line":207,"address":[6854304,6854557],"length":1,"stats":{"Line":2},"fn_name":"with_openapi<(), (), openapi_supports_scope::openapi_supports_scope::{closure#0}::{closure_env#0}>"},{"line":211,"address":[6854420,6854332],"length":1,"stats":{"Line":4},"fn_name":null},{"line":213,"address":[6854342],"length":1,"stats":{"Line":2},"fn_name":null},{"line":214,"address":[6854415,6854351],"length":1,"stats":{"Line":4},"fn_name":null},{"line":216,"address":[6854455],"length":1,"stats":{"Line":2},"fn_name":null},{"line":225,"address":[7011040],"length":1,"stats":{"Line":4},"fn_name":"resource<(), (), sync_methods::FooResource>"},{"line":226,"address":[7011064,7011181],"length":1,"stats":{"Line":9},"fn_name":null},{"line":227,"address":[7011134],"length":1,"stats":{"Line":1},"fn_name":null},{"line":229,"address":[7011094],"length":1,"stats":{"Line":4},"fn_name":null},{"line":238,"address":[6844208,6846036,6845108,6845136],"length":1,"stats":{"Line":31},"fn_name":"endpoint<(), (), openapi_supports_scope::read_all___gotham_restful_endpoint>"},{"line":239,"address":[6845238,6845315,6845156,6844310,6844387,6844228],"length":1,"stats":{"Line":62},"fn_name":null},{"line":240,"address":[6844637,6845868,6845565,6844724,6845738,6844940,6845652,6844810],"length":1,"stats":{"Line":93},"fn_name":null},{"line":241,"address":[6379381,6378565,6379411,6378624,6377808,6378595],"length":1,"stats":{"Line":93},"fn_name":"{closure#0}<(), (), openapi_supports_scope::read_all___gotham_restful_endpoint>"},{"line":242,"address":[6378029,6378845,6377828,6378644,6378969,6378153,6378220,6379036],"length":1,"stats":{"Line":120},"fn_name":null},{"line":243,"address":[6378621,6377854,6378034,6378878,6378670,6378850,6378062,6379437],"length":1,"stats":{"Line":62},"fn_name":null},{"line":244,"address":[6378901,6378614,6378192,6378085,6379008,6378866,6379430,6378050],"length":1,"stats":{"Line":64},"fn_name":null},{"line":250,"address":[6379083,6378267],"length":1,"stats":{"Line":33},"fn_name":null},{"line":251,"address":[6378500,6379207,6378547,6379316,6379363,6378391],"length":1,"stats":{"Line":44},"fn_name":null},{"line":253,"address":[6378473,6379289],"length":1,"stats":{"Line":14},"fn_name":null},{"line":254,"address":[6378420,6379236],"length":1,"stats":{"Line":16},"fn_name":null}],"covered":57,"coverable":84},{"path":["/","home","runner","work","gotham_restful","gotham_restful","src","types.rs"],"content":"use gotham::{\n\thyper::body::Bytes,\n\tmime::{Mime, APPLICATION_JSON}\n};\n#[cfg(feature = \"openapi\")]\nuse openapi_type::OpenapiType;\nuse serde::{de::DeserializeOwned, Serialize};\nuse std::error::Error;\n\n#[cfg(not(feature = \"openapi\"))]\npub trait ResourceType {}\n\n#[cfg(not(feature = \"openapi\"))]\nimpl ResourceType for T {}\n\n#[cfg(feature = \"openapi\")]\npub trait ResourceType: OpenapiType {}\n\n#[cfg(feature = \"openapi\")]\nimpl ResourceType for T {}\n\n/// A type that can be used inside a response body. Implemented for every type that is\n/// serializable with serde. If the `openapi` feature is used, it must also be of type\n/// [OpenapiType].\npub trait ResponseBody: ResourceType + Serialize {}\n\nimpl ResponseBody for T {}\n\n/// This trait should be implemented for every type that can be built from an HTTP request body\n/// plus its media type.\n///\n/// For most use cases it is sufficient to derive this trait, you usually don't need to manually\n/// implement this. Therefore, make sure that the first variable of your struct can be built from\n/// [Bytes], and the second one can be build from [Mime]. If you have any additional variables, they\n/// need to be [Default]. This is an example of such a struct:\n///\n/// ```rust\n/// # use gotham::mime::{self, Mime};\n/// # use gotham_restful::{FromBody, RequestBody};\n/// #[derive(FromBody, RequestBody)]\n/// #[supported_types(mime::IMAGE_GIF, mime::IMAGE_JPEG, mime::IMAGE_PNG)]\n/// struct RawImage {\n/// \tcontent: Vec,\n/// \tcontent_type: Mime\n/// }\n/// ```\npub trait FromBody: Sized {\n\t/// The error type returned by the conversion if it was unsuccessfull. When using the derive\n\t/// macro, there is no way to trigger an error, so [std::convert::Infallible] is used here.\n\t/// However, this might change in the future.\n\ttype Err: Error;\n\n\t/// Perform the conversion.\n\tfn from_body(body: Bytes, content_type: Mime) -> Result;\n}\n\nimpl FromBody for T {\n\ttype Err = serde_json::Error;\n\n\tfn from_body(body: Bytes, _content_type: Mime) -> Result {\n\t\tserde_json::from_slice(&body)\n\t}\n}\n\n/// A type that can be used inside a request body. Implemented for every type that is deserializable\n/// with serde. If the `openapi` feature is used, it must also be of type [OpenapiType].\n///\n/// If you want a non-deserializable type to be used as a request body, e.g. because you'd like to\n/// get the raw data, you can derive it for your own type. All you need is to have a type implementing\n/// [FromBody] and optionally a list of supported media types:\n///\n/// ```rust\n/// # use gotham::mime::{self, Mime};\n/// # use gotham_restful::{FromBody, RequestBody};\n/// #[derive(FromBody, RequestBody)]\n/// #[supported_types(mime::IMAGE_GIF, mime::IMAGE_JPEG, mime::IMAGE_PNG)]\n/// struct RawImage {\n/// \tcontent: Vec,\n/// \tcontent_type: Mime\n/// }\n/// ```\npub trait RequestBody: ResourceType + FromBody {\n\t/// Return all types that are supported as content types. Use `None` if all types are supported.\n\tfn supported_types() -> Option> {\n\t\tNone\n\t}\n}\n\nimpl RequestBody for T {\n\tfn supported_types() -> Option> {\n\t\tSome(vec![APPLICATION_JSON])\n\t}\n}\n","traces":[{"line":60,"address":[],"length":0,"stats":{"Line":2},"fn_name":null},{"line":61,"address":[7425648,7425712],"length":1,"stats":{"Line":4},"fn_name":null},{"line":84,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":85,"address":[],"length":0,"stats":{"Line":0},"fn_name":null},{"line":90,"address":[],"length":0,"stats":{"Line":1},"fn_name":null},{"line":91,"address":[],"length":0,"stats":{"Line":1},"fn_name":null}],"covered":4,"coverable":6},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","async_methods.rs"],"content":"use gotham::{\n\thyper::{HeaderMap, Method},\n\tmime::{APPLICATION_JSON, TEXT_PLAIN},\n\tprelude::*,\n\trouter::build_simple_router,\n\tstate::State,\n\ttest::TestServer\n};\nuse gotham_restful::*;\n#[cfg(feature = \"openapi\")]\nuse openapi_type::OpenapiType;\nuse serde::Deserialize;\nuse tokio::time::{sleep, Duration};\n\nmod util {\n\tinclude!(\"util/mod.rs\");\n}\nuse util::{test_delete_response, test_get_response, test_post_response, test_put_response};\n\n#[derive(Resource)]\n#[resource(\n\tread_all, read, search, create, update_all, update, delete_all, delete, state_test\n)]\nstruct FooResource;\n\n#[derive(Deserialize)]\n#[cfg_attr(feature = \"openapi\", derive(OpenapiType))]\n#[allow(dead_code)]\nstruct FooBody {\n\tdata: String\n}\n\n#[derive(Clone, Deserialize, StateData, StaticResponseExtender)]\n#[cfg_attr(feature = \"openapi\", derive(OpenapiType))]\n#[allow(dead_code)]\nstruct FooSearch {\n\tquery: String\n}\n\nconst READ_ALL_RESPONSE: &[u8] = b\"1ARwwSPVyOKpJKrYwqGgECPVWDl1BqajAAj7g7WJ3e\";\n#[read_all]\nasync fn read_all() -> Raw<&'static [u8]> {\n\tRaw::new(READ_ALL_RESPONSE, TEXT_PLAIN)\n}\n\nconst READ_RESPONSE: &[u8] = b\"FEReHoeBKU17X2bBpVAd1iUvktFL43CDu0cFYHdaP9\";\n#[read]\nasync fn read(_id: u64) -> Raw<&'static [u8]> {\n\tRaw::new(READ_RESPONSE, TEXT_PLAIN)\n}\n\nconst SEARCH_RESPONSE: &[u8] = b\"AWqcQUdBRHXKh3at4u79mdupOAfEbnTcx71ogCVF0E\";\n#[search]\nasync fn search(_body: FooSearch) -> Raw<&'static [u8]> {\n\tRaw::new(SEARCH_RESPONSE, TEXT_PLAIN)\n}\n\nconst CREATE_RESPONSE: &[u8] = b\"y6POY7wOMAB0jBRBw0FJT7DOpUNbhmT8KdpQPLkI83\";\n#[create]\nasync fn create(_body: FooBody) -> Raw<&'static [u8]> {\n\tRaw::new(CREATE_RESPONSE, TEXT_PLAIN)\n}\n\nconst UPDATE_ALL_RESPONSE: &[u8] = b\"QlbYg8gHE9OQvvk3yKjXJLTSXlIrg9mcqhfMXJmQkv\";\n#[update_all]\nasync fn update_all(_body: FooBody) -> Raw<&'static [u8]> {\n\tRaw::new(UPDATE_ALL_RESPONSE, TEXT_PLAIN)\n}\n\nconst UPDATE_RESPONSE: &[u8] = b\"qGod55RUXkT1lgPO8h0uVM6l368O2S0GrwENZFFuRu\";\n#[update]\nasync fn update(_id: u64, _body: FooBody) -> Raw<&'static [u8]> {\n\tRaw::new(UPDATE_RESPONSE, TEXT_PLAIN)\n}\n\nconst DELETE_ALL_RESPONSE: &[u8] = b\"Y36kZ749MRk2Nem4BedJABOZiZWPLOtiwLfJlGTwm5\";\n#[delete_all]\nasync fn delete_all() -> Raw<&'static [u8]> {\n\tRaw::new(DELETE_ALL_RESPONSE, TEXT_PLAIN)\n}\n\nconst DELETE_RESPONSE: &[u8] = b\"CwRzBrKErsVZ1N7yeNfjZuUn1MacvgBqk4uPOFfDDq\";\n#[delete]\nasync fn delete(_id: u64) -> Raw<&'static [u8]> {\n\tRaw::new(DELETE_RESPONSE, TEXT_PLAIN)\n}\n\nconst STATE_TEST_RESPONSE: &[u8] = b\"xxJbxOuwioqR5DfzPuVqvaqRSfpdNQGluIvHU4n1LM\";\n#[endpoint(method = \"Method::GET\", uri = \"state_test\")]\nasync fn state_test(state: &mut State) -> Raw<&'static [u8]> {\n\tsleep(Duration::from_nanos(1)).await;\n\tstate.borrow::();\n\tsleep(Duration::from_nanos(1)).await;\n\tRaw::new(STATE_TEST_RESPONSE, TEXT_PLAIN)\n}\n\n#[test]\nfn async_methods() {\n\tlet _ = pretty_env_logger::try_init_timed();\n\n\tlet server = TestServer::new(build_simple_router(|router| {\n\t\trouter.resource::(\"foo\");\n\t}))\n\t.unwrap();\n\n\ttest_get_response(&server, \"http://localhost/foo\", READ_ALL_RESPONSE);\n\ttest_get_response(&server, \"http://localhost/foo/1\", READ_RESPONSE);\n\ttest_get_response(\n\t\t&server,\n\t\t\"http://localhost/foo/search?query=hello+world\",\n\t\tSEARCH_RESPONSE\n\t);\n\ttest_post_response(\n\t\t&server,\n\t\t\"http://localhost/foo\",\n\t\tr#\"{\"data\":\"hello world\"}\"#,\n\t\tAPPLICATION_JSON,\n\t\tCREATE_RESPONSE\n\t);\n\ttest_put_response(\n\t\t&server,\n\t\t\"http://localhost/foo\",\n\t\tr#\"{\"data\":\"hello world\"}\"#,\n\t\tAPPLICATION_JSON,\n\t\tUPDATE_ALL_RESPONSE\n\t);\n\ttest_put_response(\n\t\t&server,\n\t\t\"http://localhost/foo/1\",\n\t\tr#\"{\"data\":\"hello world\"}\"#,\n\t\tAPPLICATION_JSON,\n\t\tUPDATE_RESPONSE\n\t);\n\ttest_delete_response(&server, \"http://localhost/foo\", DELETE_ALL_RESPONSE);\n\ttest_delete_response(&server, \"http://localhost/foo/1\", DELETE_RESPONSE);\n\ttest_get_response(\n\t\t&server,\n\t\t\"http://localhost/foo/state_test\",\n\t\tSTATE_TEST_RESPONSE\n\t);\n}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","cors_handling.rs"],"content":"#![cfg(feature = \"cors\")]\nuse gotham::{\n\thyper::{body::Body, client::connect::Connect, header::*, StatusCode},\n\tmime::TEXT_PLAIN,\n\tpipeline::{new_pipeline, single_pipeline},\n\trouter::build_router,\n\ttest::{Server, TestRequest, TestServer}\n};\nuse gotham_restful::{\n\tcors::{Headers, Origin},\n\tread_all, update_all, CorsConfig, DrawResources, Raw, Resource\n};\n\n#[derive(Resource)]\n#[resource(read_all, update_all)]\nstruct FooResource;\n\n#[read_all]\nfn read_all() {}\n\n#[update_all]\nfn update_all(_body: Raw>) {}\n\nfn test_server(cfg: CorsConfig) -> TestServer {\n\tlet (chain, pipeline) = single_pipeline(new_pipeline().add(cfg).build());\n\tTestServer::new(build_router(chain, pipeline, |router| {\n\t\trouter.resource::(\"/foo\")\n\t}))\n\t.unwrap()\n}\n\nfn test_response(\n\treq: TestRequest,\n\torigin: Option<&str>,\n\tvary: Option<&str>,\n\tcredentials: bool\n) where\n\tTS: Server + 'static,\n\tC: Connect + Clone + Send + Sync + 'static\n{\n\tlet res = req\n\t\t.with_header(ORIGIN, \"http://example.org\".parse().unwrap())\n\t\t.perform()\n\t\t.unwrap();\n\tassert_eq!(res.status(), StatusCode::NO_CONTENT);\n\tlet headers = res.headers();\n\tprintln!(\n\t\t\"{}\",\n\t\theaders\n\t\t\t.keys()\n\t\t\t.map(|name| name.as_str())\n\t\t\t.collect::>()\n\t\t\t.join(\",\")\n\t);\n\tassert_eq!(\n\t\theaders\n\t\t\t.get(ACCESS_CONTROL_ALLOW_ORIGIN)\n\t\t\t.and_then(|value| value.to_str().ok())\n\t\t\t.as_deref(),\n\t\torigin\n\t);\n\tassert_eq!(\n\t\theaders\n\t\t\t.get(VARY)\n\t\t\t.and_then(|value| value.to_str().ok())\n\t\t\t.as_deref(),\n\t\tvary\n\t);\n\tassert_eq!(\n\t\theaders\n\t\t\t.get(ACCESS_CONTROL_ALLOW_CREDENTIALS)\n\t\t\t.and_then(|value| value.to_str().ok())\n\t\t\t.map(|value| value == \"true\")\n\t\t\t.unwrap_or(false),\n\t\tcredentials\n\t);\n\tassert!(headers.get(ACCESS_CONTROL_MAX_AGE).is_none());\n}\n\nfn test_preflight(\n\tserver: &TestServer,\n\tmethod: &str,\n\torigin: Option<&str>,\n\tvary: &str,\n\tcredentials: bool,\n\tmax_age: u64\n) {\n\tlet res = server\n\t\t.client()\n\t\t.options(\"http://example.org/foo\")\n\t\t.with_header(ACCESS_CONTROL_REQUEST_METHOD, method.parse().unwrap())\n\t\t.with_header(ORIGIN, \"http://example.org\".parse().unwrap())\n\t\t.perform()\n\t\t.unwrap();\n\tassert_eq!(res.status(), StatusCode::NO_CONTENT);\n\tlet headers = res.headers();\n\tprintln!(\n\t\t\"{}\",\n\t\theaders\n\t\t\t.keys()\n\t\t\t.map(|name| name.as_str())\n\t\t\t.collect::>()\n\t\t\t.join(\",\")\n\t);\n\tassert_eq!(\n\t\theaders\n\t\t\t.get(ACCESS_CONTROL_ALLOW_METHODS)\n\t\t\t.and_then(|value| value.to_str().ok())\n\t\t\t.as_deref(),\n\t\tSome(method)\n\t);\n\tassert_eq!(\n\t\theaders\n\t\t\t.get(ACCESS_CONTROL_ALLOW_ORIGIN)\n\t\t\t.and_then(|value| value.to_str().ok())\n\t\t\t.as_deref(),\n\t\torigin\n\t);\n\tassert_eq!(\n\t\theaders\n\t\t\t.get(VARY)\n\t\t\t.and_then(|value| value.to_str().ok())\n\t\t\t.as_deref(),\n\t\tSome(vary)\n\t);\n\tassert_eq!(\n\t\theaders\n\t\t\t.get(ACCESS_CONTROL_ALLOW_CREDENTIALS)\n\t\t\t.and_then(|value| value.to_str().ok())\n\t\t\t.map(|value| value == \"true\")\n\t\t\t.unwrap_or(false),\n\t\tcredentials\n\t);\n\tassert_eq!(\n\t\theaders\n\t\t\t.get(ACCESS_CONTROL_MAX_AGE)\n\t\t\t.and_then(|value| value.to_str().ok())\n\t\t\t.and_then(|value| value.parse().ok()),\n\t\tSome(max_age)\n\t);\n}\n\nfn test_preflight_headers(\n\tserver: &TestServer,\n\tmethod: &str,\n\trequest_headers: Option<&str>,\n\tallowed_headers: Option<&str>,\n\tvary: &str\n) {\n\tlet client = server.client();\n\tlet mut res = client\n\t\t.options(\"http://example.org/foo\")\n\t\t.with_header(ACCESS_CONTROL_REQUEST_METHOD, method.parse().unwrap())\n\t\t.with_header(ORIGIN, \"http://example.org\".parse().unwrap());\n\tif let Some(hdr) = request_headers {\n\t\tres = res.with_header(ACCESS_CONTROL_REQUEST_HEADERS, hdr.parse().unwrap());\n\t}\n\tlet res = res.perform().unwrap();\n\tassert_eq!(res.status(), StatusCode::NO_CONTENT);\n\tlet headers = res.headers();\n\tprintln!(\n\t\t\"{}\",\n\t\theaders\n\t\t\t.keys()\n\t\t\t.map(|name| name.as_str())\n\t\t\t.collect::>()\n\t\t\t.join(\",\")\n\t);\n\tif let Some(hdr) = allowed_headers {\n\t\tassert_eq!(\n\t\t\theaders\n\t\t\t\t.get(ACCESS_CONTROL_ALLOW_HEADERS)\n\t\t\t\t.and_then(|value| value.to_str().ok())\n\t\t\t\t.as_deref(),\n\t\t\tSome(hdr)\n\t\t)\n\t} else {\n\t\tassert!(!headers.contains_key(ACCESS_CONTROL_ALLOW_HEADERS));\n\t}\n\tassert_eq!(\n\t\theaders\n\t\t\t.get(VARY)\n\t\t\t.and_then(|value| value.to_str().ok())\n\t\t\t.as_deref(),\n\t\tSome(vary)\n\t);\n}\n\n#[test]\nfn cors_origin_none() {\n\tlet cfg = Default::default();\n\tlet server = test_server(cfg);\n\n\ttest_preflight(\n\t\t&server,\n\t\t\"PUT\",\n\t\tNone,\n\t\t\"access-control-request-method\",\n\t\tfalse,\n\t\t0\n\t);\n\n\ttest_response(\n\t\tserver.client().get(\"http://example.org/foo\"),\n\t\tNone,\n\t\tNone,\n\t\tfalse\n\t);\n\ttest_response(\n\t\tserver\n\t\t\t.client()\n\t\t\t.put(\"http://example.org/foo\", Body::empty(), TEXT_PLAIN),\n\t\tNone,\n\t\tNone,\n\t\tfalse\n\t);\n}\n\n#[test]\nfn cors_origin_star() {\n\tlet cfg = CorsConfig {\n\t\torigin: Origin::Star,\n\t\t..Default::default()\n\t};\n\tlet server = test_server(cfg);\n\n\ttest_preflight(\n\t\t&server,\n\t\t\"PUT\",\n\t\tSome(\"*\"),\n\t\t\"access-control-request-method\",\n\t\tfalse,\n\t\t0\n\t);\n\n\ttest_response(\n\t\tserver.client().get(\"http://example.org/foo\"),\n\t\tSome(\"*\"),\n\t\tNone,\n\t\tfalse\n\t);\n\ttest_response(\n\t\tserver\n\t\t\t.client()\n\t\t\t.put(\"http://example.org/foo\", Body::empty(), TEXT_PLAIN),\n\t\tSome(\"*\"),\n\t\tNone,\n\t\tfalse\n\t);\n}\n\n#[test]\nfn cors_origin_single() {\n\tlet cfg = CorsConfig {\n\t\torigin: Origin::Single(\"https://foo.com\".to_owned()),\n\t\t..Default::default()\n\t};\n\tlet server = test_server(cfg);\n\n\ttest_preflight(\n\t\t&server,\n\t\t\"PUT\",\n\t\tSome(\"https://foo.com\"),\n\t\t\"access-control-request-method\",\n\t\tfalse,\n\t\t0\n\t);\n\n\ttest_response(\n\t\tserver.client().get(\"http://example.org/foo\"),\n\t\tSome(\"https://foo.com\"),\n\t\tNone,\n\t\tfalse\n\t);\n\ttest_response(\n\t\tserver\n\t\t\t.client()\n\t\t\t.put(\"http://example.org/foo\", Body::empty(), TEXT_PLAIN),\n\t\tSome(\"https://foo.com\"),\n\t\tNone,\n\t\tfalse\n\t);\n}\n\n#[test]\nfn cors_origin_copy() {\n\tlet cfg = CorsConfig {\n\t\torigin: Origin::Copy,\n\t\t..Default::default()\n\t};\n\tlet server = test_server(cfg);\n\n\ttest_preflight(\n\t\t&server,\n\t\t\"PUT\",\n\t\tSome(\"http://example.org\"),\n\t\t\"access-control-request-method,origin\",\n\t\tfalse,\n\t\t0\n\t);\n\n\ttest_response(\n\t\tserver.client().get(\"http://example.org/foo\"),\n\t\tSome(\"http://example.org\"),\n\t\tSome(\"origin\"),\n\t\tfalse\n\t);\n\ttest_response(\n\t\tserver\n\t\t\t.client()\n\t\t\t.put(\"http://example.org/foo\", Body::empty(), TEXT_PLAIN),\n\t\tSome(\"http://example.org\"),\n\t\tSome(\"origin\"),\n\t\tfalse\n\t);\n}\n\n#[test]\nfn cors_headers_none() {\n\tlet cfg = Default::default();\n\tlet server = test_server(cfg);\n\n\ttest_preflight_headers(&server, \"PUT\", None, None, \"access-control-request-method\");\n\ttest_preflight_headers(\n\t\t&server,\n\t\t\"PUT\",\n\t\tSome(\"Content-Type\"),\n\t\tNone,\n\t\t\"access-control-request-method\"\n\t);\n}\n\n#[test]\nfn cors_headers_list() {\n\tlet cfg = CorsConfig {\n\t\theaders: Headers::List(vec![CONTENT_TYPE]),\n\t\t..Default::default()\n\t};\n\tlet server = test_server(cfg);\n\n\ttest_preflight_headers(\n\t\t&server,\n\t\t\"PUT\",\n\t\tNone,\n\t\tSome(\"content-type\"),\n\t\t\"access-control-request-method\"\n\t);\n\ttest_preflight_headers(\n\t\t&server,\n\t\t\"PUT\",\n\t\tSome(\"content-type\"),\n\t\tSome(\"content-type\"),\n\t\t\"access-control-request-method\"\n\t);\n}\n\n#[test]\nfn cors_headers_copy() {\n\tlet cfg = CorsConfig {\n\t\theaders: Headers::Copy,\n\t\t..Default::default()\n\t};\n\tlet server = test_server(cfg);\n\n\ttest_preflight_headers(\n\t\t&server,\n\t\t\"PUT\",\n\t\tNone,\n\t\tNone,\n\t\t\"access-control-request-method,access-control-request-headers\"\n\t);\n\ttest_preflight_headers(\n\t\t&server,\n\t\t\"PUT\",\n\t\tSome(\"content-type\"),\n\t\tSome(\"content-type\"),\n\t\t\"access-control-request-method,access-control-request-headers\"\n\t);\n}\n\n#[test]\nfn cors_credentials() {\n\tlet cfg = CorsConfig {\n\t\torigin: Origin::None,\n\t\tcredentials: true,\n\t\t..Default::default()\n\t};\n\tlet server = test_server(cfg);\n\n\ttest_preflight(\n\t\t&server,\n\t\t\"PUT\",\n\t\tNone,\n\t\t\"access-control-request-method\",\n\t\ttrue,\n\t\t0\n\t);\n\n\ttest_response(\n\t\tserver.client().get(\"http://example.org/foo\"),\n\t\tNone,\n\t\tNone,\n\t\ttrue\n\t);\n\ttest_response(\n\t\tserver\n\t\t\t.client()\n\t\t\t.put(\"http://example.org/foo\", Body::empty(), TEXT_PLAIN),\n\t\tNone,\n\t\tNone,\n\t\ttrue\n\t);\n}\n\n#[test]\nfn cors_max_age() {\n\tlet cfg = CorsConfig {\n\t\torigin: Origin::None,\n\t\tmax_age: 31536000,\n\t\t..Default::default()\n\t};\n\tlet server = test_server(cfg);\n\n\ttest_preflight(\n\t\t&server,\n\t\t\"PUT\",\n\t\tNone,\n\t\t\"access-control-request-method\",\n\t\tfalse,\n\t\t31536000\n\t);\n\n\ttest_response(\n\t\tserver.client().get(\"http://example.org/foo\"),\n\t\tNone,\n\t\tNone,\n\t\tfalse\n\t);\n\ttest_response(\n\t\tserver\n\t\t\t.client()\n\t\t\t.put(\"http://example.org/foo\", Body::empty(), TEXT_PLAIN),\n\t\tNone,\n\t\tNone,\n\t\tfalse\n\t);\n}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","custom_request_body.rs"],"content":"use gotham::{\n\thyper::header::CONTENT_TYPE,\n\tmime::{Mime, TEXT_PLAIN},\n\trouter::builder::*,\n\ttest::TestServer\n};\nuse gotham_restful::{create, DrawResources, FromBody, Raw, RequestBody, Resource};\n\nconst RESPONSE: &[u8] = b\"This is the only valid response.\";\n\n#[derive(Resource)]\n#[resource(create)]\nstruct FooResource;\n\n#[derive(FromBody, RequestBody)]\n#[supported_types(TEXT_PLAIN)]\nstruct Foo {\n\tcontent: Vec,\n\tcontent_type: Mime\n}\n\n#[create]\nfn create(body: Foo) -> Raw> {\n\tRaw::new(body.content, body.content_type)\n}\n\n#[test]\nfn custom_request_body() {\n\tlet server = TestServer::new(build_simple_router(|router| {\n\t\trouter.resource::(\"foo\");\n\t}))\n\t.unwrap();\n\n\tlet res = server\n\t\t.client()\n\t\t.post(\"http://localhost/foo\", RESPONSE, TEXT_PLAIN)\n\t\t.perform()\n\t\t.unwrap();\n\tassert_eq!(\n\t\tres.headers().get(CONTENT_TYPE).unwrap().to_str().unwrap(),\n\t\t\"text/plain\"\n\t);\n\tlet res = res.read_body().unwrap();\n\tlet body: &[u8] = res.as_ref();\n\tassert_eq!(body, RESPONSE);\n}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","openapi_specification.rs"],"content":"#![cfg(all(feature = \"auth\", feature = \"openapi\"))]\n#![allow(clippy::approx_constant)]\n\n#[macro_use]\nextern crate pretty_assertions;\n\nuse gotham::{\n\thyper::{Method, StatusCode},\n\tmime::{IMAGE_PNG, TEXT_PLAIN_UTF_8},\n\tpipeline::{new_pipeline, single_pipeline},\n\tprelude::*,\n\trouter::build_router,\n\ttest::TestServer\n};\nuse gotham_restful::*;\nuse openapi_type::{OpenapiSchema, OpenapiType, Visitor};\nuse serde::{Deserialize, Serialize};\n\n#[allow(dead_code)]\nmod util {\n\tinclude!(\"util/mod.rs\");\n}\nuse util::test_openapi_response;\n\nconst IMAGE_RESPONSE : &[u8] = b\"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUA/wA0XsCoAAAAAXRSTlN/gFy0ywAAAApJREFUeJxjYgAAAAYAAzY3fKgAAAAASUVORK5CYII=\";\n\n#[derive(Resource)]\n#[resource(get_image, set_image)]\nstruct ImageResource;\n\n#[derive(FromBody, RequestBody)]\n#[supported_types(IMAGE_PNG)]\nstruct Image(Vec);\n\n#[read(operation_id = \"getImage\")]\nfn get_image(_id: u64) -> Raw<&'static [u8]> {\n\tRaw::new(IMAGE_RESPONSE, \"image/png;base64\".parse().unwrap())\n}\n\n#[update(operation_id = \"setImage\")]\nfn set_image(_id: u64, _image: Image) {}\n\n#[derive(Resource)]\n#[resource(read_secret, search_secret)]\nstruct SecretResource;\n\n#[derive(Deserialize, Clone)]\nstruct AuthData {\n\tsub: String,\n\tiat: u64,\n\texp: u64\n}\n\ntype AuthStatus = gotham_restful::AuthStatus;\n\n#[derive(OpenapiType, Serialize)]\nstruct Secret {\n\tcode: f32\n}\n\n#[derive(OpenapiType, Serialize)]\nstruct Secrets {\n\tsecrets: Vec\n}\n\n#[derive(Clone, Deserialize, OpenapiType, StateData, StaticResponseExtender)]\nstruct SecretQuery {\n\tdate: String,\n\thour: Option,\n\tminute: Option\n}\n\n/// This endpoint gives access to the secret.\n///\n/// You need to be authenticated to call this endpoint.\n#[read]\nfn read_secret(auth: AuthStatus, _id: String) -> AuthSuccess {\n\tauth.ok()?;\n\tOk(Secret { code: 4.2 })\n}\n\n#[search]\nfn search_secret(auth: AuthStatus, _query: SecretQuery) -> AuthSuccess {\n\tauth.ok()?;\n\tOk(Secrets {\n\t\tsecrets: vec![Secret { code: 4.2 }, Secret { code: 3.14 }]\n\t})\n}\n\n#[derive(Resource)]\n#[resource(coffee_read_all)]\nstruct CoffeeResource;\n\nfn teapot_status_codes() -> Vec {\n\tvec![StatusCode::IM_A_TEAPOT]\n}\n\nfn teapot_schema(code: StatusCode) -> OpenapiSchema {\n\tassert_eq!(code, StatusCode::IM_A_TEAPOT);\n\n\tstruct Binary;\n\n\timpl OpenapiType for Binary {\n\t\tfn visit_type(visitor: &mut V) {\n\t\t\tvisitor.visit_binary();\n\t\t}\n\t}\n\n\tBinary::schema()\n}\n\n#[read_all(status_codes = \"teapot_status_codes\", schema = \"teapot_schema\")]\nfn coffee_read_all() -> Response {\n\tResponse::new(\n\t\tStatusCode::IM_A_TEAPOT,\n\t\t\"Sorry, this is just your fancy grandma's teapot. Can't make coffee.\",\n\t\tSome(TEXT_PLAIN_UTF_8)\n\t)\n}\n\n#[derive(Resource)]\n#[resource(custom_read_with, custom_patch)]\nstruct CustomResource;\n\n#[derive(Clone, Deserialize, OpenapiType, StateData, StaticResponseExtender)]\nstruct ReadWithPath {\n\tfrom: String,\n\tid: u64\n}\n\n#[endpoint(method = \"Method::GET\", uri = \"read/:from/with/:id\")]\nfn custom_read_with(_path: ReadWithPath) {}\n\n#[endpoint(method = \"Method::PATCH\", uri = \"\", body = true)]\nfn custom_patch(_body: String) {}\n\n#[test]\nfn openapi_specification() {\n\tlet info = OpenapiInfo {\n\t\ttitle: \"This is just a test\".to_owned(),\n\t\tversion: \"1.2.3\".to_owned(),\n\t\turls: vec![\"http://localhost:12345/api/v1\".to_owned()]\n\t};\n\tlet auth: AuthMiddleware = AuthMiddleware::new(\n\t\tAuthSource::AuthorizationHeader,\n\t\tAuthValidation::default(),\n\t\tStaticAuthHandler::from_array(b\"zlBsA2QXnkmpe0QTh8uCvtAEa4j33YAc\")\n\t);\n\tlet (chain, pipelines) = single_pipeline(new_pipeline().add(auth).build());\n\tlet server = TestServer::new(build_router(chain, pipelines, |router| {\n\t\trouter.with_openapi(info, |mut router| {\n\t\t\t// the leading slash tests that the spec doesn't contain '//img' nonsense\n\t\t\trouter.resource::(\"/img\");\n\t\t\trouter.resource::(\"secret\");\n\t\t\trouter.resource::(\"coffee\");\n\t\t\trouter.resource::(\"custom\");\n\t\t\trouter.openapi_spec(\"openapi\");\n\t\t});\n\t}))\n\t.unwrap();\n\n\ttest_openapi_response(\n\t\t&server,\n\t\t\"http://localhost/openapi\",\n\t\t\"tests/openapi_specification.json\"\n\t);\n}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","openapi_supports_scope.rs"],"content":"#![cfg(feature = \"openapi\")]\n\n#[macro_use]\nextern crate pretty_assertions;\n\nuse gotham::{mime::TEXT_PLAIN, router::builder::*, test::TestServer};\nuse gotham_restful::*;\n\n#[allow(dead_code)]\nmod util {\n\tinclude!(\"util/mod.rs\");\n}\nuse util::{test_get_response, test_openapi_response};\n\nconst RESPONSE: &[u8] = b\"This is the only valid response.\";\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\n#[read_all]\nfn read_all() -> Raw<&'static [u8]> {\n\tRaw::new(RESPONSE, TEXT_PLAIN)\n}\n\n#[test]\nfn openapi_supports_scope() {\n\tlet info = OpenapiInfo {\n\t\ttitle: \"Test\".to_owned(),\n\t\tversion: \"1.2.3\".to_owned(),\n\t\turls: Vec::new()\n\t};\n\tlet server = TestServer::new(build_simple_router(|router| {\n\t\trouter.with_openapi(info, |mut router| {\n\t\t\trouter.openapi_spec(\"openapi\");\n\t\t\trouter.resource::(\"foo1\");\n\t\t\trouter.scope(\"/bar\", |router| {\n\t\t\t\trouter.resource::(\"foo2\");\n\t\t\t\trouter.scope(\"/baz\", |router| {\n\t\t\t\t\trouter.resource::(\"foo3\");\n\t\t\t\t})\n\t\t\t});\n\t\t\trouter.resource::(\"foo4\");\n\t\t});\n\t}))\n\t.unwrap();\n\n\ttest_get_response(&server, \"http://localhost/foo1\", RESPONSE);\n\ttest_get_response(&server, \"http://localhost/bar/foo2\", RESPONSE);\n\ttest_get_response(&server, \"http://localhost/bar/baz/foo3\", RESPONSE);\n\ttest_get_response(&server, \"http://localhost/foo4\", RESPONSE);\n\ttest_openapi_response(\n\t\t&server,\n\t\t\"http://localhost/openapi\",\n\t\t\"tests/openapi_supports_scope.json\"\n\t);\n}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","resource_error.rs"],"content":"use gotham_restful::ResourceError;\n\n#[derive(ResourceError)]\nenum Error {\n\t#[display(\"I/O Error: {0}\")]\n\tIoError(#[from] std::io::Error),\n\n\t#[status(INTERNAL_SERVER_ERROR)]\n\t#[display(\"Internal Server Error: {0}\")]\n\tInternalServerError(String)\n}\n\n#[allow(deprecated)]\nmod resource_error {\n\tuse super::Error;\n\tuse gotham::{hyper::StatusCode, mime::APPLICATION_JSON};\n\tuse gotham_restful::IntoResponseError;\n\n\t#[test]\n\tfn io_error() {\n\t\tlet err = Error::IoError(std::io::Error::last_os_error());\n\t\tlet res = err.into_response_error().unwrap();\n\t\tassert_eq!(res.status(), StatusCode::INTERNAL_SERVER_ERROR);\n\t\tassert_eq!(res.mime(), Some(&APPLICATION_JSON));\n\t}\n\n\t#[test]\n\tfn internal_server_error() {\n\t\tlet err = Error::InternalServerError(\"Brocken\".to_owned());\n\t\tassert_eq!(&format!(\"{err}\"), \"Internal Server Error: Brocken\");\n\n\t\tlet res = err.into_response_error().unwrap();\n\t\tassert_eq!(res.status(), StatusCode::INTERNAL_SERVER_ERROR);\n\t\tassert_eq!(res.mime(), None); // TODO shouldn't this be a json error message?\n\t}\n}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","sync_methods.rs"],"content":"use gotham::{\n\tmime::{APPLICATION_JSON, TEXT_PLAIN},\n\tprelude::*,\n\trouter::build_simple_router,\n\ttest::TestServer\n};\nuse gotham_restful::*;\n#[cfg(feature = \"openapi\")]\nuse openapi_type::OpenapiType;\nuse serde::Deserialize;\n\nmod util {\n\tinclude!(\"util/mod.rs\");\n}\nuse util::{test_delete_response, test_get_response, test_post_response, test_put_response};\n\n#[derive(Resource)]\n#[resource(read_all, read, search, create, update_all, update, delete_all, delete)]\nstruct FooResource;\n\n#[derive(Deserialize)]\n#[cfg_attr(feature = \"openapi\", derive(OpenapiType))]\n#[allow(dead_code)]\nstruct FooBody {\n\tdata: String\n}\n\n#[derive(Clone, Deserialize, StateData, StaticResponseExtender)]\n#[cfg_attr(feature = \"openapi\", derive(OpenapiType))]\n#[allow(dead_code)]\nstruct FooSearch {\n\tquery: String\n}\n\nconst READ_ALL_RESPONSE: &[u8] = b\"1ARwwSPVyOKpJKrYwqGgECPVWDl1BqajAAj7g7WJ3e\";\n#[read_all]\nfn read_all() -> Raw<&'static [u8]> {\n\tRaw::new(READ_ALL_RESPONSE, TEXT_PLAIN)\n}\n\nconst READ_RESPONSE: &[u8] = b\"FEReHoeBKU17X2bBpVAd1iUvktFL43CDu0cFYHdaP9\";\n#[read]\nfn read(_id: u64) -> Raw<&'static [u8]> {\n\tRaw::new(READ_RESPONSE, TEXT_PLAIN)\n}\n\nconst SEARCH_RESPONSE: &[u8] = b\"AWqcQUdBRHXKh3at4u79mdupOAfEbnTcx71ogCVF0E\";\n#[search]\nfn search(_body: FooSearch) -> Raw<&'static [u8]> {\n\tRaw::new(SEARCH_RESPONSE, TEXT_PLAIN)\n}\n\nconst CREATE_RESPONSE: &[u8] = b\"y6POY7wOMAB0jBRBw0FJT7DOpUNbhmT8KdpQPLkI83\";\n#[create]\nfn create(_body: FooBody) -> Raw<&'static [u8]> {\n\tRaw::new(CREATE_RESPONSE, TEXT_PLAIN)\n}\n\nconst UPDATE_ALL_RESPONSE: &[u8] = b\"QlbYg8gHE9OQvvk3yKjXJLTSXlIrg9mcqhfMXJmQkv\";\n#[update_all]\nfn update_all(_body: FooBody) -> Raw<&'static [u8]> {\n\tRaw::new(UPDATE_ALL_RESPONSE, TEXT_PLAIN)\n}\n\nconst UPDATE_RESPONSE: &[u8] = b\"qGod55RUXkT1lgPO8h0uVM6l368O2S0GrwENZFFuRu\";\n#[update]\nfn update(_id: u64, _body: FooBody) -> Raw<&'static [u8]> {\n\tRaw::new(UPDATE_RESPONSE, TEXT_PLAIN)\n}\n\nconst DELETE_ALL_RESPONSE: &[u8] = b\"Y36kZ749MRk2Nem4BedJABOZiZWPLOtiwLfJlGTwm5\";\n#[delete_all]\nfn delete_all() -> Raw<&'static [u8]> {\n\tRaw::new(DELETE_ALL_RESPONSE, TEXT_PLAIN)\n}\n\nconst DELETE_RESPONSE: &[u8] = b\"CwRzBrKErsVZ1N7yeNfjZuUn1MacvgBqk4uPOFfDDq\";\n#[delete]\nfn delete(_id: u64) -> Raw<&'static [u8]> {\n\tRaw::new(DELETE_RESPONSE, TEXT_PLAIN)\n}\n\n#[test]\nfn sync_methods() {\n\tlet _ = pretty_env_logger::try_init_timed();\n\n\tlet server = TestServer::new(build_simple_router(|router| {\n\t\trouter.resource::(\"foo\");\n\t}))\n\t.unwrap();\n\n\ttest_get_response(&server, \"http://localhost/foo\", READ_ALL_RESPONSE);\n\ttest_get_response(&server, \"http://localhost/foo/1\", READ_RESPONSE);\n\ttest_get_response(\n\t\t&server,\n\t\t\"http://localhost/foo/search?query=hello+world\",\n\t\tSEARCH_RESPONSE\n\t);\n\ttest_post_response(\n\t\t&server,\n\t\t\"http://localhost/foo\",\n\t\tr#\"{\"data\":\"hello world\"}\"#,\n\t\tAPPLICATION_JSON,\n\t\tCREATE_RESPONSE\n\t);\n\ttest_put_response(\n\t\t&server,\n\t\t\"http://localhost/foo\",\n\t\tr#\"{\"data\":\"hello world\"}\"#,\n\t\tAPPLICATION_JSON,\n\t\tUPDATE_ALL_RESPONSE\n\t);\n\ttest_put_response(\n\t\t&server,\n\t\t\"http://localhost/foo/1\",\n\t\tr#\"{\"data\":\"hello world\"}\"#,\n\t\tAPPLICATION_JSON,\n\t\tUPDATE_RESPONSE\n\t);\n\ttest_delete_response(&server, \"http://localhost/foo\", DELETE_ALL_RESPONSE);\n\ttest_delete_response(&server, \"http://localhost/foo/1\", DELETE_RESPONSE);\n}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","trybuild_ui.rs"],"content":"use trybuild::TestCases;\n\n#[test]\n#[ignore]\nfn trybuild_ui() {\n\tlet t = TestCases::new();\n\tt.compile_fail(\"tests/ui/endpoint/*.rs\");\n\tt.compile_fail(\"tests/ui/from_body/*.rs\");\n\tt.compile_fail(\"tests/ui/resource/*.rs\");\n}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","async_state.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\nuse gotham::state::State;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\n#[read_all]\nasync fn read_all(state: &State) {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","auth_data_non_clone.rs"],"content":"use gotham_restful::*;\nuse serde::Deserialize;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\n#[derive(Deserialize)]\nstruct AuthData {\n\tiat: u64,\n\texp: u64\n}\n\n#[read_all]\nasync fn read_all(auth: AuthStatus) -> Result {\n\tauth.ok()?;\n\tOk(NoContent::default())\n}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","custom_method_invalid_expr.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\n#[endpoint(method = \"I like pizza\", uri = \"custom_read\")]\nasync fn read_all() {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","custom_method_invalid_type.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\n#[endpoint(method = \"String::new()\", uri = \"custom_read\")]\nasync fn read_all() {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","custom_method_missing.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\n#[endpoint(uri = \"custom_read\")]\nasync fn read_all() {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","custom_uri_missing.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\n#[endpoint(method = \"gotham_restful::gotham::hyper::Method::GET\")]\nasync fn read_all() {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","dynamic_schema_missing_schema.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\nuse gotham::hyper::StatusCode;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\nfn status_codes() -> Vec {\n\tunimplemented!()\n}\n\n#[read_all(status_codes = \"status_codes\")]\nasync fn read_all() {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","dynamic_schema_missing_status_codes.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\nuse gotham::hyper::StatusCode;\nuse gotham_restful::private::OpenapiSchema;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\nfn schema(_: StatusCode) -> OpenapiSchema {\n\tunimplemented!()\n}\n\n#[read_all(schema = \"schema\")]\nasync fn read_all() {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","dynamic_schema_wrong_type.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\nfn schema(_: u16) -> String {\n\tunimplemented!()\n}\n\nfn status_codes() -> Vec {\n\tunimplemented!()\n}\n\n#[read_all(schema = \"schema\", status_codes = \"status_codes\")]\nasync fn read_all() {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","invalid_attribute.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\n#[read_all(FooResource)]\nfn read_all() {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","invalid_body_ty.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\nuse gotham_restful::gotham::hyper::Method;\n\n#[derive(Resource)]\n#[resource(endpoint)]\nstruct FooResource;\n\n#[derive(Debug)]\nstruct FooBody {\n\tfoo: String\n}\n\n#[endpoint(method = \"Method::GET\", uri = \"\", body = true)]\nfn endpoint(_: FooBody) {\n\tunimplemented!()\n}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","invalid_params_ty.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\nuse gotham_restful::gotham::hyper::Method;\n\n#[derive(Resource)]\n#[resource(endpoint)]\nstruct FooResource;\n\n#[derive(Debug)]\nstruct FooParams {\n\tfoo: String\n}\n\n#[endpoint(method = \"Method::GET\", uri = \"\", params = true)]\nfn endpoint(_: FooParams) {\n\tunimplemented!()\n}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","invalid_placeholders_ty.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\nuse gotham_restful::gotham::hyper::Method;\n\n#[derive(Resource)]\n#[resource(endpoint)]\nstruct FooResource;\n\n#[derive(Debug)]\nstruct FooPlaceholders {\n\tfoo: String\n}\n\n#[endpoint(method = \"Method::GET\", uri = \":foo\")]\nfn endpoint(_: FooPlaceholders) {\n\tunimplemented!()\n}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","invalid_return_type.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\nuse gotham_restful::gotham::hyper::Method;\n\n#[derive(Resource)]\n#[resource(endpoint)]\nstruct FooResource;\n\nstruct FooResponse;\n\n#[endpoint(method = \"Method::GET\", uri = \"\")]\nfn endpoint() -> FooResponse {\n\tunimplemented!()\n}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","non_custom_body_attribute.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\n#[read_all(body = false)]\nasync fn read_all() {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","non_custom_method_attribute.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\n#[read_all(method = \"gotham_restful::gotham::hyper::Method::GET\")]\nasync fn read_all() {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","non_custom_params_attribute.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\n#[read_all(params = true)]\nasync fn read_all() {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","non_custom_uri_attribute.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\n#[read_all(uri = \"custom_read\")]\nasync fn read_all() {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","self.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\n#[read_all]\nfn read_all(self) {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","too_few_args.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(Resource)]\n#[resource(read)]\nstruct FooResource;\n\n#[read]\nfn read() {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","too_many_args.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\n#[read_all]\nfn read_all(_id: u64) {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","unknown_attribute.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\n#[read_all(pineapple = \"on pizza\")]\nfn read_all() {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","unsafe.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\n#[read_all]\nunsafe fn read_all() {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","endpoint","wants_auth_non_bool.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(Resource)]\n#[resource(read_all)]\nstruct FooResource;\n\n#[read_all(wants_auth = \"yes, please\")]\nasync fn read_all() {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","from_body","enum.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(FromBody)]\nenum FromBodyEnum {\n\tSomeVariant(Vec),\n\tOtherVariant(String)\n}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","ui","resource","unknown_method.rs"],"content":"#[macro_use]\nextern crate gotham_restful;\n\n#[derive(Resource)]\n#[resource(read_any)]\nstruct FooResource;\n\n#[read_all]\nfn read_all() {}\n\nfn main() {}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","runner","work","gotham_restful","gotham_restful","tests","util","mod.rs"],"content":"use gotham::{\n\thyper::Body,\n\ttest::TestServer\n};\nuse log::info;\nuse gotham::mime::Mime;\n#[allow(unused_imports)]\nuse std::{fs::File, io::{Read, Write}, str};\n\npub fn test_get_response(server : &TestServer, path : &str, expected : &[u8])\n{\n\tinfo!(\"GET {path}\");\n\tlet res = server.client().get(path).perform().unwrap().read_body().unwrap();\n\tlet body : &[u8] = res.as_ref();\n\tassert_eq!(body, expected);\n}\n\npub fn test_post_response(server : &TestServer, path : &str, body : B, mime : Mime, expected : &[u8])\nwhere\n\tB : Into\n{\n\tinfo!(\"POST {path}\");\n\tlet res = server.client().post(path, body, mime).perform().unwrap().read_body().unwrap();\n\tlet body : &[u8] = res.as_ref();\n\tassert_eq!(body, expected);\n}\n\npub fn test_put_response(server : &TestServer, path : &str, body : B, mime : Mime, expected : &[u8])\nwhere\n\tB : Into\n{\n\tinfo!(\"PUT {path}\");\n\tlet res = server.client().put(path, body, mime).perform().unwrap().read_body().unwrap();\n\tlet body : &[u8] = res.as_ref();\n\tassert_eq!(body, expected);\n}\n\npub fn test_delete_response(server : &TestServer, path : &str, expected : &[u8])\n{\n\tinfo!(\"DELETE {path}\");\n\tlet res = server.client().delete(path).perform().unwrap().read_body().unwrap();\n\tlet body : &[u8] = res.as_ref();\n\tassert_eq!(body, expected);\n}\n\n#[cfg(feature = \"openapi\")]\npub fn test_openapi_response(server : &TestServer, path : &str, output_file : &str)\n{\n\tinfo!(\"GET {path}\");\n\tlet res = server.client().get(path).perform().unwrap().read_body().unwrap();\n\tlet body: serde_json::Value = serde_json::from_slice(&res).unwrap();\n\n\tlet mut file = File::open(output_file).unwrap();\n\tlet expected: serde_json::Value = serde_json::from_reader(&mut file).unwrap();\n\n\t//eprintln!(\"{body}\");\n\tassert_eq!(body, expected);\n}\n","traces":[],"covered":0,"coverable":0}]} \ No newline at end of file