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    /// The name of the tuple struct (e.g. newtype) this type was derived from, if any. `None` for
229    /// plain anonymous tuples and for the virtual tuples representing enum variant contents.
230    ///
231    /// Purely informational: visitors deliberately ignore it to keep display output, JSON
232    /// parsing and EIP-712 encodings identical to those of an anonymous tuple.
233    // `serde(default)` keeps schema JSONs generated before this field existed parseable.
234    #[cfg_attr(feature = "serde", serde(default))]
235    pub type_name: Option<String>,
236    pub template: Option<String>,
237    pub peekable: bool,
238    pub fields: Vec<UnnamedField<L>>,
239}
240
241#[derive(Clone, Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
242#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
243pub struct NamedField<L: LinkingScheme> {
244    pub display_name: String,
245    pub silent: bool,
246    pub value: L::TypeLink,
247    pub doc: String,
248}
249
250#[derive(Clone, Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
251#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
252pub struct UnnamedField<L: LinkingScheme> {
253    pub value: L::TypeLink,
254    pub silent: bool,
255    pub doc: String,
256}
257
258#[derive(Debug, Clone, Copy, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
259#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
260#[allow(non_camel_case_types)]
261pub enum IntegerType {
262    i8,
263    i16,
264    i32,
265    i64,
266    i128,
267    u8,
268    u16,
269    u32,
270    u64,
271    u128,
272}
273
274impl IntegerType {
275    pub fn size(&self) -> usize {
276        match self {
277            IntegerType::i8 => core::mem::size_of::<i8>(),
278            IntegerType::i16 => core::mem::size_of::<i16>(),
279            IntegerType::i32 => core::mem::size_of::<i32>(),
280            IntegerType::i64 => core::mem::size_of::<i64>(),
281            IntegerType::i128 => core::mem::size_of::<i128>(),
282            IntegerType::u8 => core::mem::size_of::<u8>(),
283            IntegerType::u16 => core::mem::size_of::<u16>(),
284            IntegerType::u32 => core::mem::size_of::<u32>(),
285            IntegerType::u64 => core::mem::size_of::<u64>(),
286            IntegerType::u128 => core::mem::size_of::<u128>(),
287        }
288    }
289}
290
291#[derive(Debug, Clone, Copy, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
292#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
293pub enum FixedPointDisplay {
294    Decimals(u8),
295    FromSiblingField {
296        field_index: usize,
297        byte_offset: usize,
298    },
299    /// Like [`FixedPointDisplay::FromSiblingField`], but if the sibling field's 32 bytes equal
300    /// `override_match`, `override_decimals` is used instead of the byte at `byte_offset`. Intended
301    /// only for our fixed 32-byte token-id override and intentionally supports 32-byte sibling
302    /// fields only; not a general-purpose primitive.
303    FromSiblingFieldWithOverride {
304        field_index: usize,
305        byte_offset: usize,
306        override_match: [u8; 32],
307        override_decimals: u8,
308    },
309}
310
311#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, BorshSerialize, BorshDeserialize)]
312#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
313pub enum IntegerDisplay {
314    Hex,
315    #[default]
316    Decimal,
317    FixedPoint(FixedPointDisplay),
318}
319
320pub trait IntegerDisplayable {
321    fn integer_type() -> IntegerType;
322
323    fn with_display(display: IntegerDisplay) -> Link {
324        Link::Immediate(Primitive::Integer(Self::integer_type(), display))
325    }
326}
327
328macro_rules! integer_displayable {
329    ($t:ident) => {
330        impl IntegerDisplayable for $t {
331            fn integer_type() -> IntegerType {
332                IntegerType::$t
333            }
334        }
335    };
336}
337macro_for_ints!(integer_displayable);
338
339pub trait ByteDisplayable {
340    fn with_display(display: ByteDisplay) -> Link {
341        Link::Immediate(Primitive::ByteVec { display })
342    }
343}
344
345// Blanket impl that delegates to the Output type's ByteDisplayable impl
346impl<T: OverrideSchema> ByteDisplayable for T
347where
348    T::Output: ByteDisplayable,
349{
350    fn with_display(display: ByteDisplay) -> Link {
351        T::Output::with_display(display)
352    }
353}
354
355impl ByteDisplayable for Vec<u8> {
356    fn with_display(display: ByteDisplay) -> Link {
357        Link::Immediate(Primitive::ByteVec { display })
358    }
359}
360
361impl<const N: usize> ByteDisplayable for [u8; N] {
362    fn with_display(display: ByteDisplay) -> Link {
363        Link::Immediate(Primitive::ByteArray { len: N, display })
364    }
365}
366
367#[derive(Debug, Clone, PartialEq, Eq, Default, BorshSerialize, BorshDeserialize)]
368#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
369pub struct ContainerSerdeMetadata {
370    pub name: String,
371    pub fields_or_variants: Vec<FieldOrVariantSerdeMetadata>,
372}
373
374#[derive(Debug, Clone, PartialEq, Eq, Default, BorshSerialize, BorshDeserialize)]
375#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
376pub struct FieldOrVariantSerdeMetadata {
377    pub name: String,
378}