borsh/
schema.rs

1//! Since Borsh is not a self-descriptive format we have a way to describe types serialized with Borsh so that
2//! we can deserialize serialized blobs without having Rust types available. Additionally, this can be used to
3//! serialize content provided in a different format, e.g. JSON object `{"user": "alice", "message": "Message"}`
4//! can be serialized by JS code into Borsh format such that it can be deserialized into `struct UserMessage {user: String, message: String}`
5//! on Rust side.
6//!
7//! The important components are: `BorshSchema` trait, `Definition` and `Declaration` types, and `BorshSchemaContainer` struct.
8//! * `BorshSchema` trait allows any type that implements it to be self-descriptive, i.e. generate it's own schema;
9//! * `Declaration` is used to describe the type identifier, e.g. `HashMap<u64, String>`;
10//! * `Definition` is used to describe the structure of the type;
11//! * `BorshSchemaContainer` is used to store all declarations and defintions that are needed to work with a single type.
12
13#![allow(dead_code)] // Unclear why rust check complains on fields of `Definition` variants.
14use crate as borsh; // For `#[derive(BorshSerialize, BorshDeserialize)]`.
15use crate::maybestd::{
16    boxed::Box,
17    collections::{hash_map::Entry, HashMap},
18    format,
19    string::{String, ToString},
20    vec,
21    vec::Vec,
22};
23use crate::{BorshDeserialize, BorshSchema as BorshSchemaMacro, BorshSerialize};
24
25/// The type that we use to represent the declaration of the Borsh type.
26pub type Declaration = String;
27/// The type that we use for the name of the variant.
28pub type VariantName = String;
29/// The name of the field in the struct (can be used to convert JSON to Borsh using the schema).
30pub type FieldName = String;
31/// The type that we use to represent the definition of the Borsh type.
32#[derive(PartialEq, Debug, BorshSerialize, BorshDeserialize, BorshSchemaMacro)]
33pub enum Definition {
34    /// A fixed-size array with the length known at the compile time and the same-type elements.
35    Array { length: u32, elements: Declaration },
36    /// A sequence of elements of length known at the run time and the same-type elements.
37    Sequence { elements: Declaration },
38    /// A fixed-size tuple with the length known at the compile time and the elements of different
39    /// types.
40    Tuple { elements: Vec<Declaration> },
41    /// A tagged union, a.k.a enum. Tagged-unions have variants with associated structures.
42    Enum {
43        variants: Vec<(VariantName, Declaration)>,
44    },
45    /// A structure, structurally similar to a tuple.
46    Struct { fields: Fields },
47}
48
49/// The collection representing the fields of a struct.
50#[derive(PartialEq, Debug, BorshSerialize, BorshDeserialize, BorshSchemaMacro)]
51pub enum Fields {
52    /// The struct with named fields.
53    NamedFields(Vec<(FieldName, Declaration)>),
54    /// The struct with unnamed fields, structurally identical to a tuple.
55    UnnamedFields(Vec<Declaration>),
56    /// The struct with no fields.
57    Empty,
58}
59
60/// All schema information needed to deserialize a single type.
61#[derive(PartialEq, Debug, BorshSerialize, BorshDeserialize, BorshSchemaMacro)]
62pub struct BorshSchemaContainer {
63    /// Declaration of the type.
64    pub declaration: Declaration,
65    /// All definitions needed to deserialize the given type.
66    pub definitions: HashMap<Declaration, Definition>,
67}
68
69/// The declaration and the definition of the type that can be used to (de)serialize Borsh without
70/// the Rust type that produced it.
71pub trait BorshSchema {
72    /// Recursively, using DFS, add type definitions required for this type. For primitive types
73    /// this is an empty map. Type definition explains how to serialize/deserialize a type.
74    fn add_definitions_recursively(definitions: &mut HashMap<Declaration, Definition>);
75
76    /// Helper method to add a single type definition to the map.
77    fn add_definition(
78        declaration: Declaration,
79        definition: Definition,
80        definitions: &mut HashMap<Declaration, Definition>,
81    ) {
82        match definitions.entry(declaration) {
83            Entry::Occupied(occ) => {
84                let existing_def = occ.get();
85                assert_eq!(existing_def, &definition, "Redefining type schema for the same type name. Types with the same names are not supported.");
86            }
87            Entry::Vacant(vac) => {
88                vac.insert(definition);
89            }
90        }
91    }
92    /// Get the name of the type without brackets.
93    fn declaration() -> Declaration;
94
95    fn schema_container() -> BorshSchemaContainer {
96        let mut definitions = HashMap::new();
97        Self::add_definitions_recursively(&mut definitions);
98        BorshSchemaContainer {
99            declaration: Self::declaration(),
100            definitions,
101        }
102    }
103}
104
105impl<T> BorshSchema for Box<T>
106where
107    T: BorshSchema,
108{
109    fn add_definitions_recursively(definitions: &mut HashMap<Declaration, Definition>) {
110        T::add_definitions_recursively(definitions);
111    }
112
113    fn declaration() -> Declaration {
114        T::declaration()
115    }
116}
117
118impl BorshSchema for () {
119    fn add_definitions_recursively(_definitions: &mut HashMap<Declaration, Definition>) {}
120
121    fn declaration() -> Declaration {
122        "nil".to_string()
123    }
124}
125
126macro_rules! impl_for_renamed_primitives {
127    ($($type: ident : $name: ident)+) => {
128    $(
129        impl BorshSchema for $type {
130            fn add_definitions_recursively(_definitions: &mut HashMap<Declaration, Definition>) {}
131            fn declaration() -> Declaration {
132                stringify!($name).to_string()
133            }
134        }
135    )+
136    };
137}
138
139macro_rules! impl_for_primitives {
140    ($($type: ident)+) => {
141    impl_for_renamed_primitives!{$($type : $type)+}
142    };
143}
144
145impl_for_primitives!(bool char f32 f64 i8 i16 i32 i64 i128 u8 u16 u32 u64 u128);
146impl_for_renamed_primitives!(String: string);
147
148macro_rules! impl_arrays {
149    ($($len:expr)+) => {
150    $(
151    impl<T> BorshSchema for [T; $len]
152    where
153        T: BorshSchema,
154    {
155        fn add_definitions_recursively(definitions: &mut HashMap<Declaration, Definition>) {
156            let definition = Definition::Array { length: $len, elements: T::declaration() };
157            Self::add_definition(Self::declaration(), definition, definitions);
158            T::add_definitions_recursively(definitions);
159        }
160        fn declaration() -> Declaration {
161            format!(r#"Array<{}, {}>"#, T::declaration(), $len)
162        }
163    }
164    )+
165    };
166}
167
168impl_arrays!(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 32 64 65);
169
170impl<T> BorshSchema for Option<T>
171where
172    T: BorshSchema,
173{
174    fn add_definitions_recursively(definitions: &mut HashMap<Declaration, Definition>) {
175        let definition = Definition::Enum {
176            variants: vec![
177                ("None".to_string(), <()>::declaration()),
178                ("Some".to_string(), T::declaration()),
179            ],
180        };
181        Self::add_definition(Self::declaration(), definition, definitions);
182        T::add_definitions_recursively(definitions);
183    }
184
185    fn declaration() -> Declaration {
186        format!(r#"Option<{}>"#, T::declaration())
187    }
188}
189
190impl<T, E> BorshSchema for core::result::Result<T, E>
191where
192    T: BorshSchema,
193    E: BorshSchema,
194{
195    fn add_definitions_recursively(definitions: &mut HashMap<Declaration, Definition>) {
196        let definition = Definition::Enum {
197            variants: vec![
198                ("Ok".to_string(), T::declaration()),
199                ("Err".to_string(), E::declaration()),
200            ],
201        };
202        Self::add_definition(Self::declaration(), definition, definitions);
203        T::add_definitions_recursively(definitions);
204    }
205
206    fn declaration() -> Declaration {
207        format!(r#"Result<{}, {}>"#, T::declaration(), E::declaration())
208    }
209}
210
211impl<T> BorshSchema for Vec<T>
212where
213    T: BorshSchema,
214{
215    fn add_definitions_recursively(definitions: &mut HashMap<Declaration, Definition>) {
216        let definition = Definition::Sequence {
217            elements: T::declaration(),
218        };
219        Self::add_definition(Self::declaration(), definition, definitions);
220        T::add_definitions_recursively(definitions);
221    }
222
223    fn declaration() -> Declaration {
224        format!(r#"Vec<{}>"#, T::declaration())
225    }
226}
227
228impl<K, V> BorshSchema for HashMap<K, V>
229where
230    K: BorshSchema,
231    V: BorshSchema,
232{
233    fn add_definitions_recursively(definitions: &mut HashMap<Declaration, Definition>) {
234        let definition = Definition::Sequence {
235            elements: <(K, V)>::declaration(),
236        };
237        Self::add_definition(Self::declaration(), definition, definitions);
238        <(K, V)>::add_definitions_recursively(definitions);
239    }
240
241    fn declaration() -> Declaration {
242        format!(r#"HashMap<{}, {}>"#, K::declaration(), V::declaration())
243    }
244}
245
246macro_rules! impl_tuple {
247    ($($name:ident),+) => {
248    impl<$($name),+> BorshSchema for ($($name),+)
249    where
250        $($name: BorshSchema),+
251    {
252        fn add_definitions_recursively(definitions: &mut HashMap<Declaration, Definition>) {
253            let mut elements = vec![];
254            $(
255                elements.push($name::declaration());
256            )+
257
258            let definition = Definition::Tuple { elements };
259            Self::add_definition(Self::declaration(), definition, definitions);
260            $(
261                $name::add_definitions_recursively(definitions);
262            )+
263        }
264
265        fn declaration() -> Declaration {
266            let params = vec![$($name::declaration()),+];
267            format!(r#"Tuple<{}>"#, params.join(", "))
268        }
269    }
270    };
271}
272
273impl_tuple!(T0, T1);
274impl_tuple!(T0, T1, T2);
275impl_tuple!(T0, T1, T2, T3);
276impl_tuple!(T0, T1, T2, T3, T4);
277impl_tuple!(T0, T1, T2, T3, T4, T5);
278impl_tuple!(T0, T1, T2, T3, T4, T5, T6);
279impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7);
280impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8);
281impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);
282impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
283impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
284impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);
285impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13);
286impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14);
287impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15);
288impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16);
289impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17);
290impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18);
291impl_tuple!(
292    T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19
293);
294impl_tuple!(
295    T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20
296);
297
298#[cfg(test)]
299mod tests {
300    use super::*;
301    use crate::maybestd::collections::HashMap;
302
303    macro_rules! map(
304    () => { HashMap::new() };
305    { $($key:expr => $value:expr),+ } => {
306        {
307            let mut m = HashMap::new();
308            $(
309                m.insert($key.to_string(), $value);
310            )+
311            m
312        }
313     };
314    );
315
316    #[test]
317    fn simple_option() {
318        let actual_name = Option::<u64>::declaration();
319        let mut actual_defs = map!();
320        Option::<u64>::add_definitions_recursively(&mut actual_defs);
321        assert_eq!("Option<u64>", actual_name);
322        assert_eq!(
323            map! {"Option<u64>" =>
324            Definition::Enum{ variants: vec![
325                ("None".to_string(), "nil".to_string()),
326                ("Some".to_string(), "u64".to_string()),
327            ]}
328            },
329            actual_defs
330        );
331    }
332
333    #[test]
334    fn nested_option() {
335        let actual_name = Option::<Option<u64>>::declaration();
336        let mut actual_defs = map!();
337        Option::<Option<u64>>::add_definitions_recursively(&mut actual_defs);
338        assert_eq!("Option<Option<u64>>", actual_name);
339        assert_eq!(
340            map! {
341            "Option<u64>" =>
342                Definition::Enum {variants: vec![
343                ("None".to_string(), "nil".to_string()),
344                ("Some".to_string(), "u64".to_string()),
345                ]},
346            "Option<Option<u64>>" =>
347                Definition::Enum {variants: vec![
348                ("None".to_string(), "nil".to_string()),
349                ("Some".to_string(), "Option<u64>".to_string()),
350                ]}
351            },
352            actual_defs
353        );
354    }
355
356    #[test]
357    fn simple_vec() {
358        let actual_name = Vec::<u64>::declaration();
359        let mut actual_defs = map!();
360        Vec::<u64>::add_definitions_recursively(&mut actual_defs);
361        assert_eq!("Vec<u64>", actual_name);
362        assert_eq!(
363            map! {
364            "Vec<u64>" => Definition::Sequence { elements: "u64".to_string() }
365            },
366            actual_defs
367        );
368    }
369
370    #[test]
371    fn nested_vec() {
372        let actual_name = Vec::<Vec<u64>>::declaration();
373        let mut actual_defs = map!();
374        Vec::<Vec<u64>>::add_definitions_recursively(&mut actual_defs);
375        assert_eq!("Vec<Vec<u64>>", actual_name);
376        assert_eq!(
377            map! {
378            "Vec<u64>" => Definition::Sequence { elements: "u64".to_string() },
379            "Vec<Vec<u64>>" => Definition::Sequence { elements: "Vec<u64>".to_string() }
380            },
381            actual_defs
382        );
383    }
384
385    #[test]
386    fn simple_tuple() {
387        let actual_name = <(u64, String)>::declaration();
388        let mut actual_defs = map!();
389        <(u64, String)>::add_definitions_recursively(&mut actual_defs);
390        assert_eq!("Tuple<u64, string>", actual_name);
391        assert_eq!(
392            map! {
393                "Tuple<u64, string>" => Definition::Tuple { elements: vec![ "u64".to_string(), "string".to_string()]}
394            },
395            actual_defs
396        );
397    }
398
399    #[test]
400    fn nested_tuple() {
401        let actual_name = <(u64, (u8, bool), String)>::declaration();
402        let mut actual_defs = map!();
403        <(u64, (u8, bool), String)>::add_definitions_recursively(&mut actual_defs);
404        assert_eq!("Tuple<u64, Tuple<u8, bool>, string>", actual_name);
405        assert_eq!(
406            map! {
407                "Tuple<u64, Tuple<u8, bool>, string>" => Definition::Tuple { elements: vec![
408                    "u64".to_string(),
409                    "Tuple<u8, bool>".to_string(),
410                    "string".to_string(),
411                ]},
412                "Tuple<u8, bool>" => Definition::Tuple { elements: vec![ "u8".to_string(), "bool".to_string()]}
413            },
414            actual_defs
415        );
416    }
417
418    #[test]
419    fn simple_map() {
420        let actual_name = HashMap::<u64, String>::declaration();
421        let mut actual_defs = map!();
422        HashMap::<u64, String>::add_definitions_recursively(&mut actual_defs);
423        assert_eq!("HashMap<u64, string>", actual_name);
424        assert_eq!(
425            map! {
426                "HashMap<u64, string>" => Definition::Sequence { elements: "Tuple<u64, string>".to_string()} ,
427                "Tuple<u64, string>" => Definition::Tuple { elements: vec![ "u64".to_string(), "string".to_string()]}
428            },
429            actual_defs
430        );
431    }
432
433    #[test]
434    fn simple_array() {
435        let actual_name = <[u64; 32]>::declaration();
436        let mut actual_defs = map!();
437        <[u64; 32]>::add_definitions_recursively(&mut actual_defs);
438        assert_eq!("Array<u64, 32>", actual_name);
439        assert_eq!(
440            map! {"Array<u64, 32>" => Definition::Array { length: 32, elements: "u64".to_string()}},
441            actual_defs
442        );
443    }
444
445    #[test]
446    fn nested_array() {
447        let actual_name = <[[[u64; 9]; 10]; 32]>::declaration();
448        let mut actual_defs = map!();
449        <[[[u64; 9]; 10]; 32]>::add_definitions_recursively(&mut actual_defs);
450        assert_eq!("Array<Array<Array<u64, 9>, 10>, 32>", actual_name);
451        assert_eq!(
452            map! {
453            "Array<u64, 9>" =>
454                Definition::Array { length: 9, elements: "u64".to_string() },
455            "Array<Array<u64, 9>, 10>" =>
456                Definition::Array { length: 10, elements: "Array<u64, 9>".to_string() },
457            "Array<Array<Array<u64, 9>, 10>, 32>" =>
458                Definition::Array { length: 32, elements: "Array<Array<u64, 9>, 10>".to_string() }
459            },
460            actual_defs
461        );
462    }
463}