maf/rpc/
params.rs

1use serde::de::DeserializeOwned;
2
3use crate::callable::{CallableParam, SupportsAsync};
4
5use super::{RpcError, RpcRequestContext, RpcRequestData, RpcRequestInit};
6
7/// Extractor for RPC function parameters.
8///
9/// ```rust
10/// use maf::prelude::*;
11///
12/// // A simple RPC that takes a single integer parameter.
13/// async fn increment_counter(Params(counter): Params<i32>, test: Store<CounterStore>) -> i32 {
14///     let mut store = test.write().await;
15///     store.count += counter;
16///     store.count
17/// }
18///
19/// async fn set_counter(
20///     // Multiple parameters can be extracted as a tuple.
21///     Params((new_value, stop, reason)): Params<(i32, boolean, String)>,
22///     test: Store<CounterStore>
23/// ) {
24///     let mut store = test.write().await;
25///     println!("Setting counter to {} because {}", new_value, reason);
26///     store.count = new_value;
27///     if stop {
28///         // Do something to stop the counter...
29///     }
30/// }
31/// ```
32#[derive(Debug)]
33pub struct Params<T: DeserializeOwned>(pub T);
34
35#[derive(Debug, thiserror::Error)]
36pub enum ParamsError {
37    #[error("failed to deserialize params: {0}")]
38    Deserialize(#[from] serde_json::Error),
39    #[error("request body data already consumed")]
40    DataAlreadyConsumed,
41}
42
43impl<T: DeserializeOwned + Send + Sync> CallableParam<RpcRequestContext, RpcRequestInit>
44    for Params<T>
45{
46    type Error = RpcError;
47
48    async fn extract(
49        ctx: &mut RpcRequestContext,
50        init: &RpcRequestInit,
51    ) -> Result<Self, Self::Error> {
52        let data = match ctx.request.data.take().ok_or_else(|| {
53            RpcError::ParamsError(init.method.clone(), ParamsError::DataAlreadyConsumed)
54        })? {
55            RpcRequestData::Typed(data) => serde_json::from_value(data)?,
56        };
57
58        Ok(Self(data))
59    }
60}
61
62impl<T: DeserializeOwned> SupportsAsync for Params<T> {}