Skip to main content

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