Skip to main content

spacetimedb_schema/def/
deserialize.rs

1//! Helpers to allow deserializing data using a ReducerDef.
2
3use crate::{
4    def::{ProcedureDef, ReducerDef, ViewDef},
5    identifier::Identifier,
6};
7use spacetimedb_lib::{
8    sats::{self, de, impl_serialize, ser, ProductValue},
9    ProductType,
10};
11
12/// Wrapper around a function def that allows deserializing to a [`ProductValue`] at the type of the def's parameter [`ProductType`].
13///
14/// Sensible instantiations for `Def` are [`ProcedureDef`], [`ReducerDef`] and [`ViewDef`].
15pub struct ArgsSeed<'a, Def>(pub sats::WithTypespace<'a, Def>);
16
17// Manual impls of traits rather than derives,
18// 'cause derives are always constrained on all type parameters,
19// even though `ArgsSeed<Def: ?Copy>: Copy` in our case.
20impl<Def> Clone for ArgsSeed<'_, Def> {
21    fn clone(&self) -> Self {
22        *self
23    }
24}
25impl<Def> Copy for ArgsSeed<'_, Def> {}
26
27pub trait FunctionDef {
28    fn params(&self) -> &ProductType;
29    fn name(&self) -> &Identifier;
30}
31
32impl FunctionDef for ReducerDef {
33    fn params(&self) -> &ProductType {
34        &self.params
35    }
36    fn name(&self) -> &Identifier {
37        self.name.as_identifier()
38    }
39}
40
41impl FunctionDef for ProcedureDef {
42    fn params(&self) -> &ProductType {
43        &self.params
44    }
45    fn name(&self) -> &Identifier {
46        &self.name
47    }
48}
49
50impl FunctionDef for ViewDef {
51    fn params(&self) -> &ProductType {
52        &self.params
53    }
54    fn name(&self) -> &Identifier {
55        &self.name
56    }
57}
58
59impl<Def: FunctionDef> ArgsSeed<'_, Def> {
60    pub fn name(&self) -> &Identifier {
61        self.0.ty().name()
62    }
63
64    pub fn params(&self) -> &ProductType {
65        self.0.ty().params()
66    }
67}
68
69impl<'de, Def: FunctionDef> de::DeserializeSeed<'de> for ArgsSeed<'_, Def> {
70    type Output = ProductValue;
71
72    fn deserialize<D: de::Deserializer<'de>>(self, deserializer: D) -> Result<Self::Output, D::Error> {
73        deserializer.deserialize_product(self)
74    }
75}
76
77impl<'de, Def: FunctionDef> de::ProductVisitor<'de> for ArgsSeed<'_, Def> {
78    type Output = ProductValue;
79
80    fn product_name(&self) -> Option<&str> {
81        Some(self.0.ty().name())
82    }
83
84    fn product_len(&self) -> usize {
85        self.0.ty().params().elements.len()
86    }
87
88    fn product_kind(&self) -> de::ProductKind {
89        de::ProductKind::ReducerArgs
90    }
91
92    fn visit_seq_product<A: de::SeqProductAccess<'de>>(self, tup: A) -> Result<Self::Output, A::Error> {
93        de::visit_seq_product(self.0.map(|r| &*r.params().elements), &self, tup)
94    }
95
96    fn visit_named_product<A: de::NamedProductAccess<'de>>(self, tup: A) -> Result<Self::Output, A::Error> {
97        de::visit_named_product(self.0.map(|r| &*r.params().elements), &self, tup)
98    }
99}
100
101pub struct ReducerArgsWithSchema<'a> {
102    value: &'a ProductValue,
103    ty: sats::WithTypespace<'a, ReducerDef>,
104}
105impl_serialize!([] ReducerArgsWithSchema<'_>, (self, ser) => {
106    use itertools::Itertools;
107    use ser::SerializeSeqProduct;
108    let mut seq = ser.serialize_seq_product(self.value.elements.len())?;
109    for (value, elem) in self.value.elements.iter().zip_eq(&*self.ty.ty().params.elements) {
110        seq.serialize_element(&self.ty.with(&elem.algebraic_type).with_value(value))?;
111    }
112    seq.end()
113});