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