Skip to main content

trillium/
macros.rs

1/// # Unwraps an `Result::Ok` or returns the `Conn` with a 500 status.
2///
3/// ```
4/// use trillium::{Conn, conn_try};
5/// use trillium_testing::TestServer;
6///
7/// # trillium_testing::block_on(async {
8/// let handler = |mut conn: Conn| async move {
9///     let request_body_string = conn_try!(conn.request_body_string().await, conn);
10///     let u8: u8 = conn_try!(request_body_string.parse(), conn);
11///     conn.ok(format!("received u8 as body: {}", u8))
12/// };
13///
14/// let app = TestServer::new(handler).await;
15/// app.post("/").with_body("not u8").await.assert_status(500);
16/// app.post("/")
17///     .with_body("10")
18///     .await
19///     .assert_ok()
20///     .assert_body("received u8 as body: 10");
21/// # });
22/// ```
23#[macro_export]
24macro_rules! conn_try {
25    ($expr:expr, $conn:expr $(,)?) => {
26        match $expr {
27            Ok(value) => value,
28            Err(error) => {
29                $crate::log::error!("{}:{} conn_try error: {}", file!(), line!(), error);
30                return $conn.with_status(500).halt();
31            }
32        }
33    };
34}
35
36/// # Unwraps an `Option::Some` or returns the `Conn`.
37///
38/// This is useful for gracefully exiting a `Handler` without
39/// returning an error.
40///
41/// ```
42/// use trillium::{Conn, State, conn_unwrap};
43/// use trillium_testing::TestServer;
44///
45/// #[derive(Copy, Clone)]
46/// struct MyState(&'static str);
47/// let handler = |conn: trillium::Conn| async move {
48///     let important_state: MyState = *conn_unwrap!(conn.state(), conn);
49///     conn.ok(important_state.0)
50/// };
51///
52/// # trillium_testing::block_on(async {
53/// let app = TestServer::new(handler).await;
54/// app.get("/").await.assert_status(404); // we never reached the conn.ok line.
55///
56/// let app2 = TestServer::new((State::new(MyState("hi")), handler)).await;
57/// app2.get("/").await.assert_ok().assert_body("hi");
58/// # });
59/// ```
60#[macro_export]
61macro_rules! conn_unwrap {
62    ($option:expr, $conn:expr $(,)?) => {
63        match $option {
64            Some(value) => value,
65            None => return $conn,
66        }
67    };
68}
69
70/// # A convenience macro for logging the contents of error variants.
71///
72/// This is useful when there is no further action required to process the
73/// error path, but you still want to record that it transpired
74#[macro_export]
75macro_rules! log_error {
76    ($expr:expr_2021) => {
77        if let Err(err) = $expr {
78            $crate::log::error!("{}:{} {:?}", file!(), line!(), err);
79        }
80    };
81
82    ($expr:expr_2021, $message:expr_2021) => {
83        if let Err(err) = $expr {
84            $crate::log::error!("{}:{} {} {:?}", file!(), line!(), $message, err);
85        }
86    };
87}
88
89/// # Macro for implementing Handler for simple newtypes that contain another handler.
90///
91/// ```
92/// use trillium::{delegate_handler, State, Conn, conn_unwrap};
93/// use trillium_testing::TestServer;
94///
95/// #[derive(Clone, Copy)]
96/// struct MyState(usize);
97/// struct MyHandler { handler: State<MyState> }
98/// delegate_handler!(MyHandler => handler);
99/// impl MyHandler {
100/// fn new(n: usize) -> Self {
101/// MyHandler { handler: State::new(MyState(n)) }
102/// }
103/// }
104///
105/// # trillium_testing::block_on(async {
106/// let handler = (MyHandler::new(5), |conn: Conn| async move {
107/// let MyState(n) = *conn_unwrap!(conn.state(), conn);
108/// conn.ok(n.to_string())
109/// });
110/// let app = TestServer::new(handler).await;
111/// app.get("/").await.assert_ok().assert_body("5");
112/// # });
113/// ```
114///
115/// ```
116/// use trillium::{Conn, State, conn_unwrap, delegate_handler};
117/// use trillium_testing::TestServer;
118///
119/// #[derive(Clone, Copy)]
120/// struct MyState(usize);
121/// struct MyHandler(State<MyState>);
122/// delegate_handler!(MyHandler);
123/// impl MyHandler {
124///     fn new(n: usize) -> Self {
125///         MyHandler(State::new(MyState(n)))
126///     }
127/// }
128///
129/// # trillium_testing::block_on(async {
130/// let handler = (MyHandler::new(5), |conn: Conn| async move {
131///     let MyState(n) = *conn_unwrap!(conn.state(), conn);
132///     conn.ok(n.to_string())
133/// });
134/// let app = TestServer::new(handler).await;
135/// app.get("/").await.assert_ok().assert_body("5");
136/// # });
137/// ```
138#[macro_export]
139macro_rules! delegate_handler {
140    ($struct_name:ty) => {
141        impl $crate::Handler for $struct_name {
142            async fn run(&self, conn: $crate::Conn) -> $crate::Conn {
143                use $crate::Handler;
144                self.0.run(conn).await
145            }
146
147            async fn init(&mut self, info: &mut $crate::Info) {
148                use $crate::Handler;
149                self.0.init(info).await;
150            }
151
152            async fn before_send(&self, conn: $crate::Conn) -> $crate::Conn {
153                use $crate::Handler;
154                self.0.before_send(conn).await
155            }
156
157            fn name(&self) -> std::borrow::Cow<'static, str> {
158                use $crate::Handler;
159                self.0.name()
160            }
161
162            fn has_upgrade(&self, upgrade: &$crate::Upgrade) -> bool {
163                use $crate::Handler;
164                self.0.has_upgrade(upgrade)
165            }
166
167            async fn upgrade(&self, upgrade: $crate::Upgrade) {
168                use $crate::Handler;
169                self.0.upgrade(upgrade).await;
170            }
171        }
172    };
173
174    ($struct_name:ty => $target:ident) => {
175        impl $crate::Handler for $struct_name {
176            async fn run(&self, conn: $crate::Conn) -> $crate::Conn {
177                use $crate::Handler;
178                self.$target.run(conn).await
179            }
180
181            async fn init(&mut self, info: &mut $crate::Info) {
182                use $crate::Handler;
183                self.$target.init(info).await;
184            }
185
186            async fn before_send(&self, conn: $crate::Conn) -> $crate::Conn {
187                use $crate::Handler;
188                self.$target.before_send(conn).await
189            }
190
191            fn name(&self) -> std::borrow::Cow<'static, str> {
192                use $crate::Handler;
193                self.$target.name()
194            }
195
196            fn has_upgrade(&self, upgrade: &$crate::Upgrade) -> bool {
197                use $crate::Handler;
198                self.$target.has_upgrade(upgrade)
199            }
200
201            async fn upgrade(&self, upgrade: $crate::Upgrade) {
202                use $crate::Handler;
203                self.$target.upgrade(upgrade).await;
204            }
205        }
206    };
207}