Derive Macro borsh::BorshSchema
source · #[derive(BorshSchema)]
{
// Attributes available to this derive:
#[borsh]
}
Expand description
Derive macro available if borsh is built with features = ["derive", "schema"]
.
derive proc-macro for borsh::BorshSchema
trait
Bounds
Generally, BorshSchema
adds borsh::BorshSchema
bound to any type parameter
found in item’s fields.
/// impl<U, V> borsh::BorshSchema for A<U, V>
/// where
/// U: borsh::BorshSchema,
/// V: borsh::BorshSchema,
#[derive(BorshSchema)]
struct A<U, V> {
x: U,
y: V,
}
/// impl<U, V> borsh::BorshSchema for A<U, V>
/// where
/// U: borsh::BorshSchema,
#[derive(BorshSchema)]
struct A<U, V> {
x: U,
#[borsh(skip)]
y: V,
}
Attributes
1. #[borsh(skip)]
(field level attribute)
#[borsh(skip)]
makes derive skip including schema from annotated field into schema’s implementation.
#[borsh(skip)]
makes derive skip adding any type parameters, present in the field, to parameters bound by borsh::BorshSchema
.
#[derive(BorshSchema)]
struct A {
x: u64,
#[borsh(skip)]
y: f32,
}
2. #[borsh(schema(params = ...))]
(field level attribute)
syntax
Attribute takes literal string value, which is a comma-separated list of ParameterOverride
-s, which may be empty.
usage
It may be used in order to:
- fix complex cases, when derive hasn’t figured out the right bounds on type parameters and declaration parameters automatically.
- remove parameters, which do not take part in serialization/deserialization, from bounded ones and from declaration parameters.
ParameterOverride
describes an entry like order_param => override_type
,
e.g. K => <K as TraitName>::Associated
.
Such an entry instructs BorshSchema
derive to:
- add
override_type
to types, bounded byborsh::BorshSchema
in implementation block. - add
<override_type>::declaration()
to parameters vector infn declaration()
method ofBorshSchema
trait that is being derived. - the
order_param
is required to establish the same order in parameters vector (2.) as that of type parameters in generics of type, thatBorshSchema
is derived for. - entries, specified for a field, together replace whatever would’ve been derived automatically for 1. and 2. .
// derive here figures the bound erroneously as `T: borsh::BorshSchema` .
// attribute replaces it with <T as TraitName>::Associated: borsh::BorshSchema`
#[derive(BorshSchema)]
struct A<V, T>
where
T: TraitName,
{
#[borsh(schema(params = "T => <T as TraitName>::Associated"))]
field: <T as TraitName>::Associated,
another: V,
}
// K in PrimaryMap isn't stored during serialization / read during deserialization.
// thus, it's not a parameter, relevant for `BorshSchema`
// ...
// impl<K: EntityRef, V> borsh::BorshSchema for A<K, V>
// where
// V: borsh::BorshSchema,
#[derive(BorshSchema)]
struct A<K: EntityRef, V> {
#[borsh(
schema(
params = "V => V"
)
)]
x: PrimaryMap<K, V>,
y: String,
}
#[derive(BorshSchema)]
pub struct PrimaryMap<K, V>
where
K: EntityRef,
{
elems: Vec<V>,
unused: PhantomData<K>,
}
interaction with #[borsh(skip)]
#[borsh(schema(params = ...))]
is not allowed to be used simultaneously with #[borsh(skip)]
.
3. #[borsh(schema(with_funcs(declaration = ..., definitions = ...)))]
(field level attribute)
syntax
Each of declaration
and definitions
nested sub-attributes takes literal string value, which is a syn’s ExprPath.
Currently both declaration
and definitions
are required to be specifed at the same time.
usage
Attribute adds possibility to specify full path of 2 functions, optionally qualified with generics, with which to generate borsh schema for annotated field.
It may be used when BorshSchema
cannot be implemented for field’s type, if it’s from foreign crate.
It may be used to override the implementation of schema for some other reason.
use indexmap::IndexMap;
mod index_map_impl {
pub mod schema {
use std::collections::BTreeMap;
use borsh::{
schema::{Declaration, Definition},
BorshSchema,
};
pub fn declaration<K: borsh::BorshSchema, V: borsh::BorshSchema>() -> Declaration {
let params = vec![<K>::declaration(), <V>::declaration()];
format!(r#"{}<{}>"#, "IndexMap", params.join(", "))
}
pub fn add_definitions_recursively<K: borsh::BorshSchema, V: borsh::BorshSchema>(
definitions: &mut BTreeMap<Declaration, Definition>,
) {
let definition = Definition::Sequence {
elements: <(K, V)>::declaration(),
};
let no_recursion_flag = definitions.get(&declaration::<K, V>()).is_none();
<() as BorshSchema>::add_definition(declaration::<K, V>(), definition, definitions);
if no_recursion_flag {
<(K, V)>::add_definitions_recursively(definitions);
}
}
}
}
#[derive(BorshSchema)]
struct B<K, V> {
#[borsh(
schema(
with_funcs(
declaration = "index_map_impl::schema::declaration::<K, V>",
definitions = "index_map_impl::schema::add_definitions_recursively::<K, V>"
),
)
)]
x: IndexMap<K, V>,
y: String,
}
interaction with #[borsh(skip)]
#[borsh(schema(with_funcs(declaration = ..., definitions = ...)))]
is not allowed to be used simultaneously with #[borsh(skip)]
.