spacetimedb_sats/
lib.rs

1pub mod algebraic_type;
2mod algebraic_type_ref;
3pub mod algebraic_value;
4mod algebraic_value_hash;
5pub mod array_type;
6pub mod array_value;
7pub mod bsatn;
8pub mod buffer;
9pub mod convert;
10pub mod de;
11pub mod hash;
12pub mod hex;
13pub mod meta_type;
14pub mod primitives;
15pub mod product_type;
16pub mod product_type_element;
17pub mod product_value;
18mod resolve_refs;
19pub mod satn;
20pub mod ser;
21pub mod size_of;
22pub mod sum_type;
23pub mod sum_type_variant;
24pub mod sum_value;
25pub mod time_duration;
26pub mod timestamp;
27pub mod typespace;
28
29#[cfg(any(test, feature = "proptest"))]
30pub mod proptest;
31
32#[cfg(feature = "serde")]
33pub mod serde {
34    pub use crate::de::serde::{deserialize_from as deserialize, SerdeDeserializer};
35    pub use crate::ser::serde::{serialize_to as serialize, SerdeSerializer};
36
37    /// A wrapper around a `serde` error which occurred while translating SATS <-> serde.
38    #[repr(transparent)]
39    pub struct SerdeError<E>(pub E);
40
41    /// A wrapper type that implements `serde` traits when `T` implements SATS traits.
42    ///
43    /// Specifically:
44    /// - <code>T: [sats::Serialize][crate::ser::Serialize] => `SerializeWrapper<T>`: [serde::Serialize]</code>
45    /// - <code>T: [sats::Deserialize<'de>][crate::de::Deserialize] => `SerializeWrapper<T>`: [serde::Deserialize<'de>]</code>
46    /// - <code>T: [sats::DeserializeSeed<'de>][crate::de::DeserializeSeed] => `SerializeWrapper<T>`: [serde::DeserializeSeed<'de>]</code>
47    #[repr(transparent)]
48    pub struct SerdeWrapper<T: ?Sized>(pub T);
49
50    impl<T: ?Sized> SerdeWrapper<T> {
51        /// Wraps a value in `SerdeWrapper`.
52        pub fn new(t: T) -> Self
53        where
54            T: Sized,
55        {
56            Self(t)
57        }
58
59        /// Converts `&T` to `&SerializeWrapper<T>`.
60        pub fn from_ref(t: &T) -> &Self {
61            // SAFETY: OK because of `repr(transparent)`.
62            unsafe { &*(t as *const T as *const SerdeWrapper<T>) }
63        }
64    }
65}
66
67/// Allows the macros in [`spacetimedb_bindings_macro`] to accept `crate = spacetimedb_sats`,
68/// which will then emit `$krate::sats`.
69#[doc(hidden)]
70pub use crate as sats;
71
72pub use algebraic_type::AlgebraicType;
73pub use algebraic_type_ref::AlgebraicTypeRef;
74pub use algebraic_value::{i256, u256, AlgebraicValue, F32, F64};
75pub use algebraic_value_hash::hash_bsatn;
76pub use array_type::ArrayType;
77pub use array_value::ArrayValue;
78pub use product_type::ProductType;
79pub use product_type_element::ProductTypeElement;
80pub use product_value::ProductValue;
81pub use sum_type::SumType;
82pub use sum_type_variant::SumTypeVariant;
83pub use sum_value::SumValue;
84pub use typespace::{GroundSpacetimeType, SpacetimeType, Typespace};
85
86pub use de::Deserialize;
87pub use ser::Serialize;
88
89/// The `Value` trait provides an abstract notion of a value.
90///
91/// All we know about values abstractly is that they have a `Type`.
92pub trait Value {
93    /// The type of this value.
94    type Type;
95}
96
97impl<T: Value> Value for Box<[T]> {
98    // TODO(centril/phoebe): This looks weird; shouldn't it be ArrayType?
99    type Type = T::Type;
100}
101
102/// A borrowed value combined with its type and typing context (`Typespace`).
103pub struct ValueWithType<'a, T: Value> {
104    /// The type combined with the context of this `val`ue.
105    ty: WithTypespace<'a, T::Type>,
106    /// The borrowed value.
107    val: &'a T,
108}
109
110impl<T: Value> Copy for ValueWithType<'_, T> {}
111impl<T: Value> Clone for ValueWithType<'_, T> {
112    fn clone(&self) -> Self {
113        *self
114    }
115}
116
117impl<'a, T: Value> ValueWithType<'a, T> {
118    /// Wraps the borrowed value `val` with its type combined with context.
119    pub fn new(ty: WithTypespace<'a, T::Type>, val: &'a T) -> Self {
120        Self { ty, val }
121    }
122
123    /// Returns the borrowed value.
124    pub fn value(&self) -> &'a T {
125        self.val
126    }
127
128    /// Returns the type of the value.
129    pub fn ty(&self) -> &'a T::Type {
130        self.ty.ty
131    }
132
133    pub fn ty_s(&self) -> WithTypespace<'a, T::Type> {
134        self.ty
135    }
136
137    /// Returns the typing context (`Typespace`).
138    pub fn typespace(&self) -> &'a Typespace {
139        self.ty.typespace
140    }
141
142    /// Reuses the typespace we already have and returns `val` and `ty` wrapped with it.
143    pub fn with<'b, U: Value>(&self, ty: &'b U::Type, val: &'b U) -> ValueWithType<'b, U>
144    where
145        'a: 'b,
146    {
147        ValueWithType {
148            ty: self.ty.with(ty),
149            val,
150        }
151    }
152}
153
154impl<'a, T: Value> ValueWithType<'a, Box<[T]>> {
155    pub fn iter(&self) -> impl Iterator<Item = ValueWithType<'a, T>> + use<'_, 'a, T> {
156        self.value().iter().map(|val| ValueWithType { ty: self.ty, val })
157    }
158}
159
160/// Adds a `Typespace` context atop of a borrowed type.
161#[derive(Debug)]
162pub struct WithTypespace<'a, T: ?Sized> {
163    /// The typespace context that has been added to `ty`.
164    typespace: &'a Typespace,
165    /// What we've added the context to.
166    ty: &'a T,
167}
168
169impl<T: ?Sized> Copy for WithTypespace<'_, T> {}
170impl<T: ?Sized> Clone for WithTypespace<'_, T> {
171    fn clone(&self) -> Self {
172        *self
173    }
174}
175
176impl<'a, T: ?Sized> WithTypespace<'a, T> {
177    /// Wraps `ty` in a context combined with the `typespace`.
178    pub const fn new(typespace: &'a Typespace, ty: &'a T) -> Self {
179        Self { typespace, ty }
180    }
181
182    /// Wraps `ty` in an empty context.
183    pub const fn empty(ty: &'a T) -> Self {
184        Self::new(Typespace::EMPTY, ty)
185    }
186
187    /// Returns the object that the context was created with.
188    pub const fn ty(&self) -> &'a T {
189        self.ty
190    }
191
192    /// Returns the typespace context.
193    pub const fn typespace(&self) -> &'a Typespace {
194        self.typespace
195    }
196
197    /// Reuses the typespace we already have and returns `ty: U` wrapped with it.
198    pub fn with<'b, U>(&self, ty: &'b U) -> WithTypespace<'b, U>
199    where
200        'a: 'b,
201    {
202        WithTypespace {
203            typespace: self.typespace,
204            ty,
205        }
206    }
207
208    pub(crate) fn iter_with<U: 'a, I: IntoIterator<Item = &'a U>>(&self, tys: I) -> IterWithTypespace<'a, I::IntoIter> {
209        IterWithTypespace {
210            typespace: self.typespace,
211            iter: tys.into_iter(),
212        }
213    }
214
215    /// Wraps `val` with the type and typespace context in `self`.
216    pub fn with_value<'b, V: Value<Type = T>>(&self, val: &'b V) -> ValueWithType<'b, V>
217    where
218        'a: 'b,
219    {
220        ValueWithType::new(*self, val)
221    }
222
223    /// Returns the `AlgebraicType` that `r` resolves to in the context of our `Typespace`.
224    ///
225    /// Panics if `r` is not known by our `Typespace`.
226    pub fn resolve(&self, r: AlgebraicTypeRef) -> WithTypespace<'a, AlgebraicType> {
227        WithTypespace {
228            typespace: self.typespace,
229            ty: &self.typespace[r],
230        }
231    }
232
233    /// Maps the object we've wrapped from `&T -> &U` in our context.
234    ///
235    /// This can be used to e.g., project fields and through a structure.
236    /// This provides an implementation of functor mapping for `WithTypespace`.
237    pub fn map<U: ?Sized>(&self, f: impl FnOnce(&'a T) -> &'a U) -> WithTypespace<'a, U> {
238        WithTypespace {
239            typespace: self.typespace,
240            ty: f(self.ty),
241        }
242    }
243}
244
245pub struct IterWithTypespace<'a, I> {
246    typespace: &'a Typespace,
247    iter: I,
248}
249
250impl<'a, I, T: 'a> Iterator for IterWithTypespace<'a, I>
251where
252    I: Iterator<Item = &'a T>,
253{
254    type Item = WithTypespace<'a, T>;
255    fn next(&mut self) -> Option<Self::Item> {
256        self.iter.next().map(|ty| self.typespace.with_type(ty))
257    }
258    fn size_hint(&self) -> (usize, Option<usize>) {
259        self.iter.size_hint()
260    }
261}
262
263impl<'a, I, T: 'a> ExactSizeIterator for IterWithTypespace<'a, I>
264where
265    I: ExactSizeIterator<Item = &'a T>,
266{
267    fn len(&self) -> usize {
268        self.iter.len()
269    }
270}
271
272/// Required for derive(SpacetimeType) to work outside of a module
273#[macro_export]
274#[doc(hidden)]
275macro_rules! __make_register_reftype {
276    ($ty:ty, $name:literal) => {};
277}
278
279/// A helper for prettier Debug implementation, without extra indirection around Some("name").
280fn dbg_aggregate_name(opt: &Option<Box<str>>) -> &dyn std::fmt::Debug {
281    opt.as_ref().map_or(opt, |s| s)
282}