1 //! Macros managing requests and responses.
2 //!
3 //! Our protocol uses the Result(T) type to communicate rich errors to
4 //! the client.  These macros deal with sending a request using the
5 //! asynchronous I/O framework Tokio, and decoding the result.
6 //!
7 //! This implementation uses macros instead of functions to interface
8 //! with the code stubs generated by the RPC compiler.
9 
10 // Sends request and decodes result.
11 //
12 // Sends the given request and decodes the result.
13 macro_rules! make_request {
14     ( $core: expr, $request: expr ) => {{
15         use crate::node::result::Which;
16 
17         let r: std::result::Result<Result<_>, capnp::Error> = $core.run(
18             $request.send().promise
19                 .and_then(|response| -> Promise<Result<_>, capnp::Error> {
20                     let r = pry!(pry!(pry!(response.get()).get_result()).which());
21                     let r = match r {
22                         /* The Result.  */
23                         Which::Ok(Ok(x)) => Ok(x),
24                         Which::Err(Ok(e)) => Err(anyhow::Error::from(e)),
25                         /* Protocol violations.  */
26                         Which::Ok(Err(e)) => Err(anyhow::Error::from(e)),
27                         Which::Err(Err(e)) => Err(anyhow::Error::from(e)),
28                     };
29                     Promise::ok(r)
30                 }));
31         r?
32     }}
33 }
34 
35 macro_rules! make_request_map {
36     ( $core: expr, $request: expr, $map: expr ) => {{
37         use crate::node::result::Which;
38 
39         let r: std::result::Result<Result<_>, capnp::Error> = $core.run(
40             $request.send().promise
41                 .and_then(|response| -> Promise<Result<_>, capnp::Error> {
42                     let r = pry!(pry!(pry!(response.get()).get_result()).which());
43                     let r = match r {
44                         /* The Result.  */
45                         Which::Ok(Ok(x)) => $map(x),
46                         Which::Err(Ok(e)) => Err(anyhow::Error::from(e)),
47                         /* Protocol violations.  */
48                         Which::Ok(Err(e)) => Err(anyhow::Error::from(e)),
49                         Which::Err(Err(e)) => Err(anyhow::Error::from(e)),
50                     };
51                     Promise::ok(r)
52                 }));
53         r?
54     }}
55 }
56 
57 /// These macros are for server functions.  Because they use the
58 /// 'results' parameter, they must be bound explicitly at the
59 /// beginning of the function.
60 macro_rules! bind_results {
61     ( $results: ident ) => {
62         #[allow(unused)]
63         const DEBUG_BACKEND_ERRORS: bool = false;
64 
65         /// Behaves like `return Err(_)` for server functions.
66         #[allow(unused_macros)]
67         macro_rules! fail {
68             ( $expr:expr ) => {{
69                 if DEBUG_BACKEND_ERRORS {
70                     eprintln!("{}:{}: {:?}", file!(), line!(), $expr);
71                 }
72                 pry!($results.get().get_result()).set_err($expr);
73                 return Promise::ok(());
74             }};
75         }
76 
77         /// Behaves like `try!` for server functions.
78         ///
79         /// If the given expression evaluates to Err(_), the error is
80         /// stored in the result and the function terminates.
81         #[allow(unused_macros)]
82         macro_rules! sry {
83             ( $expr:expr ) => {{
84                 match $expr {
85                     Ok(x) => x,
86                     Err(x) => {
87                         if DEBUG_BACKEND_ERRORS {
88                             eprintln!("{}:{}: {:?}", file!(), line!(), x);
89                         }
90                         pry!($results.get().get_result()).set_err(x.into());
91                         return Promise::ok(());
92                     },
93                 }
94             }};
95         }
96     };
97 }
98