#![allow(dead_code)] use crate as borsh; use crate::__private::maybestd::{
borrow,
boxed::Box,
collections::{btree_map::Entry, BTreeMap, BTreeSet},
format,
string::{String, ToString},
vec,
vec::Vec,
};
use crate::io::{Read, Result as IOResult, Write};
use crate::{BorshDeserialize, BorshSchema as BorshSchemaMacro, BorshSerialize};
use core::borrow::Borrow;
use core::cmp::Ord;
use core::marker::PhantomData;
mod container_ext;
pub use container_ext::{SchemaContainerValidateError, SchemaMaxSerializedSizeError};
pub type Declaration = String;
pub type VariantName = String;
pub type DiscriminantValue = i64;
pub type FieldName = String;
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize, BorshSchemaMacro)]
pub enum Definition {
Primitive(u8),
Sequence {
length_width: u8,
length_range: core::ops::RangeInclusive<u64>,
elements: Declaration,
},
Tuple { elements: Vec<Declaration> },
Enum {
tag_width: u8,
variants: Vec<(DiscriminantValue, VariantName, Declaration)>,
},
Struct { fields: Fields },
}
impl Definition {
pub const ARRAY_LENGTH_WIDTH: u8 = 0;
pub const DEFAULT_LENGTH_WIDTH: u8 = 4;
pub const DEFAULT_LENGTH_RANGE: core::ops::RangeInclusive<u64> = 0..=(u32::MAX as u64);
}
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize, BorshSchemaMacro)]
pub enum Fields {
NamedFields(Vec<(FieldName, Declaration)>),
UnnamedFields(Vec<Declaration>),
Empty,
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct BorshSchemaContainer {
declaration: Declaration,
definitions: BTreeMap<Declaration, Definition>,
}
impl BorshSchemaContainer {
pub fn new(declaration: Declaration, definitions: BTreeMap<Declaration, Definition>) -> Self {
Self {
declaration,
definitions,
}
}
pub fn for_type<T: BorshSchema + ?Sized>() -> Self {
let mut definitions = Default::default();
T::add_definitions_recursively(&mut definitions);
Self::new(T::declaration(), definitions)
}
pub fn declaration(&self) -> &Declaration {
&self.declaration
}
pub fn definitions(&self) -> impl Iterator<Item = (&'_ Declaration, &'_ Definition)> {
self.definitions.iter()
}
pub fn get_definition<Q>(&self, declaration: &Q) -> Option<&Definition>
where
Declaration: Borrow<Q>,
Q: Ord + ?Sized,
{
self.definitions.get(declaration)
}
pub fn get_mut_definition<Q>(&mut self, declaration: &Q) -> Option<&mut Definition>
where
Declaration: Borrow<Q>,
Q: Ord + ?Sized,
{
self.definitions.get_mut(declaration)
}
pub fn insert_definition(
&mut self,
declaration: Declaration,
definition: Definition,
) -> Option<Definition> {
self.definitions.insert(declaration, definition)
}
pub fn remove_definition<Q>(&mut self, declaration: &Q) -> Option<Definition>
where
Declaration: Borrow<Q>,
Q: Ord + ?Sized,
{
self.definitions.remove(declaration)
}
}
impl BorshSerialize for BorshSchemaContainer
where
Declaration: BorshSerialize,
BTreeMap<Declaration, Definition>: BorshSerialize,
{
fn serialize<W: Write>(&self, writer: &mut W) -> IOResult<()> {
let declaration = self.declaration();
let definitions: BTreeMap<&Declaration, &Definition> = self.definitions().collect();
BorshSerialize::serialize(declaration, writer)?;
BorshSerialize::serialize(&definitions, writer)?;
Ok(())
}
}
impl BorshDeserialize for BorshSchemaContainer
where
Declaration: BorshDeserialize,
BTreeMap<Declaration, Definition>: BorshDeserialize,
{
fn deserialize_reader<R: Read>(reader: &mut R) -> IOResult<Self> {
let declaration: Declaration = BorshDeserialize::deserialize_reader(reader)?;
let definitions: BTreeMap<Declaration, Definition> =
BorshDeserialize::deserialize_reader(reader)?;
Ok(Self::new(declaration, definitions))
}
}
pub fn add_definition(
declaration: Declaration,
definition: Definition,
definitions: &mut BTreeMap<Declaration, Definition>,
) {
match definitions.entry(declaration) {
Entry::Occupied(occ) => {
let existing_def = occ.get();
assert_eq!(
existing_def,
&definition,
"Redefining type schema for {}. Types with the same names are not supported.",
occ.key()
);
}
Entry::Vacant(vac) => {
vac.insert(definition);
}
}
}
pub trait BorshSchema {
fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>);
fn declaration() -> Declaration;
}
impl BorshSchema for BorshSchemaContainer
where
Declaration: BorshSchema,
BTreeMap<Declaration, Definition>: BorshSchema,
{
fn declaration() -> Declaration {
"BorshSchemaContainer".to_string()
}
fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
let fields = Fields::NamedFields(<[_]>::into_vec(Box::new([
(
"declaration".to_string(),
<Declaration as BorshSchema>::declaration(),
),
(
"definitions".to_string(),
<BTreeMap<Declaration, Definition> as BorshSchema>::declaration(),
),
])));
let definition = Definition::Struct { fields };
add_definition(
<Self as BorshSchema>::declaration(),
definition,
definitions,
);
<Declaration as BorshSchema>::add_definitions_recursively(definitions);
<BTreeMap<Declaration, Definition> as BorshSchema>::add_definitions_recursively(
definitions,
);
}
}
impl<T> BorshSchema for Box<T>
where
T: BorshSchema + ?Sized,
{
fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
T::add_definitions_recursively(definitions);
}
fn declaration() -> Declaration {
T::declaration()
}
}
impl<T> BorshSchema for core::cell::Cell<T>
where
T: BorshSchema + Copy,
{
fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
T::add_definitions_recursively(definitions);
}
fn declaration() -> Declaration {
T::declaration()
}
}
impl<T> BorshSchema for core::cell::RefCell<T>
where
T: BorshSchema + Sized,
{
fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
T::add_definitions_recursively(definitions);
}
fn declaration() -> Declaration {
T::declaration()
}
}
#[cfg(feature = "rc")]
pub mod rc {
use crate::BorshSchema;
use super::{Declaration, Definition};
use crate::__private::maybestd::collections::BTreeMap;
use crate::__private::maybestd::{rc::Rc, sync::Arc};
impl<T> BorshSchema for Rc<T>
where
T: BorshSchema + ?Sized,
{
fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
T::add_definitions_recursively(definitions);
}
fn declaration() -> Declaration {
T::declaration()
}
}
impl<T> BorshSchema for Arc<T>
where
T: BorshSchema + ?Sized,
{
fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
T::add_definitions_recursively(definitions);
}
fn declaration() -> Declaration {
T::declaration()
}
}
}
impl<T> BorshSchema for borrow::Cow<'_, T>
where
T: borrow::ToOwned + ?Sized,
T::Owned: BorshSchema,
{
fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
<T::Owned as BorshSchema>::add_definitions_recursively(definitions);
}
fn declaration() -> Declaration {
<T::Owned as BorshSchema>::declaration()
}
}
macro_rules! impl_for_renamed_primitives {
($($ty: ty : $name: ident => $size: expr);+) => {
$(
impl BorshSchema for $ty {
#[inline]
fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
let definition = Definition::Primitive($size);
add_definition(Self::declaration(), definition, definitions);
}
#[inline]
fn declaration() -> Declaration { stringify!($name).into() }
}
)+
};
($($ty: ty : $name: expr, $size: expr);+) => {
$(
impl BorshSchema for $ty {
#[inline]
fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
let definition = Definition::Primitive($size);
add_definition(Self::declaration(), definition, definitions);
}
#[inline]
fn declaration() -> Declaration { $name.into() }
}
)+
};
}
macro_rules! impl_for_primitives {
($($ty: ident => $size: expr);+) => {
impl_for_renamed_primitives!{$($ty : $ty => $size);+}
};
}
impl_for_primitives!(bool => 1; f32 => 4; f64 => 8; i8 => 1; i16 => 2; i32 => 4; i64 => 8; i128 => 16);
impl_for_primitives!(u8 => 1; u16 => 2; u32 => 4; u64 => 8; u128 => 16);
impl_for_renamed_primitives!(isize: i64 => 8);
impl_for_renamed_primitives!(usize: u64 => 8);
impl_for_renamed_primitives!(core::num::NonZeroI8: NonZeroI8 => 1);
impl_for_renamed_primitives!(core::num::NonZeroI16: NonZeroI16 => 2);
impl_for_renamed_primitives!(core::num::NonZeroI32: NonZeroI32 => 4);
impl_for_renamed_primitives!(core::num::NonZeroI64: NonZeroI64 => 8);
impl_for_renamed_primitives!(core::num::NonZeroI128: NonZeroI128 => 16);
impl_for_renamed_primitives!(core::num::NonZeroU8: NonZeroU8 => 1);
impl_for_renamed_primitives!(core::num::NonZeroU16: NonZeroU16 => 2);
impl_for_renamed_primitives!(core::num::NonZeroU32: NonZeroU32 => 4);
impl_for_renamed_primitives!(core::num::NonZeroU64: NonZeroU64 => 8);
impl_for_renamed_primitives!(core::num::NonZeroU128: NonZeroU128 => 16);
impl_for_renamed_primitives!(core::num::NonZeroUsize: NonZeroUsize => 8);
impl_for_renamed_primitives!((): "()", 0);
impl BorshSchema for String {
#[inline]
fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
str::add_definitions_recursively(definitions);
}
#[inline]
fn declaration() -> Declaration {
str::declaration()
}
}
impl BorshSchema for str {
#[inline]
fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
let definition = Definition::Sequence {
length_width: Definition::DEFAULT_LENGTH_WIDTH,
length_range: Definition::DEFAULT_LENGTH_RANGE,
elements: u8::declaration(),
};
add_definition(Self::declaration(), definition, definitions);
u8::add_definitions_recursively(definitions);
}
#[inline]
fn declaration() -> Declaration {
"String".into()
}
}
#[cfg(feature = "ascii")]
pub mod ascii {
use crate::BorshSchema;
use super::{add_definition, Declaration, Definition};
use crate::__private::maybestd::collections::BTreeMap;
impl BorshSchema for ascii::AsciiString {
#[inline]
fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
ascii::AsciiStr::add_definitions_recursively(definitions);
}
#[inline]
fn declaration() -> Declaration {
ascii::AsciiStr::declaration()
}
}
impl BorshSchema for ascii::AsciiStr {
#[inline]
fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
let definition = Definition::Sequence {
length_width: Definition::DEFAULT_LENGTH_WIDTH,
length_range: Definition::DEFAULT_LENGTH_RANGE,
elements: ascii::AsciiChar::declaration(),
};
add_definition(Self::declaration(), definition, definitions);
ascii::AsciiChar::add_definitions_recursively(definitions);
}
#[inline]
fn declaration() -> Declaration {
"AsciiString".into()
}
}
impl BorshSchema for ascii::AsciiChar {
#[inline]
fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
add_definition(Self::declaration(), Definition::Primitive(1), definitions);
}
#[inline]
fn declaration() -> Declaration {
"AsciiChar".into()
}
}
}
impl BorshSchema for core::ops::RangeFull {
#[inline]
fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
let fields = Fields::Empty;
let def = Definition::Struct { fields };
add_definition(Self::declaration(), def, definitions);
}
#[inline]
fn declaration() -> Declaration {
"RangeFull".into()
}
}
macro_rules! impl_for_range {
($type:ident, $($name:ident),*) => {
impl<T: BorshSchema> BorshSchema for core::ops::$type<T> {
fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
let decl = T::declaration();
let fields = Fields::NamedFields(vec![$(
(FieldName::from(stringify!($name)), decl.clone())
),*]);
let def = Definition::Struct { fields };
add_definition(Self::declaration(), def, definitions);
T::add_definitions_recursively(definitions);
}
fn declaration() -> Declaration {
format!("{}<{}>", stringify!($type), T::declaration())
}
}
};
}
impl_for_range!(Range, start, end);
impl_for_range!(RangeInclusive, start, end);
impl_for_range!(RangeFrom, start);
impl_for_range!(RangeTo, end);
impl_for_range!(RangeToInclusive, end);
impl<T, const N: usize> BorshSchema for [T; N]
where
T: BorshSchema,
{
fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
use core::convert::TryFrom;
let length = u64::try_from(N).unwrap();
let definition = Definition::Sequence {
length_width: Definition::ARRAY_LENGTH_WIDTH,
length_range: length..=length,
elements: T::declaration(),
};
add_definition(Self::declaration(), definition, definitions);
T::add_definitions_recursively(definitions);
}
fn declaration() -> Declaration {
format!(r#"[{}; {}]"#, T::declaration(), N)
}
}
impl<T> BorshSchema for Option<T>
where
T: BorshSchema,
{
fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
let definition = Definition::Enum {
tag_width: 1,
variants: vec![
(0u8 as i64, "None".to_string(), <()>::declaration()),
(1u8 as i64, "Some".to_string(), T::declaration()),
],
};
add_definition(Self::declaration(), definition, definitions);
T::add_definitions_recursively(definitions);
<()>::add_definitions_recursively(definitions);
}
fn declaration() -> Declaration {
format!(r#"Option<{}>"#, T::declaration())
}
}
impl<T, E> BorshSchema for core::result::Result<T, E>
where
T: BorshSchema,
E: BorshSchema,
{
fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
let definition = Definition::Enum {
tag_width: 1,
variants: vec![
(1u8 as i64, "Ok".to_string(), T::declaration()),
(0u8 as i64, "Err".to_string(), E::declaration()),
],
};
add_definition(Self::declaration(), definition, definitions);
T::add_definitions_recursively(definitions);
E::add_definitions_recursively(definitions);
}
fn declaration() -> Declaration {
format!(r#"Result<{}, {}>"#, T::declaration(), E::declaration())
}
}
impl<T> BorshSchema for Vec<T>
where
T: BorshSchema,
{
fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
let definition = Definition::Sequence {
length_width: Definition::DEFAULT_LENGTH_WIDTH,
length_range: Definition::DEFAULT_LENGTH_RANGE,
elements: T::declaration(),
};
add_definition(Self::declaration(), definition, definitions);
T::add_definitions_recursively(definitions);
}
fn declaration() -> Declaration {
format!(r#"Vec<{}>"#, T::declaration())
}
}
impl<T> BorshSchema for [T]
where
T: BorshSchema,
{
fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
let definition = Definition::Sequence {
length_width: Definition::DEFAULT_LENGTH_WIDTH,
length_range: Definition::DEFAULT_LENGTH_RANGE,
elements: T::declaration(),
};
add_definition(Self::declaration(), definition, definitions);
T::add_definitions_recursively(definitions);
}
fn declaration() -> Declaration {
format!(r#"Vec<{}>"#, T::declaration())
}
}
#[cfg(hash_collections)]
pub mod hashes {
use crate::BorshSchema;
use super::{add_definition, Declaration, Definition};
use crate::__private::maybestd::collections::BTreeMap;
use crate::__private::maybestd::collections::{HashMap, HashSet};
#[cfg(not(feature = "std"))]
use alloc::format;
impl<K, V> BorshSchema for HashMap<K, V>
where
K: BorshSchema,
V: BorshSchema,
{
fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
let definition = Definition::Sequence {
length_width: Definition::DEFAULT_LENGTH_WIDTH,
length_range: Definition::DEFAULT_LENGTH_RANGE,
elements: <(K, V)>::declaration(),
};
add_definition(Self::declaration(), definition, definitions);
<(K, V)>::add_definitions_recursively(definitions);
}
fn declaration() -> Declaration {
format!(r#"HashMap<{}, {}>"#, K::declaration(), V::declaration())
}
}
impl<T> BorshSchema for HashSet<T>
where
T: BorshSchema,
{
fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
let definition = Definition::Sequence {
length_width: Definition::DEFAULT_LENGTH_WIDTH,
length_range: Definition::DEFAULT_LENGTH_RANGE,
elements: <T>::declaration(),
};
add_definition(Self::declaration(), definition, definitions);
<T>::add_definitions_recursively(definitions);
}
fn declaration() -> Declaration {
format!(r#"HashSet<{}>"#, T::declaration())
}
}
}
impl<K, V> BorshSchema for BTreeMap<K, V>
where
K: BorshSchema,
V: BorshSchema,
{
fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
let definition = Definition::Sequence {
length_width: Definition::DEFAULT_LENGTH_WIDTH,
length_range: Definition::DEFAULT_LENGTH_RANGE,
elements: <(K, V)>::declaration(),
};
add_definition(Self::declaration(), definition, definitions);
<(K, V)>::add_definitions_recursively(definitions);
}
fn declaration() -> Declaration {
format!(r#"BTreeMap<{}, {}>"#, K::declaration(), V::declaration())
}
}
impl<T> BorshSchema for BTreeSet<T>
where
T: BorshSchema,
{
fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
let definition = Definition::Sequence {
length_width: Definition::DEFAULT_LENGTH_WIDTH,
length_range: Definition::DEFAULT_LENGTH_RANGE,
elements: <T>::declaration(),
};
add_definition(Self::declaration(), definition, definitions);
<T>::add_definitions_recursively(definitions);
}
fn declaration() -> Declaration {
format!(r#"BTreeSet<{}>"#, T::declaration())
}
}
impl<T> BorshSchema for PhantomData<T> {
fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
<()>::add_definitions_recursively(definitions);
}
fn declaration() -> Declaration {
<()>::declaration()
}
}
macro_rules! impl_tuple {
($($name:ident),+) => {
impl<$($name),+> BorshSchema for ($($name,)+)
where
$($name: BorshSchema),+
{
fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
let elements = vec![$($name::declaration()),+];
let definition = Definition::Tuple { elements };
add_definition(Self::declaration(), definition, definitions);
$(
$name::add_definitions_recursively(definitions);
)+
}
fn declaration() -> Declaration {
let params = vec![$($name::declaration()),+];
if params.len() == 1 {
format!(r#"({},)"#, params[0])
} else {
format!(r#"({})"#, params.join(", "))
}
}
}
};
}
impl_tuple!(T0);
impl_tuple!(T0, T1);
impl_tuple!(T0, T1, T2);
impl_tuple!(T0, T1, T2, T3);
impl_tuple!(T0, T1, T2, T3, T4);
impl_tuple!(T0, T1, T2, T3, T4, T5);
impl_tuple!(T0, T1, T2, T3, T4, T5, T6);
impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7);
impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8);
impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);
impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);
impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13);
impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14);
impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15);
impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16);
impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17);
impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18);
impl_tuple!(
T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19
);
impl_tuple!(
T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20
);