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