Skip to content

Commit

Permalink
schema changes
Browse files Browse the repository at this point in the history
  • Loading branch information
dzmitry-lahoda committed Nov 3, 2024
1 parent 3da00ce commit 4acaec2
Show file tree
Hide file tree
Showing 13 changed files with 147 additions and 6 deletions.
14 changes: 10 additions & 4 deletions borsh-derive/src/internals/enum_discriminant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub struct Discriminants{
variants: HashMap<Ident, TokenStream>,
discriminant_type : syn::TypePath,
use_discriminant: bool,
tag_width: u8,
}

impl Discriminants {
Expand All @@ -35,8 +36,10 @@ impl Discriminants {
}

let mut discriminant_type: TypePath = syn::parse_str("u8").unwrap();
let mut tag_width = 1;

if let Some((tag_width, span)) = maybe_borsh_tag_width {
if let Some((defined_tag_width, span)) = maybe_borsh_tag_width {
tag_width = defined_tag_width;
if !use_discriminant {
return Err(syn::Error::new(
span,
Expand Down Expand Up @@ -67,7 +70,6 @@ impl Discriminants {
)),
};
discriminant_type = rust_repr.clone();
println!("repr_type: {:?}, repr_size: {:?} tag_width:{:?} ", repr_type, repr_size, tag_width);

if repr_size != tag_width {
return Err(syn::Error::new(
Expand All @@ -83,20 +85,24 @@ impl Discriminants {
));
}
}
println!("discriminant_type: {:?}", discriminant_type.path.get_ident());
}

Ok(Self {
variants : map,
discriminant_type,
use_discriminant
use_discriminant,
tag_width,
})
}

pub fn discriminant_type(&self) -> &syn::TypePath {
&self.discriminant_type
}

pub fn tag_width(&self) -> u8 {
self.tag_width
}

pub fn get(
&self,
variant_ident: &Ident,
Expand Down
4 changes: 3 additions & 1 deletion borsh-derive/src/internals/schema/enums/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,15 @@ pub fn process(input: &ItemEnum, cratename: Path) -> syn::Result<TokenStream2> {
variants_defs.push(variant_output.variant_entry);
}

let tag_width = discriminants.tag_width();
let type_definitions = quote! {
fn add_definitions_recursively(definitions: &mut #cratename::__private::maybestd::collections::BTreeMap<#cratename::schema::Declaration, #cratename::schema::Definition>) {
#inner_defs
#add_recursive_defs
let definition = #cratename::schema::Definition::Enum {
tag_width: 1,
tag_width: #tag_width,
variants: #cratename::__private::maybestd::vec![#(#variants_defs),*],
tag_signed: false,
};
#cratename::schema::add_definition(<Self as #cratename::BorshSchema>::declaration(), definition, definitions);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
source: borsh-derive/src/internals/schema/enums/mod.rs
assertion_line: 403
expression: pretty_print_syn_str(&actual).unwrap()
---
impl<K: Key, V> borsh::BorshSchema for A<K, V>
where
V: Value,
K: borsh::BorshSchema,
V: borsh::BorshSchema,
{
fn declaration() -> borsh::schema::Declaration {
let params = borsh::__private::maybestd::vec![
< K as borsh::BorshSchema > ::declaration(), < V as borsh::BorshSchema >
::declaration()
];
format!(r#"{}<{}>"#, "A", params.join(", "))
}
fn add_definitions_recursively(
definitions: &mut borsh::__private::maybestd::collections::BTreeMap<
borsh::schema::Declaration,
borsh::schema::Definition,
>,
) {
#[allow(dead_code)]
#[derive(borsh::BorshSchema)]
#[borsh(crate = "borsh")]
struct AB<K: Key, V>
where
V: Value,
{
x: HashMap<K, V>,
y: String,
}
#[allow(dead_code)]
#[derive(borsh::BorshSchema)]
#[borsh(crate = "borsh")]
struct AC<K: Key>(K, Vec<A>);
<AB<K, V> as borsh::BorshSchema>::add_definitions_recursively(definitions);
<AC<K> as borsh::BorshSchema>::add_definitions_recursively(definitions);
let definition = borsh::schema::Definition::Enum {
tag_width: 1u8,
variants: borsh::__private::maybestd::vec![
(u8::from(0u8) as i64, "B".into(), < AB < K, V > as borsh::BorshSchema >
::declaration()), (u8::from(1u8) as i64, "C".into(), < AC < K > as
borsh::BorshSchema > ::declaration())
],
tag_signed: false,
};
borsh::schema::add_definition(
<Self as borsh::BorshSchema>::declaration(),
definition,
definitions,
);
}
}
6 changes: 6 additions & 0 deletions borsh/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ pub enum Definition {
/// invalid if the value is greater than eight.
tag_width: u8,

/// If true, than tag is signed value.
/// If false, unsigned value.
tag_signed: bool,

/// Possible variants of the enumeration.
/// `VariantName` is metadata, not present in a type's serialized representation.
variants: Vec<(DiscriminantValue, VariantName, Declaration)>,
Expand Down Expand Up @@ -601,6 +605,7 @@ where
(0u8 as i64, "None".to_string(), <()>::declaration()),
(1u8 as i64, "Some".to_string(), T::declaration()),
],
tag_signed: false,
};
add_definition(Self::declaration(), definition, definitions);
T::add_definitions_recursively(definitions);
Expand All @@ -624,6 +629,7 @@ where
(1u8 as i64, "Ok".to_string(), T::declaration()),
(0u8 as i64, "Err".to_string(), E::declaration()),
],
tag_signed: false,
};
add_definition(Self::declaration(), definition, definitions);
T::add_definitions_recursively(definitions);
Expand Down
2 changes: 2 additions & 0 deletions borsh/src/schema/container_ext/max_size.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ fn max_serialized_size_impl<'a>(
Ok(Definition::Enum {
tag_width,
variants,
tag_signed: _,
}) => {
let mut max = 0;
for (_, _, variant) in variants {
Expand Down Expand Up @@ -232,6 +233,7 @@ fn is_zero_size_impl<'a>(
Ok(Definition::Enum {
tag_width: 0,
variants,
tag_signed: _,
}) => all(
variants.iter(),
|(_variant_discrim, _variant_name, declaration)| declaration,
Expand Down
2 changes: 2 additions & 0 deletions borsh/src/schema/container_ext/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,12 @@ fn validate_impl<'a>(
Definition::Enum {
tag_width,
variants,
tag_signed: _,
} => {
if *tag_width > U64_LEN {
return Err(Error::TagTooWide(declaration.to_string()));
}

for (_, _, variant) in variants {
validate_impl(variant, schema, stack)?;
}
Expand Down
1 change: 1 addition & 0 deletions borsh/tests/schema/container_extension/test_max_size.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ fn max_serialized_size_custom_enum() {
}
fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
let definition = Definition::Enum {
tag_signed: false,
tag_width: N,
variants: vec![
(0, "Just".into(), T::declaration()),
Expand Down
54 changes: 53 additions & 1 deletion borsh/tests/schema/test_enum_discriminants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ fn test_schema_discriminant_no_unit_type() {
assert_eq!(
schema_map! {
"XY" => Definition::Enum {
tag_signed: false,
tag_width: 1,
variants: vec![
(0, "A".to_string(), "XYA".to_string()),
Expand All @@ -29,7 +30,7 @@ fn test_schema_discriminant_no_unit_type() {
(22, "D".to_string(), "XYD".to_string()),
(10, "E".to_string(), "XYE".to_string()),
(11, "F".to_string(), "XYF".to_string())
]
],
},
"XYA" => Definition::Struct{ fields: Fields::Empty },
"XYB" => Definition::Struct{ fields: Fields::Empty },
Expand Down Expand Up @@ -73,6 +74,7 @@ fn test_schema_discriminant_no_unit_type_no_use_discriminant() {
assert_eq!(
schema_map! {
"XYNoDiscriminant" => Definition::Enum {
tag_signed: false,
tag_width: 1,
variants: vec![
(0, "A".to_string(), "XYNoDiscriminantA".to_string()),
Expand Down Expand Up @@ -100,3 +102,53 @@ fn test_schema_discriminant_no_unit_type_no_use_discriminant() {
defs
);
}


#[test]
fn tag_widths() {
#[derive(BorshSchema)]
#[borsh(use_discriminant=true, tag_width = 2)]
#[repr(u16)]
enum U16Discriminant {
A = 42u16,
}

let mut defs = Default::default();
U16Discriminant::add_definitions_recursively(&mut defs);
assert_eq!(
schema_map! {
"U16Discriminant" => Definition::Enum {
tag_signed: false,
tag_width: 2,
variants: vec![
(42, "A".to_string(), "U16DiscriminantA".to_string()),
],
},
"U16DiscriminantA" => Definition::Struct{ fields: Fields::Empty }
},
defs
);

#[derive(BorshSchema)]
#[borsh(use_discriminant = true, tag_width = 4)]
#[repr(u32)]
enum U32Discriminant {
A = 42u32,
}

let mut defs = Default::default();
U32Discriminant::add_definitions_recursively(&mut defs);
assert_eq!(
schema_map! {
"U32Discriminant" => Definition::Enum {
tag_signed: false,
tag_width: 4,
variants: vec![
(42, "A".to_string(), "U32DiscriminantA".to_string()),
],
},
"U32DiscriminantA" => Definition::Struct{ fields: Fields::Empty }
},
defs
);
}
6 changes: 6 additions & 0 deletions borsh/tests/schema/test_generic_enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ pub fn complex_enum_generics() {
"ABacon" => Definition::Struct {fields: Fields::Empty},
"Oil" => Definition::Struct {fields: Fields::Empty},
"A<Cucumber, Wrapper>" => Definition::Enum {
tag_signed: false,
tag_width: 1,
variants: vec![
(0, "Bacon".to_string(), "ABacon".to_string()),
Expand Down Expand Up @@ -102,6 +103,7 @@ pub fn complex_enum_generics2() {
assert_eq!(
schema_map! {
"A<Cucumber, Wrapper<String>>" => Definition::Enum {
tag_signed: false,
tag_width: 1,
variants: vec![
(0, "Bacon".to_string(), "ABacon".to_string()),
Expand All @@ -111,6 +113,7 @@ pub fn complex_enum_generics2() {
]
},
"A<String, String>" => Definition::Enum {
tag_signed: false,
tag_width: 1,
variants: vec![
(0, "Bacon".to_string(), "ABacon".to_string()),
Expand All @@ -134,13 +137,15 @@ pub fn complex_enum_generics2() {
},
"Oil<u64, String>" => Definition::Struct { fields: Fields::NamedFields(vec![("seeds".to_string(), "HashMap<u64, String>".to_string()), ("liquid".to_string(), "Option<u64>".to_string())])},
"Option<String>" => Definition::Enum {
tag_signed: false,
tag_width: 1,
variants: vec![
(0, "None".to_string(), "()".to_string()),
(1, "Some".to_string(), "String".to_string())
]
},
"Option<u64>" => Definition::Enum {
tag_signed: false,
tag_width: 1,
variants: vec![
(0, "None".to_string(), "()".to_string()),
Expand All @@ -166,6 +171,7 @@ pub fn complex_enum_generics2() {
fn common_map_associated() -> BTreeMap<String, Definition> {
schema_map! {
"EnumParametrized<String, u32, i8, u16>" => Definition::Enum {
tag_signed: false,
tag_width: 1,
variants: vec![
(0, "B".to_string(), "EnumParametrizedB<u32, i8, u16>".to_string()),
Expand Down
3 changes: 3 additions & 0 deletions borsh/tests/schema/test_option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ fn simple_option() {
assert_eq!(
schema_map! {
"Option<u64>" => Definition::Enum {
tag_signed: false,
tag_width: 1,
variants: vec![
(0, "None".to_string(), "()".to_string()),
Expand All @@ -31,13 +32,15 @@ fn nested_option() {
assert_eq!(
schema_map! {
"Option<u64>" => Definition::Enum {
tag_signed: false,
tag_width: 1,
variants: vec![
(0, "None".to_string(), "()".to_string()),
(1, "Some".to_string(), "u64".to_string()),
]
},
"Option<Option<u64>>" => Definition::Enum {
tag_signed: false,
tag_width: 1,
variants: vec![
(0, "None".to_string(), "()".to_string()),
Expand Down
1 change: 1 addition & 0 deletions borsh/tests/schema/test_recursive_enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub fn recursive_enum_schema() {
assert_eq!(
schema_map! {
"ERecD" => Definition::Enum {
tag_signed: false,
tag_width: 1,
variants: vec![
(0, "B".to_string(), "ERecDB".to_string()),
Expand Down
1 change: 1 addition & 0 deletions borsh/tests/schema/test_schema_with_third_party.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ pub fn enum_overriden() {
assert_eq!(
schema_map! {
"C<u64, String>" => Definition::Enum {
tag_signed: false,
tag_width: 1,
variants: vec![
(0, "C3".to_string(), "CC3".to_string()),
Expand Down
3 changes: 3 additions & 0 deletions borsh/tests/schema/test_simple_enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub fn simple_enum() {
"ABacon" => Definition::Struct{ fields: Fields::Empty },
"AEggs" => Definition::Struct{ fields: Fields::Empty },
"A" => Definition::Enum {
tag_signed: false,
tag_width: 1,
variants: vec![(0, "Bacon".to_string(), "ABacon".to_string()), (1, "Eggs".to_string(), "AEggs".to_string())]
}
Expand All @@ -47,6 +48,7 @@ pub fn single_field_enum() {
schema_map! {
"ABacon" => Definition::Struct {fields: Fields::Empty},
"A" => Definition::Enum {
tag_signed: false,
tag_width: 1,
variants: vec![(0, "Bacon".to_string(), "ABacon".to_string())]
}
Expand Down Expand Up @@ -131,6 +133,7 @@ pub fn complex_enum_with_schema() {
"ABacon" => Definition::Struct {fields: Fields::Empty},
"Oil" => Definition::Struct {fields: Fields::Empty},
"A" => Definition::Enum {
tag_signed: false,
tag_width: 1,
variants: vec![
(0, "Bacon".to_string(), "ABacon".to_string()),
Expand Down

0 comments on commit 4acaec2

Please sign in to comment.