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
use routefinder::{Captures, RouteSpec};
use trillium::Conn;

/**
Extends trillium::Conn with accessors for router params.
*/
pub trait RouterConnExt {
    /**
    Retrieves a captured param from the conn. Note that this will only
    be Some if the exact param is present in the matched route.

    Routefinder params are defined starting with a colon, but the
    colon is not needed when fetching the param.

    ```
    use trillium::{conn_unwrap, Conn};
    use trillium_router::{Router, RouterConnExt};

    let router = Router::new().get("/pages/:page_name", |conn: Conn| async move {
        let page_name = conn_unwrap!(conn.param("page_name"), conn);
        let content = format!("you have reached the page named {}", page_name);
        conn.ok(content)
    });

    use trillium_testing::prelude::*;
    assert_ok!(
        get("/pages/trillium").on(&router),
        "you have reached the page named trillium"
    );
    ```
    */

    fn param<'a>(&'a self, param: &str) -> Option<&'a str>;

    /// Retrieves the wildcard match from the conn. Note that this will
    /// only be Some if the matched route contains a wildcard, as
    /// expressed by a "*" in the routefinder route spec.
    ///
    /// ```
    /// use trillium::{conn_unwrap, Conn};
    /// use trillium_router::{Router, RouterConnExt};
    ///
    /// let router = Router::new().get("/pages/*", |conn: Conn| async move {
    ///     let wildcard = conn_unwrap!(conn.wildcard(), conn);
    ///     let content = format!("the wildcard matched {}", wildcard);
    ///     conn.ok(content)
    /// });
    ///
    /// use trillium_testing::prelude::*;
    /// assert_ok!(
    ///     get("/pages/this/is/a/wildcard/match").on(&router),
    ///     "the wildcard matched this/is/a/wildcard/match"
    /// );
    /// ```

    fn wildcard(&self) -> Option<&str>;

    /// Retrieves the matched route specification
    /// ```
    /// use trillium::{conn_unwrap, Conn};
    /// use trillium_router::{Router, RouterConnExt};
    ///
    /// let router = Router::new().get("/pages/:page_id", |conn: Conn| async move {
    ///     let route = conn_unwrap!(conn.route(), conn).to_string();
    ///     conn.ok(format!("route was {route}"))
    /// });
    ///
    /// use trillium_testing::prelude::*;
    /// assert_ok!(
    ///     get("/pages/12345").on(&router),
    ///     "route was /pages/:page_id"
    /// );
    /// ```
    fn route(&self) -> Option<&RouteSpec>;
}

impl RouterConnExt for Conn {
    fn param<'a>(&'a self, param: &str) -> Option<&'a str> {
        self.state::<Captures>().and_then(|p| p.get(param))
    }

    fn wildcard(&self) -> Option<&str> {
        self.state::<Captures>().and_then(|p| p.wildcard())
    }

    fn route(&self) -> Option<&RouteSpec> {
        self.state()
    }
}

// ```
// use trillium::{conn_unwrap, Conn};
// use trillium_router::{Router, RouterConnExt};

// let router = Router::new().get("/pages/*", |conn: Conn| async move {
//     let wildcard = conn_unwrap!(conn.wildcard(), conn);
//     let content = format!("the wildcard matched {}", wildcard);
//     conn.ok(content)
// });

// use trillium_testing::prelude::*;
// assert_ok!(
//     get("/pages/this/is/a/wildcard/match").on(&router),
//     "the wildcard matched this/is/a/wildcard/match"
// );
// ```