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            _ => Vec::new(),
179        }
180    }
181}
182
183/// An enum variant can contain...
184/// - A (possibly anonymous) struct
185/// - Another Enum
186#[derive(Clone, Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
187#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
188pub struct EnumVariant<L: LinkingScheme> {
189    pub name: String,
190    pub discriminant: u8,
191    pub template: Option<String>,
192    pub value: Option<L::TypeLink>,
193}
194
195#[derive(Clone, Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
196#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
197pub struct Enum<L: LinkingScheme> {
198    pub type_name: String,
199    pub variants: Vec<EnumVariant<L>>,
200    /// Whether this enum is "hide_tag"ged, meaning that the variant tags shouldn't be displayed.
201    pub hide_tag: bool,
202}
203
204#[derive(Clone, Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
205#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
206pub struct Struct<L: LinkingScheme> {
207    pub type_name: String,
208    pub template: Option<String>,
209    pub peekable: bool,
210    pub fields: Vec<NamedField<L>>,
211}
212
213#[derive(Clone, Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
214#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
215pub struct Tuple<L: LinkingScheme> {
216    pub template: Option<String>,
217    pub peekable: bool,
218    pub fields: Vec<UnnamedField<L>>,
219}
220
221#[derive(Clone, Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
222#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
223pub struct NamedField<L: LinkingScheme> {
224    pub display_name: String,
225    pub silent: bool,
226    pub value: L::TypeLink,
227    pub doc: String,
228}
229
230#[derive(Clone, Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
231#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
232pub struct UnnamedField<L: LinkingScheme> {
233    pub value: L::TypeLink,
234    pub silent: bool,
235    pub doc: String,
236}
237
238#[derive(Debug, Clone, Copy, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
239#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
240#[allow(non_camel_case_types)]
241pub enum IntegerType {
242    i8,
243    i16,
244    i32,
245    i64,
246    i128,
247    u8,
248    u16,
249    u32,
250    u64,
251    u128,
252}
253
254impl IntegerType {
255    pub fn size(&self) -> usize {
256        match self {
257            IntegerType::i8 => core::mem::size_of::<i8>(),
258            IntegerType::i16 => core::mem::size_of::<i16>(),
259            IntegerType::i32 => core::mem::size_of::<i32>(),
260            IntegerType::i64 => core::mem::size_of::<i64>(),
261            IntegerType::i128 => core::mem::size_of::<i128>(),
262            IntegerType::u8 => core::mem::size_of::<u8>(),
263            IntegerType::u16 => core::mem::size_of::<u16>(),
264            IntegerType::u32 => core::mem::size_of::<u32>(),
265            IntegerType::u64 => core::mem::size_of::<u64>(),
266            IntegerType::u128 => core::mem::size_of::<u128>(),
267        }
268    }
269}
270
271#[derive(Debug, Clone, Copy, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
272#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
273pub enum FixedPointDisplay {
274    Decimals(u8),
275    FromSiblingField {
276        field_index: usize,
277        byte_offset: usize,
278    },
279}
280
281#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, BorshSerialize, BorshDeserialize)]
282#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
283pub enum IntegerDisplay {
284    Hex,
285    #[default]
286    Decimal,
287    FixedPoint(FixedPointDisplay),
288}
289
290pub trait IntegerDisplayable {
291    fn integer_type() -> IntegerType;
292
293    fn with_display(display: IntegerDisplay) -> Link {
294        Link::Immediate(Primitive::Integer(Self::integer_type(), display))
295    }
296}
297
298macro_rules! integer_displayable {
299    ($t:ident) => {
300        impl IntegerDisplayable for $t {
301            fn integer_type() -> IntegerType {
302                IntegerType::$t
303            }
304        }
305    };
306}
307macro_for_ints!(integer_displayable);
308
309pub trait ByteDisplayable {
310    fn with_display(display: ByteDisplay) -> Link {
311        Link::Immediate(Primitive::ByteVec { display })
312    }
313}
314
315// Blanket impl that delegates to the Output type's ByteDisplayable impl
316impl<T: OverrideSchema> ByteDisplayable for T
317where
318    T::Output: ByteDisplayable,
319{
320    fn with_display(display: ByteDisplay) -> Link {
321        T::Output::with_display(display)
322    }
323}
324
325impl ByteDisplayable for Vec<u8> {
326    fn with_display(display: ByteDisplay) -> Link {
327        Link::Immediate(Primitive::ByteVec { display })
328    }
329}
330
331impl<const N: usize> ByteDisplayable for [u8; N] {
332    fn with_display(display: ByteDisplay) -> Link {
333        Link::Immediate(Primitive::ByteArray { len: N, display })
334    }
335}
336
337#[derive(Debug, Clone, PartialEq, Eq, Default, BorshSerialize, BorshDeserialize)]
338#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
339pub struct ContainerSerdeMetadata {
340    pub name: String,
341    pub fields_or_variants: Vec<FieldOrVariantSerdeMetadata>,
342}
343
344#[derive(Debug, Clone, PartialEq, Eq, Default, BorshSerialize, BorshDeserialize)]
345#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
346pub struct FieldOrVariantSerdeMetadata {
347    pub name: String,
348}