//! Macros managing requests and responses. //! //! Our protocol uses the Result(T) type to communicate rich errors to //! the client. These macros deal with sending a request using the //! asynchronous I/O framework Tokio, and decoding the result. //! //! This implementation uses macros instead of functions to interface //! with the code stubs generated by the RPC compiler. // Sends request and decodes result. // // Sends the given request and decodes the result. macro_rules! make_request { ( $core: expr, $request: expr ) => {{ use futures_util::TryFutureExt; use crate::node::result::Which; let r: std::result::Result, capnp::Error> = $core.block_on( $request.send().promise .and_then(|response| -> Promise, capnp::Error> { let r = pry!(pry!(pry!(response.get()).get_result()).which()); let r = match r { /* The Result. */ Which::Ok(Ok(x)) => Ok(x), Which::Err(Ok(e)) => Err(anyhow::Error::from(e)), /* Protocol violations. */ Which::Ok(Err(e)) => Err(anyhow::Error::from(e)), Which::Err(Err(e)) => Err(anyhow::Error::from(e)), }; Promise::ok(r) })); r? }} } macro_rules! make_request_map { ( $core: expr, $request: expr, $map: expr ) => {{ use futures_util::TryFutureExt; use crate::node::result::Which; let r: std::result::Result, capnp::Error> = $core.block_on( $request.send().promise .and_then(|response| -> Promise, capnp::Error> { let r = pry!(pry!(pry!(response.get()).get_result()).which()); let r = match r { /* The Result. */ Which::Ok(Ok(x)) => $map(x), Which::Err(Ok(e)) => Err(anyhow::Error::from(e)), /* Protocol violations. */ Which::Ok(Err(e)) => Err(anyhow::Error::from(e)), Which::Err(Err(e)) => Err(anyhow::Error::from(e)), }; Promise::ok(r) })); r? }} } /// These macros are for server functions. Because they use the /// 'results' parameter, they must be bound explicitly at the /// beginning of the function. macro_rules! bind_results { ( $results: ident ) => { #[allow(unused)] const DEBUG_BACKEND_ERRORS: bool = false; /// Behaves like `return Err(_)` for server functions. #[allow(unused_macros)] macro_rules! fail { ( $expr:expr ) => {{ if DEBUG_BACKEND_ERRORS { eprintln!("{}:{}: {:?}", file!(), line!(), $expr); } pry!($results.get().get_result()).set_err($expr); return Promise::ok(()); }}; } /// Behaves like `try!` for server functions. /// /// If the given expression evaluates to Err(_), the error is /// stored in the result and the function terminates. #[allow(unused_macros)] macro_rules! sry { ( $expr:expr ) => {{ match $expr { Ok(x) => x, Err(x) => { if DEBUG_BACKEND_ERRORS { eprintln!("{}:{}: {:?}", file!(), line!(), x); } pry!($results.get().get_result()).set_err(x.into()); return Promise::ok(()); }, } }}; } }; }