Skip to main content

sov_universal_wallet/ty/
mod.rs

1pub mod byte_display;
2pub mod visitor;
3use core::panic;
4use std::fmt::Debug;
5
6use borsh::{BorshDeserialize, BorshSerialize};
7pub use byte_display::ByteDisplay;
8#[cfg(feature = "serde")]
9use serde::{de::DeserializeOwned, Deserialize, Serialize};
10
11use crate::schema::{IndexLinking, Link, OverrideSchema, Primitive};
12
13macro_rules! macro_for_ints {
14    ($macro:ident) => {
15        $macro!(u8);
16        $macro!(u16);
17        $macro!(u32);
18        $macro!(u64);
19        $macro!(u128);
20        $macro!(i8);
21        $macro!(i16);
22        $macro!(i32);
23        $macro!(i64);
24        $macro!(i128);
25    };
26}
27pub(crate) use macro_for_ints;
28
29pub trait LinkingScheme: Clone + Debug {
30    /// The type used to link to other types in the schema representation. Usually, this is an enum
31    /// which represents primitives with an immediate value and complex types with some kind of pointer.
32    #[cfg(not(feature = "serde"))]
33    type TypeLink: Clone + Debug + PartialEq + Eq + BorshSerialize + BorshDeserialize;
34    #[cfg(feature = "serde")]
35    type TypeLink: Clone
36        + Debug
37        + PartialEq
38        + Eq
39        + BorshSerialize
40        + BorshDeserialize
41        + Serialize
42        + DeserializeOwned;
43}
44
45#[derive(Clone, Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
46#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
47pub enum Ty<L: LinkingScheme> {
48    Enum(Enum<L>),
49    Struct(Struct<L>),
50    Tuple(Tuple<L>),
51    Option {
52        value: L::TypeLink,
53    },
54    Integer(IntegerType, IntegerDisplay),
55    ByteArray {
56        len: usize,
57        display: ByteDisplay,
58    },
59    Float32,
60    Float64,
61    String,
62    Boolean,
63    Skip {
64        len: usize,
65    },
66    ByteVec {
67        display: ByteDisplay,
68    },
69    Array {
70        len: usize,
71        value: L::TypeLink,
72    },
73    Vec {
74        value: L::TypeLink,
75    },
76    Map {
77        key: L::TypeLink,
78        value: L::TypeLink,
79    },
80}
81
82impl<L: LinkingScheme> Ty<L> {
83    /// Returns true if the type is a skip type
84    pub fn is_skip(&self) -> bool {
85        matches!(self, Ty::Skip { .. })
86    }
87}
88
89impl Ty<IndexLinking> {
90    /// Fills the next available placeholder in the type with the given link, panicking if no placeholder is available.
91    pub fn fill_next_placholder(&mut self, child: Link) {
92        let err_msg =
93            format!("Called `fill_next_placholder` on a type with no placeholders: {self:?}");
94        match self {
95            Ty::Enum(e) => {
96                e.variants
97                    .iter_mut()
98                    .find(|v| v.value == Some(Link::Placeholder))
99                    .expect(&err_msg).value = Some(child);
100            }
101            Ty::Struct(s) => {
102                s.fields
103                    .iter_mut()
104                    .find(|field| field.value == Link::Placeholder)
105                    .expect(&err_msg)
106                    .value = child;
107            }
108            Ty::Tuple(t) => {
109                t.fields
110                    .iter_mut()
111                    .find(|field| field.value == Link::Placeholder)
112                    .expect(&err_msg)
113                    .value = child;
114            }
115            Ty::Option { value } => if *value == Link::Placeholder {
116                *value = child;
117            } else {
118                panic!("{}", err_msg);
119            }
120            Ty::Array { value, .. } => {
121				if *value == Link::Placeholder {
122					*value = child;
123				} else {
124					panic!("{}", err_msg);
125				}
126			}
127            Ty::Vec { value } => if *value == Link::Placeholder {
128				*value = child;
129			} else {
130				panic!("{}", err_msg);
131			}
132            Ty::Map { key, value } => if *key == Link::Placeholder {
133				*key = child;
134			} else if *value == Link::Placeholder {
135				*value = child;
136			} else {
137				panic!("{}", err_msg);
138			}
139            _ => panic!(
140                "Tried to fill a placholder on a type with no children. Only Vec, Tuple, Option, Array, Struct and Map types have children. Self: {:?}",
141                self
142            ),
143        }
144    }
145}
146
147impl<L: LinkingScheme> Ty<L> {
148    pub fn is_primitive(&self) -> bool {
149        // Match exhaustively in case additional primitives are added later
150        match self {
151            Ty::Enum(_)
152            | Ty::Struct(_)
153            | Ty::Tuple(_)
154            | Ty::Option { .. }
155            | Ty::Array { .. }
156            | Ty::Vec { .. }
157            | Ty::Map { .. } => false,
158            Ty::Integer(_, _)
159            | Ty::ByteArray { .. }
160            | Ty::ByteVec { .. }
161            | Ty::String
162            | Ty::Float32
163            | Ty::Float64
164            | Ty::Boolean
165            | Ty::Skip { .. } => true,
166        }
167    }
168
169    pub fn parent_byte_references(&self) -> Vec<(usize, usize)> {
170        match self {
171            Ty::Integer(
172                _,
173                IntegerDisplay::FixedPoint(FixedPointDisplay::FromSiblingField {
174                    field_index,
175                    byte_offset,
176                }),
177            ) => vec![(*field_index, *byte_offset)],
178            Ty::Integer(
179                _,
180                IntegerDisplay::FixedPoint(FixedPointDisplay::FromSiblingFieldWithOverride {
181                    field_index,
182                    ..
183                }),
184            ) => {
185                // Intentionally limited to 32-byte sibling fields (our token-id use case): we grab
186                // all 32 bytes to compare against `override_match`, which also covers the fallback
187                // `byte_offset` (always within 0..32).
188                (0..32).map(|i| (*field_index, i)).collect()
189            }
190            _ => Vec::new(),
191        }
192    }
193}
194
195/// An enum variant can contain...
196/// - A (possibly anonymous) struct
197/// - Another Enum
198#[derive(Clone, Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
199#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
200pub struct EnumVariant<L: LinkingScheme> {
201    pub name: String,
202    pub discriminant: u8,
203    pub template: Option<String>,
204    pub value: Option<L::TypeLink>,
205}
206
207#[derive(Clone, Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
208#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
209pub struct Enum<L: LinkingScheme> {
210    pub type_name: String,
211    pub variants: Vec<EnumVariant<L>>,
212    /// Whether this enum is "hide_tag"ged, meaning that the variant tags shouldn't be displayed.
213    pub hide_tag: bool,
214}
215
216#[derive(Clone, Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
217#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
218pub struct Struct<L: LinkingScheme> {
219    pub type_name: String,
220    pub template: Option<String>,
221    pub peekable: bool,
222    pub fields: Vec<NamedField<L>>,
223}
224
225#[derive(Clone, Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
226#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
227pub struct Tuple<L: LinkingScheme> {
228    pub template: Option<String>,
229    pub peekable: bool,
230    pub fields: Vec<UnnamedField<L>>,
231}
232
233#[derive(Clone, Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
234#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
235pub struct NamedField<L: LinkingScheme> {
236    pub display_name: String,
237    pub silent: bool,
238    pub value: L::TypeLink,
239    pub doc: String,
240}
241
242#[derive(Clone, Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
243#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
244pub struct UnnamedField<L: LinkingScheme> {
245    pub value: L::TypeLink,
246    pub silent: bool,
247    pub doc: String,
248}
249
250#[derive(Debug, Clone, Copy, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
251#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
252#[allow(non_camel_case_types)]
253pub enum IntegerType {
254    i8,
255    i16,
256    i32,
257    i64,
258    i128,
259    u8,
260    u16,
261    u32,
262    u64,
263    u128,
264}
265
266impl IntegerType {
267    pub fn size(&self) -> usize {
268        match self {
269            IntegerType::i8 => core::mem::size_of::<i8>(),
270            IntegerType::i16 => core::mem::size_of::<i16>(),
271            IntegerType::i32 => core::mem::size_of::<i32>(),
272            IntegerType::i64 => core::mem::size_of::<i64>(),
273            IntegerType::i128 => core::mem::size_of::<i128>(),
274            IntegerType::u8 => core::mem::size_of::<u8>(),
275            IntegerType::u16 => core::mem::size_of::<u16>(),
276            IntegerType::u32 => core::mem::size_of::<u32>(),
277            IntegerType::u64 => core::mem::size_of::<u64>(),
278            IntegerType::u128 => core::mem::size_of::<u128>(),
279        }
280    }
281}
282
283#[derive(Debug, Clone, Copy, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
284#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
285pub enum FixedPointDisplay {
286    Decimals(u8),
287    FromSiblingField {
288        field_index: usize,
289        byte_offset: usize,
290    },
291    /// Like [`FixedPointDisplay::FromSiblingField`], but if the sibling field's 32 bytes equal
292    /// `override_match`, `override_decimals` is used instead of the byte at `byte_offset`. Intended
293    /// only for our fixed 32-byte token-id override and intentionally supports 32-byte sibling
294    /// fields only; not a general-purpose primitive.
295    FromSiblingFieldWithOverride {
296        field_index: usize,
297        byte_offset: usize,
298        override_match: [u8; 32],
299        override_decimals: u8,
300    },
301}
302
303#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, BorshSerialize, BorshDeserialize)]
304#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
305pub enum IntegerDisplay {
306    Hex,
307    #[default]
308    Decimal,
309    FixedPoint(FixedPointDisplay),
310}
311
312pub trait IntegerDisplayable {
313    fn integer_type() -> IntegerType;
314
315    fn with_display(display: IntegerDisplay) -> Link {
316        Link::Immediate(Primitive::Integer(Self::integer_type(), display))
317    }
318}
319
320macro_rules! integer_displayable {
321    ($t:ident) => {
322        impl IntegerDisplayable for $t {
323            fn integer_type() -> IntegerType {
324                IntegerType::$t
325            }
326        }
327    };
328}
329macro_for_ints!(integer_displayable);
330
331pub trait ByteDisplayable {
332    fn with_display(display: ByteDisplay) -> Link {
333        Link::Immediate(Primitive::ByteVec { display })
334    }
335}
336
337// Blanket impl that delegates to the Output type's ByteDisplayable impl
338impl<T: OverrideSchema> ByteDisplayable for T
339where
340    T::Output: ByteDisplayable,
341{
342    fn with_display(display: ByteDisplay) -> Link {
343        T::Output::with_display(display)
344    }
345}
346
347impl ByteDisplayable for Vec<u8> {
348    fn with_display(display: ByteDisplay) -> Link {
349        Link::Immediate(Primitive::ByteVec { display })
350    }
351}
352
353impl<const N: usize> ByteDisplayable for [u8; N] {
354    fn with_display(display: ByteDisplay) -> Link {
355        Link::Immediate(Primitive::ByteArray { len: N, display })
356    }
357}
358
359#[derive(Debug, Clone, PartialEq, Eq, Default, BorshSerialize, BorshDeserialize)]
360#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
361pub struct ContainerSerdeMetadata {
362    pub name: String,
363    pub fields_or_variants: Vec<FieldOrVariantSerdeMetadata>,
364}
365
366#[derive(Debug, Clone, PartialEq, Eq, Default, BorshSerialize, BorshDeserialize)]
367#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
368pub struct FieldOrVariantSerdeMetadata {
369    pub name: String,
370}