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}