borsh/
schema.rs

1//!
2//! Since Borsh is not a self-descriptive format we have a way to describe types serialized with Borsh so that
3//! we can deserialize serialized blobs without having Rust types available. Additionally, this can be used to
4//! serialize content provided in a different format, e.g. JSON object `{"user": "alice", "message": "Message"}`
5//! can be serialized by JS code into Borsh format such that it can be deserialized into `struct UserMessage {user: String, message: String}`
6//! on Rust side.
7//!
8//! The important components are: `BorshSchema` trait, `Definition` and `Declaration` types, and `BorshSchemaContainer` struct.
9//! * `BorshSchema` trait allows any type that implements it to be self-descriptive, i.e. generate it's own schema;
10//! * `Declaration` is used to describe the type identifier, e.g. `HashMap<u64, String>`;
11//! * `Definition` is used to describe the structure of the type;
12//! * `BorshSchemaContainer` is used to store all declarations and definitions that are needed to work with a single type.
13
14#![allow(dead_code)] // Unclear why rust check complains on fields of `Definition` variants.
15use crate as borsh; // For `#[derive(BorshSerialize, BorshDeserialize)]`.
16use crate::__private::maybestd::{
17    borrow,
18    boxed::Box,
19    collections::{btree_map::Entry, BTreeMap, BTreeSet, LinkedList, VecDeque},
20    format,
21    string::{String, ToString},
22    vec,
23    vec::Vec,
24};
25use crate::io::{Read, Result as IOResult, Write};
26use crate::{BorshDeserialize, BorshSchema as BorshSchemaMacro, BorshSerialize};
27use core::borrow::Borrow;
28use core::cmp::Ord;
29use core::marker::PhantomData;
30
31mod container_ext;
32
33pub use container_ext::{SchemaContainerValidateError, SchemaMaxSerializedSizeError};
34
35/// The type that we use to represent the declaration of the Borsh type.
36pub type Declaration = String;
37/// The type that we use for the name of the variant.
38pub type VariantName = String;
39/// The type that we use for value of discriminant.
40pub type DiscriminantValue = i64;
41/// The name of the field in the struct (can be used to convert JSON to Borsh using the schema).
42pub type FieldName = String;
43/// The type that we use to represent the definition of the Borsh type.
44///
45/// Description of data encoding on the wire.
46#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize, BorshSchemaMacro)]
47pub enum Definition {
48    /// A fixed-size type, which is considered undivisible
49    Primitive(u8),
50
51    /// A sequence of homogeneous elements.
52    ///
53    /// If `length_width` is non-zero, the sequence is tagged, i.e. prefixed by
54    /// the number of elements in the sequence.  In that case, the length is
55    /// encoded as a `length_width`-byte wide little-endian unsigned integer.
56    ///
57    /// If `length_width` is zero, the sequence is untagged.  In that case, if
58    /// `length_range` contains a single number, the sequence is fixed-sized
59    /// with the range determining number of elements.  Otherwise, knowledge of
60    /// the type is necessary to be able to decode the number of elements.
61    ///
62    /// Prototypical examples of the use of this definitions are:
63    /// * `[T; N]` → `length_width: 0, length_range: N..=N, elements: "T"` and
64    /// * `Vec<T>` → `length_width: 4, length_range: 0..=u32::MAX,
65    ///   elements: "T"`.
66    ///
67    /// With `length_width` and `length_range` other custom encoding formats can
68    /// also be expressed.  For example:
69    /// * `BoundedVec<LO, HI, T>` → `length_width: 4, length_range: LO..=HI`;
70    /// * `PascalString` → `length_width: 1, length_range: 0..=255`;
71    /// * `Ipv4Packet` → `length_width: 0, length_range: 20..=65536` or
72    /// * `VarInt<u32>` → `length_width: 0, length_range: 1..=5`.
73    Sequence {
74        /// How many bytes does the length tag occupy.
75        ///
76        /// Zero if this is fixed-length array or the length must be determined
77        /// by means not specified in the schema.  The schema is invalid if the
78        /// value is greater than eight.
79        length_width: u8,
80
81        /// Bounds on the possible lengths of the sequence.
82        ///
83        /// Note: The schema is invalid if the range is empty or `length_width`
84        /// is non-zero and either bound of the range cannot be represented as
85        /// `length_width`-byte-wide unsigned integer.
86        length_range: core::ops::RangeInclusive<u64>,
87
88        /// Type of each element of the sequence.
89        elements: Declaration,
90    },
91
92    /// A fixed-size tuple with the length known at the compile time and the elements of different
93    /// types.
94    Tuple { elements: Vec<Declaration> },
95
96    /// A possibly tagged union, a.k.a enum.
97    ///
98    /// Tagged unions are prefixed by a tag identifying encoded variant followed
99    /// by encoding of that variant.  The tag is `tag_width`-byte wide
100    /// little-endian number.
101    ///
102    /// Untagged unions don’t have a separate tag which means that knowledge of
103    /// the type is necessary to fully analyse the binary.  Variants may still
104    /// be used to list possible values or determine the longest possible
105    /// encoding.
106    Enum {
107        /// Width in bytes of the discriminant tag.
108        ///
109        /// Zero indicates this is an untagged union.  In standard borsh
110        /// encoding this is one.  Custom encoding formats may use larger width
111        /// if they need to encode more than 256 variants.  The schema is
112        /// invalid if the value is greater than eight.
113        tag_width: u8,
114
115        /// Possible variants of the enumeration.
116        /// `VariantName` is metadata, not present in a type's serialized representation.
117        variants: Vec<(DiscriminantValue, VariantName, Declaration)>,
118    },
119
120    /// A structure, structurally similar to a tuple.
121    Struct { fields: Fields },
122}
123
124impl Definition {
125    /// Array length isn't present in payload, it's determined by type of data
126    /// serialized.
127    pub const ARRAY_LENGTH_WIDTH: u8 = 0;
128
129    /// Convenience constant representing the length width of a standard borsh
130    /// sequence.
131    ///
132    /// Can be used for `Definition::Sequence::length_width`.
133    pub const DEFAULT_LENGTH_WIDTH: u8 = 4;
134
135    /// Convenience constant representing the length range of a standard borsh
136    /// sequence.
137    ///
138    /// It equals `0..=u32::MAX`.  Can be used with
139    /// `Definition::Sequence::length_range`.
140    pub const DEFAULT_LENGTH_RANGE: core::ops::RangeInclusive<u64> = 0..=(u32::MAX as u64);
141}
142
143/// The collection representing the fields of a struct.
144#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize, BorshSchemaMacro)]
145pub enum Fields {
146    /// The struct with named fields, structurally identical to a tuple.
147    /// `FieldName` is metadata, not present in a type's serialized representation.
148    NamedFields(Vec<(FieldName, Declaration)>),
149    /// The struct with unnamed fields, structurally identical to a tuple.
150    UnnamedFields(Vec<Declaration>),
151    /// The struct with no fields, structurally identical to an empty tuple.
152    Empty,
153}
154
155/// All schema information needed to deserialize a single type.
156#[derive(Clone, PartialEq, Eq, Debug)]
157pub struct BorshSchemaContainer {
158    /// Declaration of the type.
159    declaration: Declaration,
160    /// All definitions needed to deserialize the given type.
161    definitions: BTreeMap<Declaration, Definition>,
162}
163
164impl BorshSchemaContainer {
165    pub fn new(declaration: Declaration, definitions: BTreeMap<Declaration, Definition>) -> Self {
166        Self {
167            declaration,
168            definitions,
169        }
170    }
171
172    /// generate [BorshSchemaContainer] for type `T`
173    pub fn for_type<T: BorshSchema + ?Sized>() -> Self {
174        let mut definitions = Default::default();
175        T::add_definitions_recursively(&mut definitions);
176        Self::new(T::declaration(), definitions)
177    }
178
179    pub fn declaration(&self) -> &Declaration {
180        &self.declaration
181    }
182    pub fn definitions(&self) -> impl Iterator<Item = (&'_ Declaration, &'_ Definition)> {
183        self.definitions.iter()
184    }
185
186    pub fn get_definition<Q>(&self, declaration: &Q) -> Option<&Definition>
187    where
188        Declaration: Borrow<Q>,
189        Q: Ord + ?Sized,
190    {
191        self.definitions.get(declaration)
192    }
193
194    pub fn get_mut_definition<Q>(&mut self, declaration: &Q) -> Option<&mut Definition>
195    where
196        Declaration: Borrow<Q>,
197        Q: Ord + ?Sized,
198    {
199        self.definitions.get_mut(declaration)
200    }
201
202    pub fn insert_definition(
203        &mut self,
204        declaration: Declaration,
205        definition: Definition,
206    ) -> Option<Definition> {
207        self.definitions.insert(declaration, definition)
208    }
209    pub fn remove_definition<Q>(&mut self, declaration: &Q) -> Option<Definition>
210    where
211        Declaration: Borrow<Q>,
212        Q: Ord + ?Sized,
213    {
214        self.definitions.remove(declaration)
215    }
216}
217
218impl BorshSerialize for BorshSchemaContainer
219where
220    Declaration: BorshSerialize,
221    BTreeMap<Declaration, Definition>: BorshSerialize,
222{
223    fn serialize<W: Write>(&self, writer: &mut W) -> IOResult<()> {
224        let declaration = self.declaration();
225        let definitions: BTreeMap<&Declaration, &Definition> = self.definitions().collect();
226        BorshSerialize::serialize(declaration, writer)?;
227        BorshSerialize::serialize(&definitions, writer)?;
228        Ok(())
229    }
230}
231
232impl BorshDeserialize for BorshSchemaContainer
233where
234    Declaration: BorshDeserialize,
235    BTreeMap<Declaration, Definition>: BorshDeserialize,
236{
237    fn deserialize_reader<R: Read>(reader: &mut R) -> IOResult<Self> {
238        let declaration: Declaration = BorshDeserialize::deserialize_reader(reader)?;
239        let definitions: BTreeMap<Declaration, Definition> =
240            BorshDeserialize::deserialize_reader(reader)?;
241        Ok(Self::new(declaration, definitions))
242    }
243}
244
245/// Helper method to add a single type definition to the map.
246pub fn add_definition(
247    declaration: Declaration,
248    definition: Definition,
249    definitions: &mut BTreeMap<Declaration, Definition>,
250) {
251    match definitions.entry(declaration) {
252        Entry::Occupied(occ) => {
253            let existing_def = occ.get();
254            assert_eq!(
255                existing_def,
256                &definition,
257                "Redefining type schema for {}. Types with the same names are not supported.",
258                occ.key()
259            );
260        }
261        Entry::Vacant(vac) => {
262            vac.insert(definition);
263        }
264    }
265}
266
267/// The declaration and the definition of the type that can be used to (de)serialize Borsh without
268/// the Rust type that produced it.
269pub trait BorshSchema {
270    /// Recursively, using DFS, add type definitions required for this type.
271    /// Type definition partially explains how to serialize/deserialize a type.
272    fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>);
273
274    /// Get the name of the type without brackets.
275    fn declaration() -> Declaration;
276}
277
278impl BorshSchema for BorshSchemaContainer
279where
280    Declaration: BorshSchema,
281    BTreeMap<Declaration, Definition>: BorshSchema,
282{
283    fn declaration() -> Declaration {
284        "BorshSchemaContainer".to_string()
285    }
286    fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
287        let fields = Fields::NamedFields(<[_]>::into_vec(Box::new([
288            (
289                "declaration".to_string(),
290                <Declaration as BorshSchema>::declaration(),
291            ),
292            (
293                "definitions".to_string(),
294                <BTreeMap<Declaration, Definition> as BorshSchema>::declaration(),
295            ),
296        ])));
297        let definition = Definition::Struct { fields };
298        add_definition(
299            <Self as BorshSchema>::declaration(),
300            definition,
301            definitions,
302        );
303        <Declaration as BorshSchema>::add_definitions_recursively(definitions);
304        <BTreeMap<Declaration, Definition> as BorshSchema>::add_definitions_recursively(
305            definitions,
306        );
307    }
308}
309impl<T> BorshSchema for Box<T>
310where
311    T: BorshSchema + ?Sized,
312{
313    fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
314        T::add_definitions_recursively(definitions);
315    }
316
317    fn declaration() -> Declaration {
318        T::declaration()
319    }
320}
321
322impl<T> BorshSchema for core::cell::Cell<T>
323where
324    T: BorshSchema + Copy,
325{
326    fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
327        T::add_definitions_recursively(definitions);
328    }
329
330    fn declaration() -> Declaration {
331        T::declaration()
332    }
333}
334
335impl<T> BorshSchema for core::cell::RefCell<T>
336where
337    T: BorshSchema + Sized,
338{
339    fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
340        T::add_definitions_recursively(definitions);
341    }
342
343    fn declaration() -> Declaration {
344        T::declaration()
345    }
346}
347/// Module is available if borsh is built with `features = ["rc"]`.
348#[cfg(feature = "rc")]
349pub mod rc {
350    //!
351    //! Module defines [BorshSchema] implementation for
352    //! [alloc::rc::Rc](std::rc::Rc) and [alloc::sync::Arc](std::sync::Arc).
353    use crate::BorshSchema;
354
355    use super::{Declaration, Definition};
356    use crate::__private::maybestd::collections::BTreeMap;
357    use crate::__private::maybestd::{rc::Rc, sync::Arc};
358
359    impl<T> BorshSchema for Rc<T>
360    where
361        T: BorshSchema + ?Sized,
362    {
363        fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
364            T::add_definitions_recursively(definitions);
365        }
366
367        fn declaration() -> Declaration {
368            T::declaration()
369        }
370    }
371
372    impl<T> BorshSchema for Arc<T>
373    where
374        T: BorshSchema + ?Sized,
375    {
376        fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
377            T::add_definitions_recursively(definitions);
378        }
379
380        fn declaration() -> Declaration {
381            T::declaration()
382        }
383    }
384}
385
386impl<T> BorshSchema for borrow::Cow<'_, T>
387where
388    T: borrow::ToOwned + ?Sized,
389    T::Owned: BorshSchema,
390{
391    fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
392        <T::Owned as BorshSchema>::add_definitions_recursively(definitions);
393    }
394
395    fn declaration() -> Declaration {
396        <T::Owned as BorshSchema>::declaration()
397    }
398}
399
400macro_rules! impl_for_renamed_primitives {
401    ($($ty: ty : $name: ident => $size: expr);+) => {
402    $(
403        impl BorshSchema for $ty {
404            #[inline]
405            fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
406                let definition = Definition::Primitive($size);
407                add_definition(Self::declaration(), definition, definitions);
408            }
409            #[inline]
410            fn declaration() -> Declaration { stringify!($name).into() }
411        }
412    )+
413    };
414
415    ($($ty: ty : $name: expr, $size: expr);+) => {
416    $(
417        impl BorshSchema for $ty {
418            #[inline]
419            fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
420                let definition = Definition::Primitive($size);
421                add_definition(Self::declaration(), definition, definitions);
422            }
423            #[inline]
424            fn declaration() -> Declaration { $name.into() }
425        }
426    )+
427    };
428}
429
430macro_rules! impl_for_primitives {
431    ($($ty: ident => $size: expr);+) => {
432        impl_for_renamed_primitives!{$($ty : $ty => $size);+}
433    };
434}
435
436impl_for_primitives!(bool => 1; f32 => 4; f64 => 8; i8 => 1; i16 => 2; i32 => 4; i64 => 8; i128 => 16);
437impl_for_primitives!(u8 => 1; u16 => 2; u32 => 4; u64 => 8; u128 => 16);
438impl_for_renamed_primitives!(isize: i64 => 8);
439impl_for_renamed_primitives!(usize: u64 => 8);
440
441impl_for_renamed_primitives!(core::num::NonZeroI8: NonZeroI8 => 1);
442impl_for_renamed_primitives!(core::num::NonZeroI16: NonZeroI16 => 2);
443impl_for_renamed_primitives!(core::num::NonZeroI32: NonZeroI32 => 4);
444impl_for_renamed_primitives!(core::num::NonZeroI64: NonZeroI64 => 8);
445impl_for_renamed_primitives!(core::num::NonZeroI128: NonZeroI128 => 16);
446impl_for_renamed_primitives!(core::num::NonZeroU8: NonZeroU8 => 1);
447impl_for_renamed_primitives!(core::num::NonZeroU16: NonZeroU16 => 2);
448impl_for_renamed_primitives!(core::num::NonZeroU32: NonZeroU32 => 4);
449impl_for_renamed_primitives!(core::num::NonZeroU64: NonZeroU64 => 8);
450impl_for_renamed_primitives!(core::num::NonZeroU128: NonZeroU128 => 16);
451// see 12 lines above
452impl_for_renamed_primitives!(core::num::NonZeroUsize: NonZeroUsize => 8);
453
454impl_for_renamed_primitives!((): "()", 0);
455
456impl BorshSchema for String {
457    #[inline]
458    fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
459        str::add_definitions_recursively(definitions);
460    }
461    #[inline]
462    fn declaration() -> Declaration {
463        str::declaration()
464    }
465}
466
467impl BorshSchema for str {
468    #[inline]
469    fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
470        let definition = Definition::Sequence {
471            length_width: Definition::DEFAULT_LENGTH_WIDTH,
472            length_range: Definition::DEFAULT_LENGTH_RANGE,
473            elements: u8::declaration(),
474        };
475        add_definition(Self::declaration(), definition, definitions);
476        u8::add_definitions_recursively(definitions);
477    }
478    #[inline]
479    fn declaration() -> Declaration {
480        "String".into()
481    }
482}
483
484/// Module is available if borsh is built with `features = ["ascii"]`.
485#[cfg(feature = "ascii")]
486pub mod ascii {
487    //!
488    //! Module defines [BorshSchema] implementation for
489    //! some types from [ascii](::ascii) crate.
490    use crate::BorshSchema;
491
492    use super::{add_definition, Declaration, Definition};
493    use crate::__private::maybestd::collections::BTreeMap;
494
495    impl BorshSchema for ascii::AsciiString {
496        #[inline]
497        fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
498            ascii::AsciiStr::add_definitions_recursively(definitions);
499        }
500        #[inline]
501        fn declaration() -> Declaration {
502            ascii::AsciiStr::declaration()
503        }
504    }
505
506    impl BorshSchema for ascii::AsciiStr {
507        #[inline]
508        fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
509            let definition = Definition::Sequence {
510                length_width: Definition::DEFAULT_LENGTH_WIDTH,
511                length_range: Definition::DEFAULT_LENGTH_RANGE,
512                elements: ascii::AsciiChar::declaration(),
513            };
514            add_definition(Self::declaration(), definition, definitions);
515            ascii::AsciiChar::add_definitions_recursively(definitions);
516        }
517        #[inline]
518        fn declaration() -> Declaration {
519            "AsciiString".into()
520        }
521    }
522
523    impl BorshSchema for ascii::AsciiChar {
524        #[inline]
525        fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
526            add_definition(Self::declaration(), Definition::Primitive(1), definitions);
527        }
528        #[inline]
529        fn declaration() -> Declaration {
530            "AsciiChar".into()
531        }
532    }
533}
534
535impl BorshSchema for core::ops::RangeFull {
536    #[inline]
537    fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
538        let fields = Fields::Empty;
539        let def = Definition::Struct { fields };
540        add_definition(Self::declaration(), def, definitions);
541    }
542    #[inline]
543    fn declaration() -> Declaration {
544        "RangeFull".into()
545    }
546}
547
548macro_rules! impl_for_range {
549    ($type:ident, $($name:ident),*) => {
550        impl<T: BorshSchema> BorshSchema for core::ops::$type<T> {
551            fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
552                let decl = T::declaration();
553                let fields = Fields::NamedFields(vec![$(
554                    (FieldName::from(stringify!($name)), decl.clone())
555                ),*]);
556                let def = Definition::Struct { fields };
557                add_definition(Self::declaration(), def, definitions);
558                T::add_definitions_recursively(definitions);
559            }
560            fn declaration() -> Declaration {
561                format!("{}<{}>", stringify!($type), T::declaration())
562            }
563        }
564    };
565}
566
567impl_for_range!(Range, start, end);
568impl_for_range!(RangeInclusive, start, end);
569impl_for_range!(RangeFrom, start);
570impl_for_range!(RangeTo, end);
571impl_for_range!(RangeToInclusive, end);
572
573impl<T, const N: usize> BorshSchema for [T; N]
574where
575    T: BorshSchema,
576{
577    fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
578        use core::convert::TryFrom;
579        let length = u64::try_from(N).unwrap();
580        let definition = Definition::Sequence {
581            length_width: Definition::ARRAY_LENGTH_WIDTH,
582            length_range: length..=length,
583            elements: T::declaration(),
584        };
585        add_definition(Self::declaration(), definition, definitions);
586        T::add_definitions_recursively(definitions);
587    }
588    fn declaration() -> Declaration {
589        format!(r#"[{}; {}]"#, T::declaration(), N)
590    }
591}
592
593impl<T> BorshSchema for Option<T>
594where
595    T: BorshSchema,
596{
597    fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
598        let definition = Definition::Enum {
599            tag_width: 1,
600            variants: vec![
601                (0u8 as i64, "None".to_string(), <()>::declaration()),
602                (1u8 as i64, "Some".to_string(), T::declaration()),
603            ],
604        };
605        add_definition(Self::declaration(), definition, definitions);
606        T::add_definitions_recursively(definitions);
607        <()>::add_definitions_recursively(definitions);
608    }
609
610    fn declaration() -> Declaration {
611        format!(r#"Option<{}>"#, T::declaration())
612    }
613}
614
615impl<T, E> BorshSchema for core::result::Result<T, E>
616where
617    T: BorshSchema,
618    E: BorshSchema,
619{
620    fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
621        let definition = Definition::Enum {
622            tag_width: 1,
623            variants: vec![
624                (1u8 as i64, "Ok".to_string(), T::declaration()),
625                (0u8 as i64, "Err".to_string(), E::declaration()),
626            ],
627        };
628        add_definition(Self::declaration(), definition, definitions);
629        T::add_definitions_recursively(definitions);
630        E::add_definitions_recursively(definitions);
631    }
632
633    fn declaration() -> Declaration {
634        format!(r#"Result<{}, {}>"#, T::declaration(), E::declaration())
635    }
636}
637
638macro_rules! impl_for_vec_like_collection {
639    ($type: ident) => {
640        impl<T> BorshSchema for $type<T>
641        where
642            T: BorshSchema,
643        {
644            fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
645                let definition = Definition::Sequence {
646                    length_width: Definition::DEFAULT_LENGTH_WIDTH,
647                    length_range: Definition::DEFAULT_LENGTH_RANGE,
648                    elements: T::declaration(),
649                };
650                add_definition(Self::declaration(), definition, definitions);
651                T::add_definitions_recursively(definitions);
652            }
653
654            fn declaration() -> Declaration {
655                format!(r#"{}<{}>"#, stringify!($type), T::declaration())
656            }
657        }
658    };
659}
660
661impl_for_vec_like_collection!(Vec);
662impl_for_vec_like_collection!(VecDeque);
663impl_for_vec_like_collection!(LinkedList);
664
665impl<T> BorshSchema for [T]
666where
667    T: BorshSchema,
668{
669    fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
670        let definition = Definition::Sequence {
671            length_width: Definition::DEFAULT_LENGTH_WIDTH,
672            length_range: Definition::DEFAULT_LENGTH_RANGE,
673            elements: T::declaration(),
674        };
675        add_definition(Self::declaration(), definition, definitions);
676        T::add_definitions_recursively(definitions);
677    }
678
679    fn declaration() -> Declaration {
680        format!(r#"Vec<{}>"#, T::declaration())
681    }
682}
683
684/// Module is available if borsh is built with `features = ["std"]` or `features = ["hashbrown"]`.
685///
686/// Module defines [BorshSchema] implementation for
687/// [HashMap](std::collections::HashMap)/[HashSet](std::collections::HashSet).
688#[cfg(hash_collections)]
689pub mod hashes {
690    use crate::BorshSchema;
691
692    use super::{add_definition, Declaration, Definition};
693    use crate::__private::maybestd::collections::BTreeMap;
694
695    use crate::__private::maybestd::collections::{HashMap, HashSet};
696    #[cfg(not(feature = "std"))]
697    use alloc::format;
698
699    // S is not serialized, so we ignore it in schema too
700    // forcing S to be BorshSchema forces to define Definition
701    // which must be empty, but if not - it will fail
702    // so better to ignore it
703    impl<K, V, S> BorshSchema for HashMap<K, V, S>
704    where
705        K: BorshSchema,
706        V: BorshSchema,
707    {
708        fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
709            let definition = Definition::Sequence {
710                length_width: Definition::DEFAULT_LENGTH_WIDTH,
711                length_range: Definition::DEFAULT_LENGTH_RANGE,
712                elements: <(K, V)>::declaration(),
713            };
714            add_definition(Self::declaration(), definition, definitions);
715            <(K, V)>::add_definitions_recursively(definitions);
716        }
717
718        fn declaration() -> Declaration {
719            format!(r#"HashMap<{}, {}>"#, K::declaration(), V::declaration())
720        }
721    }
722
723    impl<T, S> BorshSchema for HashSet<T, S>
724    where
725        T: BorshSchema,
726    {
727        fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
728            let definition = Definition::Sequence {
729                length_width: Definition::DEFAULT_LENGTH_WIDTH,
730                length_range: Definition::DEFAULT_LENGTH_RANGE,
731                elements: <T>::declaration(),
732            };
733            add_definition(Self::declaration(), definition, definitions);
734            <T>::add_definitions_recursively(definitions);
735        }
736
737        fn declaration() -> Declaration {
738            format!(r#"HashSet<{}>"#, T::declaration())
739        }
740    }
741}
742
743impl<K, V> BorshSchema for BTreeMap<K, V>
744where
745    K: BorshSchema,
746    V: BorshSchema,
747{
748    fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
749        let definition = Definition::Sequence {
750            length_width: Definition::DEFAULT_LENGTH_WIDTH,
751            length_range: Definition::DEFAULT_LENGTH_RANGE,
752            elements: <(K, V)>::declaration(),
753        };
754        add_definition(Self::declaration(), definition, definitions);
755        <(K, V)>::add_definitions_recursively(definitions);
756    }
757
758    fn declaration() -> Declaration {
759        format!(r#"BTreeMap<{}, {}>"#, K::declaration(), V::declaration())
760    }
761}
762
763impl<T> BorshSchema for BTreeSet<T>
764where
765    T: BorshSchema,
766{
767    fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
768        let definition = Definition::Sequence {
769            length_width: Definition::DEFAULT_LENGTH_WIDTH,
770            length_range: Definition::DEFAULT_LENGTH_RANGE,
771            elements: <T>::declaration(),
772        };
773        add_definition(Self::declaration(), definition, definitions);
774        <T>::add_definitions_recursively(definitions);
775    }
776
777    fn declaration() -> Declaration {
778        format!(r#"BTreeSet<{}>"#, T::declaration())
779    }
780}
781
782// Because it's a zero-sized marker, its type parameter doesn't need to be
783// included in the schema and so it's not bound to `BorshSchema`
784impl<T> BorshSchema for PhantomData<T> {
785    fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
786        <()>::add_definitions_recursively(definitions);
787    }
788
789    fn declaration() -> Declaration {
790        <()>::declaration()
791    }
792}
793
794macro_rules! impl_tuple {
795    ($($name:ident),+) => {
796    impl<$($name),+> BorshSchema for ($($name,)+)
797    where
798        $($name: BorshSchema),+
799    {
800        fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
801            let elements = vec![$($name::declaration()),+];
802
803            let definition = Definition::Tuple { elements };
804            add_definition(Self::declaration(), definition, definitions);
805            $(
806                $name::add_definitions_recursively(definitions);
807            )+
808        }
809
810        fn declaration() -> Declaration {
811            let params = vec![$($name::declaration()),+];
812            if params.len() == 1 {
813                format!(r#"({},)"#, params[0])
814            } else {
815                format!(r#"({})"#, params.join(", "))
816            }
817        }
818    }
819    };
820}
821
822impl_tuple!(T0);
823impl_tuple!(T0, T1);
824impl_tuple!(T0, T1, T2);
825impl_tuple!(T0, T1, T2, T3);
826impl_tuple!(T0, T1, T2, T3, T4);
827impl_tuple!(T0, T1, T2, T3, T4, T5);
828impl_tuple!(T0, T1, T2, T3, T4, T5, T6);
829impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7);
830impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8);
831impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);
832impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
833impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
834impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);
835impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13);
836impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14);
837impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15);
838impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16);
839impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17);
840impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18);
841impl_tuple!(
842    T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19
843);
844impl_tuple!(
845    T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20
846);
847
848#[cfg(feature = "std")]
849mod ip_addr_std_derive_impl {
850    use crate::BorshSchema as BorshSchemaMacro;
851
852    #[derive(BorshSchemaMacro)]
853    #[borsh(crate = "crate")]
854    pub struct Ipv4Addr {
855        octets: [u8; 4],
856    }
857
858    #[derive(BorshSchemaMacro)]
859    #[borsh(crate = "crate")]
860    pub struct Ipv6Addr {
861        octets: [u8; 16],
862    }
863
864    #[derive(BorshSchemaMacro)]
865    #[borsh(crate = "crate")]
866    pub enum IpAddr {
867        /// An IPv4 address.
868        V4(core::net::Ipv4Addr),
869        /// An IPv6 address.
870        V6(core::net::Ipv6Addr),
871    }
872}
873
874#[cfg(feature = "std")]
875impl BorshSchema for core::net::Ipv4Addr {
876    fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
877        <ip_addr_std_derive_impl::Ipv4Addr>::add_definitions_recursively(definitions);
878    }
879
880    fn declaration() -> Declaration {
881        ip_addr_std_derive_impl::Ipv4Addr::declaration()
882    }
883}
884
885#[cfg(feature = "std")]
886impl BorshSchema for core::net::Ipv6Addr {
887    fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
888        <ip_addr_std_derive_impl::Ipv6Addr>::add_definitions_recursively(definitions);
889    }
890
891    fn declaration() -> Declaration {
892        ip_addr_std_derive_impl::Ipv6Addr::declaration()
893    }
894}
895
896#[cfg(feature = "std")]
897impl BorshSchema for core::net::IpAddr {
898    fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
899        <ip_addr_std_derive_impl::IpAddr>::add_definitions_recursively(definitions);
900    }
901
902    fn declaration() -> Declaration {
903        ip_addr_std_derive_impl::IpAddr::declaration()
904    }
905}