diff --git a/borsh-derive/src/internals/schema/enums/mod.rs b/borsh-derive/src/internals/schema/enums/mod.rs index 35a0345d4..bcd5c2e35 100644 --- a/borsh-derive/src/internals/schema/enums/mod.rs +++ b/borsh-derive/src/internals/schema/enums/mod.rs @@ -198,6 +198,43 @@ mod tests { local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); } + #[test] + fn borsh_discriminant_false() { + let item_enum: ItemEnum = syn::parse2(quote! { + #[borsh(use_discriminant = false)] + enum X { + A, + B = 20, + C, + D, + E = 10, + F, + } + }) + .unwrap(); + let actual = process(&item_enum, default_cratename()).unwrap(); + + local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + } + #[test] + fn borsh_discriminant_true() { + let item_enum: ItemEnum = syn::parse2(quote! { + #[borsh(use_discriminant = true)] + enum X { + A, + B = 20, + C, + D, + E = 10, + F, + } + }) + .unwrap(); + let actual = process(&item_enum, default_cratename()).unwrap(); + + local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + } + #[test] fn single_field_enum() { let item_enum: ItemEnum = syn::parse2(quote! { diff --git a/borsh-derive/src/internals/schema/enums/snapshots/borsh_discriminant_false.snap b/borsh-derive/src/internals/schema/enums/snapshots/borsh_discriminant_false.snap new file mode 100644 index 000000000..7fc5183e8 --- /dev/null +++ b/borsh-derive/src/internals/schema/enums/snapshots/borsh_discriminant_false.snap @@ -0,0 +1,58 @@ +--- +source: borsh-derive/src/internals/schema/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for X { + fn declaration() -> borsh::schema::Declaration { + "X".to_string() + } + 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 XA; + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct XB; + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct XC; + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct XD; + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct XE; + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct XF; + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + let definition = borsh::schema::Definition::Enum { + tag_width: 1, + variants: borsh::__private::maybestd::vec![ + (0u8 as i64, "A".to_string(), < XA > ::declaration()), (1u8 as i64, "B" + .to_string(), < XB > ::declaration()), (2u8 as i64, "C".to_string(), < XC + > ::declaration()), (3u8 as i64, "D".to_string(), < XD > + ::declaration()), (4u8 as i64, "E".to_string(), < XE > ::declaration()), + (5u8 as i64, "F".to_string(), < XF > ::declaration()) + ], + }; + borsh::schema::add_definition(Self::declaration(), definition, definitions); + } +} + diff --git a/borsh-derive/src/internals/schema/enums/snapshots/borsh_discriminant_true.snap b/borsh-derive/src/internals/schema/enums/snapshots/borsh_discriminant_true.snap new file mode 100644 index 000000000..6a0e0cbbe --- /dev/null +++ b/borsh-derive/src/internals/schema/enums/snapshots/borsh_discriminant_true.snap @@ -0,0 +1,58 @@ +--- +source: borsh-derive/src/internals/schema/enums/mod.rs +expression: pretty_print_syn_str(&actual).unwrap() +--- +impl borsh::BorshSchema for X { + fn declaration() -> borsh::schema::Declaration { + "X".to_string() + } + 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 XA; + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct XB; + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct XC; + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct XD; + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct XE; + #[allow(dead_code)] + #[derive(borsh::BorshSchema)] + #[borsh(crate = "borsh")] + struct XF; + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + ::add_definitions_recursively(definitions); + let definition = borsh::schema::Definition::Enum { + tag_width: 1, + variants: borsh::__private::maybestd::vec![ + (0, "A".to_string(), < XA > ::declaration()), (20, "B".to_string(), < XB + > ::declaration()), (20 + 1, "C".to_string(), < XC > ::declaration()), + (20 + 1 + 1, "D".to_string(), < XD > ::declaration()), (10, "E" + .to_string(), < XE > ::declaration()), (10 + 1, "F".to_string(), < XF > + ::declaration()) + ], + }; + borsh::schema::add_definition(Self::declaration(), definition, definitions); + } +} + diff --git a/borsh/tests/test_enum_discriminants.rs b/borsh/tests/test_enum_discriminants.rs index d8de987b6..2fd9473cb 100644 --- a/borsh/tests/test_enum_discriminants.rs +++ b/borsh/tests/test_enum_discriminants.rs @@ -8,6 +8,7 @@ extern crate alloc; use alloc::vec; use borsh::{from_slice, to_vec, BorshDeserialize, BorshSerialize}; + // sequence, no unit enums #[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Clone, Copy, Debug)] #[borsh(use_discriminant = true)] @@ -183,3 +184,131 @@ fn test_discriminant_serde() { assert_eq!(from_slice::(&data).unwrap(), values[index]); } } + +#[cfg(feature = "unstable__schema")] +mod schema { + #[cfg(not(feature = "std"))] + use alloc::{collections::BTreeMap, string::ToString, vec}; + + #[cfg(feature = "std")] + use std::collections::BTreeMap; + + macro_rules! map( + () => { BTreeMap::new() }; + { $($key:expr => $value:expr),+ } => { + { + let mut m = BTreeMap::new(); + $( + m.insert($key.to_string(), $value); + )+ + m + } + }; + ); + + use borsh::{ + schema::{Definition, Fields}, + BorshSchema, + }; + + #[allow(unused)] + #[derive(BorshSchema)] + #[borsh(use_discriminant = true)] + #[repr(i16)] + enum XY { + A, + B = 20, + C, + D(u32, u32), + E = 10, + F(u64), + } + + #[test] + fn test_schema_discriminant_no_unit_type() { + assert_eq!("XY".to_string(), XY::declaration()); + let mut defs = Default::default(); + XY::add_definitions_recursively(&mut defs); + assert_eq!( + map! { + "XY" => Definition::Enum { + tag_width: 1, + variants: vec![ + (0, "A".to_string(), "XYA".to_string()), + (20, "B".to_string(), "XYB".to_string()), + (21, "C".to_string(), "XYC".to_string()), + (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 }, + "XYC" => Definition::Struct{ fields: Fields::Empty }, + "XYD" => Definition::Struct{ fields: Fields::UnnamedFields( + vec!["u32".to_string(), "u32".to_string()] + )}, + "XYE" => Definition::Struct{ fields: Fields::Empty }, + "XYF" => Definition::Struct{ fields: Fields::UnnamedFields( + vec!["u64".to_string()] + + )}, + "u32" => Definition::Primitive(4), + "u64" => Definition::Primitive(8) + }, + defs + ); + } + + #[allow(unused)] + #[derive(BorshSchema)] + #[borsh(use_discriminant = false)] + #[repr(i16)] + enum XYNoDiscriminant { + A, + B = 20, + C, + D(u32, u32), + E = 10, + F(u64), + } + + #[test] + fn test_schema_discriminant_no_unit_type_no_use_discriminant() { + assert_eq!( + "XYNoDiscriminant".to_string(), + XYNoDiscriminant::declaration() + ); + let mut defs = Default::default(); + XYNoDiscriminant::add_definitions_recursively(&mut defs); + assert_eq!( + map! { + "XYNoDiscriminant" => Definition::Enum { + tag_width: 1, + variants: vec![ + (0, "A".to_string(), "XYNoDiscriminantA".to_string()), + (1, "B".to_string(), "XYNoDiscriminantB".to_string()), + (2, "C".to_string(), "XYNoDiscriminantC".to_string()), + (3, "D".to_string(), "XYNoDiscriminantD".to_string()), + (4, "E".to_string(), "XYNoDiscriminantE".to_string()), + (5, "F".to_string(), "XYNoDiscriminantF".to_string()) + ] + }, + "XYNoDiscriminantA" => Definition::Struct{ fields: Fields::Empty }, + "XYNoDiscriminantB" => Definition::Struct{ fields: Fields::Empty }, + "XYNoDiscriminantC" => Definition::Struct{ fields: Fields::Empty }, + "XYNoDiscriminantD" => Definition::Struct{ fields: Fields::UnnamedFields( + vec!["u32".to_string(), "u32".to_string()] + )}, + "XYNoDiscriminantE" => Definition::Struct{ fields: Fields::Empty }, + "XYNoDiscriminantF" => Definition::Struct{ fields: Fields::UnnamedFields( + vec!["u64".to_string()] + + )}, + "u32" => Definition::Primitive(4), + "u64" => Definition::Primitive(8) + }, + defs + ); + } +}