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(any(test, 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
165impl<T: Value + PartialEq> PartialEq<T> for ValueWithType<'_, T> {
166    fn eq(&self, other: &T) -> bool {
167        self.val == other
168    }
169}
170
171use core::fmt;
172
173impl<T: fmt::Debug + Value<Type: fmt::Debug>> fmt::Debug for ValueWithType<'_, T> {
174    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
175        f.debug_struct("ValueWithType")
176            .field("type", self.ty())
177            .field("value", self.value())
178            .finish()
179    }
180}
181
182/// Adds a `Typespace` context atop of a borrowed type.
183#[derive(Debug)]
184pub struct WithTypespace<'a, T: ?Sized> {
185    /// The typespace context that has been added to `ty`.
186    typespace: &'a Typespace,
187    /// What we've added the context to.
188    ty: &'a T,
189}
190
191impl<T: ?Sized> Copy for WithTypespace<'_, T> {}
192impl<T: ?Sized> Clone for WithTypespace<'_, T> {
193    fn clone(&self) -> Self {
194        *self
195    }
196}
197
198impl<'a, T: ?Sized> WithTypespace<'a, T> {
199    /// Wraps `ty` in a context combined with the `typespace`.
200    pub const fn new(typespace: &'a Typespace, ty: &'a T) -> Self {
201        Self { typespace, ty }
202    }
203
204    /// Wraps `ty` in an empty context.
205    pub const fn empty(ty: &'a T) -> Self {
206        Self::new(Typespace::EMPTY, ty)
207    }
208
209    /// Returns the object that the context was created with.
210    pub const fn ty(&self) -> &'a T {
211        self.ty
212    }
213
214    /// Returns the typespace context.
215    pub const fn typespace(&self) -> &'a Typespace {
216        self.typespace
217    }
218
219    /// Reuses the typespace we already have and returns `ty: U` wrapped with it.
220    pub fn with<'b, U>(&self, ty: &'b U) -> WithTypespace<'b, U>
221    where
222        'a: 'b,
223    {
224        WithTypespace {
225            typespace: self.typespace,
226            ty,
227        }
228    }
229
230    pub(crate) fn iter_with<U: 'a, I: IntoIterator<Item = &'a U>>(&self, tys: I) -> IterWithTypespace<'a, I::IntoIter> {
231        IterWithTypespace {
232            typespace: self.typespace,
233            iter: tys.into_iter(),
234        }
235    }
236
237    /// Wraps `val` with the type and typespace context in `self`.
238    pub fn with_value<'b, V: Value<Type = T>>(&self, val: &'b V) -> ValueWithType<'b, V>
239    where
240        'a: 'b,
241    {
242        ValueWithType::new(*self, val)
243    }
244
245    /// Returns the `AlgebraicType` that `r` resolves to in the context of our `Typespace`.
246    ///
247    /// Panics if `r` is not known by our `Typespace`.
248    pub fn resolve(&self, r: AlgebraicTypeRef) -> WithTypespace<'a, AlgebraicType> {
249        WithTypespace {
250            typespace: self.typespace,
251            ty: &self.typespace[r],
252        }
253    }
254
255    /// Maps the object we've wrapped from `&T -> &U` in our context.
256    ///
257    /// This can be used to e.g., project fields and through a structure.
258    /// This provides an implementation of functor mapping for `WithTypespace`.
259    pub fn map<U: ?Sized>(&self, f: impl FnOnce(&'a T) -> &'a U) -> WithTypespace<'a, U> {
260        WithTypespace {
261            typespace: self.typespace,
262            ty: f(self.ty),
263        }
264    }
265}
266
267pub struct IterWithTypespace<'a, I> {
268    typespace: &'a Typespace,
269    iter: I,
270}
271
272impl<'a, I, T: 'a> Iterator for IterWithTypespace<'a, I>
273where
274    I: Iterator<Item = &'a T>,
275{
276    type Item = WithTypespace<'a, T>;
277    fn next(&mut self) -> Option<Self::Item> {
278        self.iter.next().map(|ty| self.typespace.with_type(ty))
279    }
280    fn size_hint(&self) -> (usize, Option<usize>) {
281        self.iter.size_hint()
282    }
283}
284
285impl<'a, I, T: 'a> ExactSizeIterator for IterWithTypespace<'a, I>
286where
287    I: ExactSizeIterator<Item = &'a T>,
288{
289    fn len(&self) -> usize {
290        self.iter.len()
291    }
292}
293
294/// Required for derive(SpacetimeType) to work outside of a module
295#[macro_export]
296#[doc(hidden)]
297macro_rules! __make_register_reftype {
298    ($ty:ty, $name:literal) => {};
299}
300
301/// A helper for prettier Debug implementation, without extra indirection around Some("name").
302fn dbg_aggregate_name(opt: &Option<Box<str>>) -> &dyn std::fmt::Debug {
303    opt.as_ref().map_or(opt, |s| s)
304}