1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
use hyper::body::HttpBody;
use hyper::{Body, Response};
use serde::{Deserialize, Deserializer};

use crate::router::response::StaticResponseExtender;
use crate::state::{State, StateData};

/// Defines a binding for storing the dynamic segments of the `Request` path in `State`. On failure
/// the `StaticResponseExtender` implementation extends the `Response` to indicate why the
/// extraction process failed.
///
/// This trait is automatically implemented when the struct implements the `Deserialize`,
/// `StateData` and `StaticResponseExtender` traits. These traits can be derived, or implemented
/// manually for greater control.
///
/// The default behaviour given by deriving all three traits will use the automatically derived
/// behaviour from Serde, and result in a `400 Bad Request` HTTP response if the path segments are
/// not able to be deserialized.
///
/// # Examples
///
/// ```rust
/// # use hyper::{Body, Response, StatusCode};
/// # use gotham::state::{FromState, State};
/// # use gotham::helpers::http::response::create_response;
/// # use gotham::router::{build_simple_router, Router};
/// # use gotham::prelude::*;
/// # use gotham::test::TestServer;
/// # use serde::Deserialize;
/// #
/// #[derive(Deserialize, StateData, StaticResponseExtender)]
/// struct MyPathParams {
///     id: i32,
///     slug: String,
/// }
///
/// fn handler(mut state: State) -> (State, Response<Body>) {
///     let MyPathParams { id, slug } = MyPathParams::take_from(&mut state);
///     let body = format!("id = {}, slug = {}", id, slug);
///
///     let response = create_response(
///         &state,
///         StatusCode::OK,
///         mime::TEXT_PLAIN,
///         body,
///     );
///
///     (state, response)
/// }
///
/// fn router() -> Router {
///     build_simple_router(|route| {
///         route
///             .get("/article/:id/:slug")
///             .with_path_extractor::<MyPathParams>()
///             .to(handler);
///     })
/// }
/// #
/// # fn main() {
/// #   let test_server = TestServer::new(router()).unwrap();
/// #   let response = test_server
/// #       .client()
/// #       .get("http://example.com/article/1551/ten-reasons-serde-is-amazing")
/// #       .perform()
/// #       .unwrap();
/// #   assert_eq!(response.status(), StatusCode::OK);
/// #   let body = response.read_utf8_body().unwrap();
/// #   assert_eq!(body, "id = 1551, slug = ten-reasons-serde-is-amazing");
/// # }
pub trait PathExtractor<B>:
    for<'de> Deserialize<'de> + StaticResponseExtender<ResBody = B> + StateData
where
    B: HttpBody,
{
}

impl<T, B> PathExtractor<B> for T
where
    B: HttpBody,
    for<'de> T: Deserialize<'de> + StaticResponseExtender<ResBody = B> + StateData,
{
}

/// A `PathExtractor` that does not extract/store any data from the `Request` path.
///
/// This is the default `PathExtractor` which is applied to a route when no other `PathExtractor`
/// is provided. It ignores any dynamic path segments, and always succeeds during deserialization.
pub struct NoopPathExtractor;

// This doesn't get derived correctly if we just `#[derive(Deserialize)]` above, because the
// Deserializer expects to _ignore_ a value, not just do nothing. By filling in the impl ourselves,
// we can explicitly do nothing.
impl<'de> Deserialize<'de> for NoopPathExtractor {
    fn deserialize<D>(_de: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        Ok(NoopPathExtractor)
    }
}

impl StateData for NoopPathExtractor {}

impl StaticResponseExtender for NoopPathExtractor {
    type ResBody = Body;
    fn extend(_state: &mut State, _res: &mut Response<Body>) {}
}