ez_jsonrpc/
params.rs

1//! Extra support for parameter (de)serialization
2mod _ser;
3mod assert_named;
4mod from_named_impl;
5mod from_positional_impl;
6mod to_named_impl;
7mod to_positional_impl;
8
9use std::marker::PhantomData;
10
11#[doc(inline)] // TODO(aatifsyed): document these properly
12pub use ez_jsonrpc_macros::*;
13
14#[doc(inline)]
15pub use {
16    _ser::{Error, Serializer},
17    assert_named::AssertNamed,
18};
19
20pub mod ser {
21    use ez_jsonrpc_types::Map;
22    use serde::ser::{SerializeMap, SerializeSeq};
23    use serde_json::Value;
24
25    /// A [`SerializeSeq`] implementor suitable for constructing a
26    /// [`RequestParameters::ByPosition`](crate::types::RequestParameters::ByPosition).
27    #[derive(Debug, Default, Clone)]
28    pub struct ByPosition {
29        inner: Vec<Value>,
30    }
31
32    impl ByPosition {
33        pub fn new() -> Self {
34            Self::default()
35        }
36        pub fn with_capacity(capacity: usize) -> Self {
37            Self {
38                inner: Vec::with_capacity(capacity),
39            }
40        }
41    }
42
43    impl SerializeSeq for ByPosition {
44        type Ok = Vec<Value>;
45        type Error = serde_json::Error;
46
47        fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
48        where
49            T: ?Sized + serde::Serialize,
50        {
51            self.inner.push(serde_json::to_value(value)?);
52            Ok(())
53        }
54
55        fn end(self) -> Result<Self::Ok, Self::Error> {
56            Ok(self.inner)
57        }
58    }
59
60    /// A [`SerializeMap`] implementor suitable for constructing a
61    /// [`RequestParameters::ByName`](crate::types::RequestParameters::ByName).
62    #[derive(Debug, Default, Clone)]
63    pub struct ByName {
64        map: Map,
65        next_key: Option<String>,
66    }
67
68    impl ByName {
69        pub fn new() -> Self {
70            Self::default()
71        }
72        pub fn with_capacity(capacity: usize) -> Self {
73            Self {
74                map: Map::with_capacity(capacity),
75                next_key: None,
76            }
77        }
78    }
79
80    impl SerializeMap for ByName {
81        type Ok = Map;
82        type Error = serde_json::Error;
83
84        fn serialize_key<T>(&mut self, key: &T) -> Result<(), Self::Error>
85        where
86            T: ?Sized + serde::Serialize,
87        {
88            match key.serialize(super::_ser::MapKeySerializer) {
89                Ok(it) => {
90                    self.next_key = Some(it);
91                    Ok(())
92                }
93                Err(e) => match e.inner {
94                    super::_ser::ErrorInner::UnsupportedType(_) => unreachable!(),
95                    super::_ser::ErrorInner::Json(e) => Err(e),
96                },
97            }
98        }
99
100        fn serialize_value<T>(&mut self, value: &T) -> Result<(), Self::Error>
101        where
102            T: ?Sized + serde::Serialize,
103        {
104            let key = self
105                .next_key
106                .take()
107                .expect("serialize_value called before serialize_key");
108            self.map.insert(key, serde_json::to_value(value)?);
109            Ok(())
110        }
111
112        fn end(self) -> Result<Self::Ok, Self::Error> {
113            Ok(self.map)
114        }
115    }
116}
117
118/// Support for serializing a type into a [`RequestParameters::ByPosition`](crate::types::RequestParameters::ByPosition).
119pub trait SerializePositional {
120    fn ser_positional<S: serde::ser::SerializeSeq>(&self, serializer: S)
121        -> Result<S::Ok, S::Error>;
122}
123
124/// Support for deserializing a type from a [`RequestParameters::ByPosition`](crate::types::RequestParameters::ByPosition).
125pub trait DeserializePositional<'de>: Sized {
126    fn de_positional<D: serde::de::SeqAccess<'de>>(deserializer: D) -> Result<Self, D::Error>;
127}
128
129/// Support for deserializing a type from a [`RequestParameters::ByPosition`](crate::types::RequestParameters::ByPosition).
130pub trait DeserializePositionalSeed<'de>: Sized {
131    type Value;
132    fn de_positional_seed<D: serde::de::SeqAccess<'de>>(
133        self,
134        deserializer: D,
135    ) -> Result<Self::Value, D::Error>;
136}
137
138impl<'de, T> DeserializePositionalSeed<'de> for PhantomData<T>
139where
140    T: DeserializePositional<'de>,
141{
142    type Value = T;
143
144    fn de_positional_seed<D: serde::de::SeqAccess<'de>>(
145        self,
146        deserializer: D,
147    ) -> Result<Self::Value, D::Error> {
148        T::de_positional(deserializer)
149    }
150}
151
152/// Support for serializing a type into a [`RequestParameters::ByName`](crate::types::RequestParameters::ByName).
153pub trait SerializeNamed {
154    fn ser_named<S: serde::ser::SerializeMap>(&self, serializer: S) -> Result<S::Ok, S::Error>;
155}
156
157/// Support for serializing a type from a [`RequestParameters::ByName`](crate::types::RequestParameters::ByName).
158pub trait DeserializeNamed<'de>: Sized {
159    fn de_named<D: serde::de::MapAccess<'de>>(deserializer: D) -> Result<Self, D::Error>;
160}
161
162/// Support for serializing a type from a [`RequestParameters::ByName`](crate::types::RequestParameters::ByName).
163pub trait DeserializeNamedSeed<'de>: Sized {
164    type Value;
165    fn de_named_seed<D: serde::de::MapAccess<'de>>(
166        self,
167        deserializer: D,
168    ) -> Result<Self::Value, D::Error>;
169}
170
171impl<'de, T> DeserializeNamedSeed<'de> for PhantomData<T>
172where
173    T: DeserializeNamed<'de>,
174{
175    type Value = T;
176    fn de_named_seed<D: serde::de::MapAccess<'de>>(
177        self,
178        deserializer: D,
179    ) -> Result<Self::Value, D::Error> {
180        T::de_named(deserializer)
181    }
182}
183
184macro_rules! for_tuples {
185    ($callback:ident) => {
186        $callback!();
187        $callback!(T0);
188        $callback!(T0, T1);
189        $callback!(T0, T1, T2);
190        $callback!(T0, T1, T2, T3);
191        $callback!(T0, T1, T2, T3, T4);
192        $callback!(T0, T1, T2, T3, T4, T5);
193        $callback!(T0, T1, T2, T3, T4, T5, T6);
194        $callback!(T0, T1, T2, T3, T4, T5, T6, T7);
195        $callback!(T0, T1, T2, T3, T4, T5, T6, T7, T8);
196        $callback!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);
197        $callback!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
198        $callback!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
199        $callback!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);
200        $callback!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T14);
201        $callback!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T14, T15);
202        $callback!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T14, T15, T16);
203    };
204}
205pub(crate) use for_tuples;
206
207#[cfg(test)]
208mod tests {
209    use std::fmt;
210
211    use super::*;
212
213    use ez_jsonrpc_types::RequestParameters;
214    use fmt::Debug;
215    use serde::{
216        de::{DeserializeOwned, IntoDeserializer as _},
217        Deserialize, Serialize,
218    };
219    use serde_json::json;
220
221    #[derive(Deserialize, Serialize, PartialEq, Debug)]
222    struct Foo {
223        name: String,
224        count: u32,
225    }
226
227    #[track_caller]
228    fn do_test<T: DeserializeOwned + Serialize + PartialEq + Debug>(
229        item: T,
230        expected: RequestParameters,
231    ) {
232        assert_eq!(
233            &T::deserialize(expected.clone().into_deserializer()).expect("couldn't deserialize"),
234            &item,
235            "deserialized mismatch"
236        );
237        assert_eq!(
238            item.serialize(Serializer).expect("couldn't serialize"),
239            expected,
240            "serialized mismatch"
241        )
242    }
243
244    #[test]
245    fn test() {
246        do_test(
247            (String::from("hello"), 1),
248            RequestParameters::ByPosition(vec![json!("hello"), json!(1)]),
249        );
250        do_test(
251            Foo {
252                name: "string".into(),
253                count: 1,
254            },
255            RequestParameters::ByName(crate::types::Map::from_iter([
256                (String::from("name"), json!("string")),
257                (String::from("count"), json!(1)),
258            ])),
259        );
260    }
261}