diff --git a/.github/test.sh b/.github/test.sh index 2fdbf58b9..6fea5344c 100755 --- a/.github/test.sh +++ b/.github/test.sh @@ -15,6 +15,8 @@ pushd borsh cargo test --no-run cargo test cargo test --features derive +cargo test --features derive,unstable__tokio +cargo test --features derive,unstable__async-std cargo test --features unstable__schema ########## features = ["ascii"] group cargo test --features ascii 'roundtrip::test_ascii_strings' diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 087983950..428f7c1d1 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -20,7 +20,7 @@ jobs: tests: strategy: matrix: - rust_version: [1.67, stable] + rust_version: [1.75.0, stable] runs-on: ubuntu-20.04 steps: diff --git a/Cargo.toml b/Cargo.toml index 985557bb4..9977a334f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,9 @@ [workspace] +resolver = "2" members = ["borsh", "borsh-derive", "fuzz/fuzz-run", "benchmarks"] [workspace.package] # shared version of all public crates in the workspace version = "1.5.5" -rust-version = "1.67.0" +edition = "2021" +rust-version = "1.75.0" diff --git a/benchmarks/Cargo.toml b/benchmarks/Cargo.toml index aad6202b9..c8d23aac1 100644 --- a/benchmarks/Cargo.toml +++ b/benchmarks/Cargo.toml @@ -3,7 +3,7 @@ name = "benchmarks" version.workspace = true rust-version.workspace = true authors = ["Near Inc "] -edition = "2018" +edition.workspace = true publish = false # This is somehow needed for command line arguments to work: https://github.com/bheisler/criterion.rs/issues/193#issuecomment-415740713 diff --git a/borsh-derive/Cargo.toml b/borsh-derive/Cargo.toml index 0bfa2ed8f..4596d6d42 100644 --- a/borsh-derive/Cargo.toml +++ b/borsh-derive/Cargo.toml @@ -3,7 +3,7 @@ name = "borsh-derive" version.workspace = true rust-version.workspace = true authors = ["Near Inc "] -edition = "2018" +edition.workspace = true license = "Apache-2.0" readme = "README.md" categories = ["encoding", "network-programming"] @@ -18,14 +18,14 @@ exclude = ["*.snap"] proc-macro = true [dependencies] -syn = { version = "2.0.81", features = ["full", "fold"] } +syn = { version = "2.0.96", features = ["full", "fold"] } proc-macro-crate = "3" -proc-macro2 = "1" -quote = "1" +proc-macro2 = "1.0" +quote = "1.0" once_cell = "1.18.0" [dev-dependencies] -syn = { version = "2.0.81", features = ["full", "fold", "parsing"] } +syn = { version = "2.0.96", features = ["parsing"] } prettyplease = "0.2.9" insta = "1.29.0" diff --git a/borsh-derive/src/internals/attributes/field/bounds.rs b/borsh-derive/src/internals/attributes/field/bounds.rs index d383b2327..261a354e5 100644 --- a/borsh-derive/src/internals/attributes/field/bounds.rs +++ b/borsh-derive/src/internals/attributes/field/bounds.rs @@ -1,9 +1,9 @@ use std::collections::BTreeMap; +use once_cell::sync::Lazy; use syn::{meta::ParseNestedMeta, WherePredicate}; use crate::internals::attributes::{parsing::parse_lit_into_vec, Symbol, DESERIALIZE, SERIALIZE}; -use once_cell::sync::Lazy; pub enum Variants { Serialize(Vec), diff --git a/borsh-derive/src/internals/attributes/field/mod.rs b/borsh-derive/src/internals/attributes/field/mod.rs index 0ff2555c1..739059c29 100644 --- a/borsh-derive/src/internals/attributes/field/mod.rs +++ b/borsh-derive/src/internals/attributes/field/mod.rs @@ -2,19 +2,18 @@ use std::collections::BTreeMap; use once_cell::sync::Lazy; use syn::{meta::ParseNestedMeta, Attribute, WherePredicate}; +#[cfg(feature = "schema")] +use { + super::schema_keys::{PARAMS, SCHEMA, WITH_FUNCS}, + schema::SCHEMA_FIELD_PARSE_MAP, +}; use self::bounds::BOUNDS_FIELD_PARSE_MAP; - use super::{ get_one_attribute, parsing::{attr_get_by_symbol_keys, meta_get_by_symbol_keys, parse_lit_into}, - BoundType, Symbol, BORSH, BOUND, DESERIALIZE_WITH, SERIALIZE_WITH, SKIP, -}; - -#[cfg(feature = "schema")] -use { - super::schema_keys::{PARAMS, SCHEMA, WITH_FUNCS}, - schema::SCHEMA_FIELD_PARSE_MAP, + BoundType, Symbol, ASYNC_BOUND, BORSH, BOUND, DESERIALIZE_WITH, DESERIALIZE_WITH_ASYNC, + SERIALIZE_WITH, SERIALIZE_WITH_ASYNC, SKIP, }; pub mod bounds; @@ -25,6 +24,8 @@ enum Variants { Bounds(bounds::Bounds), SerializeWith(syn::ExprPath), DeserializeWith(syn::ExprPath), + SerializeWithAsync(syn::ExprPath), + DeserializeWithAsync(syn::ExprPath), Skip(()), #[cfg(feature = "schema")] Schema(schema::Attributes), @@ -42,6 +43,12 @@ static BORSH_FIELD_PARSE_MAP: Lazy>> = Lazy::new(| Ok(Variants::Bounds(bounds_attributes)) }); + let f_async_bounds: Box = Box::new(|_attr_name, _meta_item_name, meta| { + let map_result = meta_get_by_symbol_keys(ASYNC_BOUND, meta, &BOUNDS_FIELD_PARSE_MAP)?; + let bounds_attributes: bounds::Bounds = map_result.into(); + Ok(Variants::Bounds(bounds_attributes)) + }); + let f_serialize_with: Box = Box::new(|attr_name, meta_item_name, meta| { parse_lit_into::(attr_name, meta_item_name, meta) .map(Variants::SerializeWith) @@ -52,6 +59,16 @@ static BORSH_FIELD_PARSE_MAP: Lazy>> = Lazy::new(| .map(Variants::DeserializeWith) }); + let f_serialize_with_async: Box = Box::new(|attr_name, meta_item_name, meta| { + parse_lit_into::(attr_name, meta_item_name, meta) + .map(Variants::SerializeWithAsync) + }); + + let f_deserialize_with_async: Box = Box::new(|attr_name, meta_item_name, meta| { + parse_lit_into::(attr_name, meta_item_name, meta) + .map(Variants::DeserializeWithAsync) + }); + #[cfg(feature = "schema")] let f_schema: Box = Box::new(|_attr_name, _meta_item_name, meta| { let map_result = meta_get_by_symbol_keys(SCHEMA, meta, &SCHEMA_FIELD_PARSE_MAP)?; @@ -62,8 +79,11 @@ static BORSH_FIELD_PARSE_MAP: Lazy>> = Lazy::new(| let f_skip: Box = Box::new(|_attr_name, _meta_item_name, _meta| Ok(Variants::Skip(()))); m.insert(BOUND, f_bounds); + m.insert(ASYNC_BOUND, f_async_bounds); m.insert(SERIALIZE_WITH, f_serialize_with); m.insert(DESERIALIZE_WITH, f_deserialize_with); + m.insert(SERIALIZE_WITH_ASYNC, f_serialize_with_async); + m.insert(DESERIALIZE_WITH_ASYNC, f_deserialize_with_async); m.insert(SKIP, f_skip); #[cfg(feature = "schema")] m.insert(SCHEMA, f_schema); @@ -73,8 +93,11 @@ static BORSH_FIELD_PARSE_MAP: Lazy>> = Lazy::new(| #[derive(Default, Clone)] pub(crate) struct Attributes { pub bounds: Option, + pub async_bounds: Option, pub serialize_with: Option, pub deserialize_with: Option, + pub serialize_with_async: Option, + pub deserialize_with_async: Option, pub skip: bool, #[cfg(feature = "schema")] pub schema: Option, @@ -83,14 +106,23 @@ pub(crate) struct Attributes { impl From> for Attributes { fn from(mut map: BTreeMap) -> Self { let bounds = map.remove(&BOUND); + let async_bounds = map.remove(&ASYNC_BOUND); let serialize_with = map.remove(&SERIALIZE_WITH); let deserialize_with = map.remove(&DESERIALIZE_WITH); + let serialize_with_async = map.remove(&SERIALIZE_WITH_ASYNC); + let deserialize_with_async = map.remove(&DESERIALIZE_WITH_ASYNC); let skip = map.remove(&SKIP); + let bounds = bounds.map(|variant| match variant { Variants::Bounds(bounds) => bounds, _ => unreachable!("only one enum variant is expected to correspond to given map key"), }); + let async_bounds = async_bounds.map(|variant| match variant { + Variants::Bounds(bounds) => bounds, + _ => unreachable!("only one enum variant is expected to correspond to given map key"), + }); + let serialize_with = serialize_with.map(|variant| match variant { Variants::SerializeWith(serialize_with) => serialize_with, _ => unreachable!("only one enum variant is expected to correspond to given map key"), @@ -101,6 +133,16 @@ impl From> for Attributes { _ => unreachable!("only one enum variant is expected to correspond to given map key"), }); + let serialize_with_async = serialize_with_async.map(|variant| match variant { + Variants::SerializeWithAsync(serialize_with_async) => serialize_with_async, + _ => unreachable!("only one enum variant is expected to correspond to given map key"), + }); + + let deserialize_with_async = deserialize_with_async.map(|variant| match variant { + Variants::DeserializeWithAsync(deserialize_with_async) => deserialize_with_async, + _ => unreachable!("only one enum variant is expected to correspond to given map key"), + }); + let skip = skip.map(|variant| match variant { Variants::Skip(skip) => skip, _ => unreachable!("only one enum variant is expected to correspond to given map key"), @@ -116,10 +158,14 @@ impl From> for Attributes { } }) }; + Self { bounds, + async_bounds, serialize_with, deserialize_with, + serialize_with_async, + deserialize_with_async, skip: skip.is_some(), #[cfg(feature = "schema")] schema, @@ -136,12 +182,21 @@ pub(crate) fn filter_attrs( impl Attributes { fn check(&self, attr: &Attribute) -> Result<(), syn::Error> { - if self.skip && (self.serialize_with.is_some() || self.deserialize_with.is_some()) { + if self.skip + && (self.serialize_with.is_some() + || self.deserialize_with.is_some() + || self.serialize_with_async.is_some() + || self.deserialize_with_async.is_some()) + { return Err(syn::Error::new_spanned( attr, format!( - "`{}` cannot be used at the same time as `{}` or `{}`", - SKIP.0, SERIALIZE_WITH.0, DESERIALIZE_WITH.0 + "`{}` cannot be used at the same time as `{}`, `{}`, `{}` or `{}`", + SKIP.name, + SERIALIZE_WITH.name, + DESERIALIZE_WITH.name, + SERIALIZE_WITH_ASYNC.name, + DESERIALIZE_WITH_ASYNC.name ), )); } @@ -151,6 +206,7 @@ impl Attributes { Ok(()) } + pub(crate) fn parse(attrs: &[Attribute]) -> Result { let borsh = get_one_attribute(attrs)?; @@ -164,11 +220,17 @@ impl Attributes { Ok(result) } + pub(crate) fn needs_bounds_derive(&self, ty: BoundType) -> bool { let predicates = self.get_bounds(ty); predicates.is_none() } + pub(crate) fn needs_async_bounds_derive(&self, ty: BoundType) -> bool { + let predicates = self.get_async_bounds(ty); + predicates.is_none() + } + fn get_bounds(&self, ty: BoundType) -> Option> { let bounds = self.bounds.as_ref(); bounds.and_then(|bounds| match ty { @@ -176,10 +238,24 @@ impl Attributes { BoundType::Deserialize => bounds.deserialize.clone(), }) } + + fn get_async_bounds(&self, ty: BoundType) -> Option> { + let bounds = self.async_bounds.as_ref(); + bounds.and_then(|bounds| match ty { + BoundType::Serialize => bounds.serialize.clone(), + BoundType::Deserialize => bounds.deserialize.clone(), + }) + } + pub(crate) fn collect_bounds(&self, ty: BoundType) -> Vec { let predicates = self.get_bounds(ty); predicates.unwrap_or_default() } + + pub(crate) fn collect_async_bounds(&self, ty: BoundType) -> Vec { + let predicates = self.get_async_bounds(ty); + predicates.unwrap_or_default() + } } #[cfg(feature = "schema")] @@ -191,7 +267,7 @@ impl Attributes { attr, format!( "`{}` cannot be used at the same time as `{}({})`", - SKIP.0, SCHEMA.0, PARAMS.1 + SKIP.name, SCHEMA.name, PARAMS.expected ), )); } @@ -201,7 +277,7 @@ impl Attributes { attr, format!( "`{}` cannot be used at the same time as `{}({})`", - SKIP.0, SCHEMA.0, WITH_FUNCS.1 + SKIP.name, SCHEMA.name, WITH_FUNCS.expected ), )); } @@ -239,25 +315,31 @@ impl Attributes { #[cfg(test)] mod tests { - use quote::quote; - use syn::{Attribute, ItemStruct}; - - fn parse_bounds(attrs: &[Attribute]) -> Result, syn::Error> { - // #[borsh(bound(serialize = "...", deserialize = "..."))] - let borsh_attrs = Attributes::parse(attrs)?; - Ok(borsh_attrs.bounds) - } + use syn::{parse_quote, Attribute, ItemStruct}; + use super::{bounds, Attributes}; use crate::internals::test_helpers::{ debug_print_tokenizable, debug_print_vec_of_tokenizable, local_insta_assert_debug_snapshot, local_insta_assert_snapshot, }; - use super::{bounds, Attributes}; + struct ParsedBounds { + common: Option, + r#async: Option, + } + + fn parse_bounds(attrs: &[Attribute]) -> Result { + // #[borsh(bound(serialize = "...", deserialize = "..."), async_bound(serialize = "...", deserialize = "..."))] + let borsh_attrs = Attributes::parse(attrs)?; + Ok(ParsedBounds { + common: borsh_attrs.bounds, + r#async: borsh_attrs.async_bounds, + }) + } #[test] fn test_reject_multiple_borsh_attrs() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A { #[borsh(skip)] #[borsh(bound(deserialize = "K: Hash + Ord, @@ -268,8 +350,7 @@ mod tests { x: u64, y: String, } - }) - .unwrap(); + }; let first_field = &item_struct.fields.into_iter().collect::>()[0]; let err = match Attributes::parse(&first_field.attrs) { @@ -281,7 +362,7 @@ mod tests { #[test] fn test_bounds_parsing1() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A { #[borsh(bound(deserialize = "K: Hash + Ord, V: Eq + Ord", @@ -291,18 +372,17 @@ mod tests { x: u64, y: String, } - }) - .unwrap(); + }; let first_field = &item_struct.fields.into_iter().collect::>()[0]; - let attrs = parse_bounds(&first_field.attrs).unwrap().unwrap(); - local_insta_assert_snapshot!(debug_print_vec_of_tokenizable(attrs.serialize.clone())); + let attrs = parse_bounds(&first_field.attrs).unwrap().common.unwrap(); + local_insta_assert_snapshot!(debug_print_vec_of_tokenizable(attrs.serialize)); local_insta_assert_snapshot!(debug_print_vec_of_tokenizable(attrs.deserialize)); } #[test] fn test_bounds_parsing2() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A { #[borsh(bound(deserialize = "K: Hash + Eq + borsh::de::BorshDeserialize, V: borsh::de::BorshDeserialize", @@ -312,18 +392,17 @@ mod tests { x: u64, y: String, } - }) - .unwrap(); + }; let first_field = &item_struct.fields.into_iter().collect::>()[0]; - let attrs = parse_bounds(&first_field.attrs).unwrap().unwrap(); - local_insta_assert_snapshot!(debug_print_vec_of_tokenizable(attrs.serialize.clone())); + let attrs = parse_bounds(&first_field.attrs).unwrap().common.unwrap(); + local_insta_assert_snapshot!(debug_print_vec_of_tokenizable(attrs.serialize)); local_insta_assert_snapshot!(debug_print_vec_of_tokenizable(attrs.deserialize)); } #[test] fn test_bounds_parsing3() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A { #[borsh(bound(deserialize = "K: Hash + Eq + borsh::de::BorshDeserialize, V: borsh::de::BorshDeserialize", @@ -332,42 +411,39 @@ mod tests { x: u64, y: String, } - }) - .unwrap(); + }; let first_field = &item_struct.fields.into_iter().collect::>()[0]; - let attrs = parse_bounds(&first_field.attrs).unwrap().unwrap(); + let attrs = parse_bounds(&first_field.attrs).unwrap().common.unwrap(); assert_eq!(attrs.serialize.as_ref().unwrap().len(), 0); local_insta_assert_snapshot!(debug_print_vec_of_tokenizable(attrs.deserialize)); } #[test] fn test_bounds_parsing4() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A { #[borsh(bound(deserialize = "K: Hash"))] x: u64, y: String, } - }) - .unwrap(); + }; let first_field = &item_struct.fields.into_iter().collect::>()[0]; - let attrs = parse_bounds(&first_field.attrs).unwrap().unwrap(); + let attrs = parse_bounds(&first_field.attrs).unwrap().common.unwrap(); assert!(attrs.serialize.is_none()); local_insta_assert_snapshot!(debug_print_vec_of_tokenizable(attrs.deserialize)); } #[test] fn test_bounds_parsing_error() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A { #[borsh(bound(deser = "K: Hash"))] x: u64, y: String, } - }) - .unwrap(); + }; let first_field = &item_struct.fields.into_iter().collect::>()[0]; let err = match parse_bounds(&first_field.attrs) { @@ -379,14 +455,13 @@ mod tests { #[test] fn test_bounds_parsing_error2() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A { #[borsh(bound(deserialize = "K Hash"))] x: u64, y: String, } - }) - .unwrap(); + }; let first_field = &item_struct.fields.into_iter().collect::>()[0]; let err = match parse_bounds(&first_field.attrs) { @@ -398,14 +473,148 @@ mod tests { #[test] fn test_bounds_parsing_error3() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A { #[borsh(bound(deserialize = 42))] x: u64, y: String, } - }) - .unwrap(); + }; + + let first_field = &item_struct.fields.into_iter().collect::>()[0]; + let err = match parse_bounds(&first_field.attrs) { + Ok(..) => unreachable!("expecting error here"), + Err(err) => err, + }; + local_insta_assert_debug_snapshot!(err); + } + + #[test] + fn test_async_bounds_parsing1() { + let item_struct: ItemStruct = parse_quote! { + struct A { + #[borsh(async_bound( + deserialize = + "K: Hash + Ord, + V: Eq + Ord", + serialize = + "K: Hash + Eq + Ord, + V: Ord" + ))] + x: u64, + y: String, + } + }; + + let first_field = &item_struct.fields.into_iter().collect::>()[0]; + let attrs = parse_bounds(&first_field.attrs).unwrap().r#async.unwrap(); + local_insta_assert_snapshot!(debug_print_vec_of_tokenizable(attrs.serialize)); + local_insta_assert_snapshot!(debug_print_vec_of_tokenizable(attrs.deserialize)); + } + + #[test] + fn test_async_bounds_parsing2() { + let item_struct: ItemStruct = parse_quote! { + struct A { + #[borsh(async_bound(deserialize = + "K: Hash + Eq + borsh::de::BorshDeserializeAsync, + V: borsh::de::BorshDeserializeAsync", + serialize = + "K: Hash + Eq + borsh::ser::BorshSerializeAsync, + V: borsh::ser::BorshSerializeAsync" + ))] + x: u64, + y: String, + } + }; + + let first_field = &item_struct.fields.into_iter().collect::>()[0]; + let attrs = parse_bounds(&first_field.attrs).unwrap().r#async.unwrap(); + local_insta_assert_snapshot!(debug_print_vec_of_tokenizable(attrs.serialize)); + local_insta_assert_snapshot!(debug_print_vec_of_tokenizable(attrs.deserialize)); + } + + #[test] + fn test_async_bounds_parsing3() { + let item_struct: ItemStruct = parse_quote! { + struct A { + #[borsh(async_bound(deserialize = + "K: Hash + Eq + borsh::de::BorshDeserializeAsync, + V: borsh::de::BorshDeserializeAsync", + serialize = "" + ))] + x: u64, + y: String, + } + }; + + let first_field = &item_struct.fields.into_iter().collect::>()[0]; + let attrs = parse_bounds(&first_field.attrs).unwrap().r#async.unwrap(); + assert_eq!(attrs.serialize.as_ref().unwrap().len(), 0); + local_insta_assert_snapshot!(debug_print_vec_of_tokenizable(attrs.deserialize)); + } + + #[test] + fn test_async_bounds_parsing4() { + let item_struct: ItemStruct = parse_quote! { + struct A { + #[borsh(async_bound(deserialize = "K: Hash"))] + x: u64, + y: String, + } + }; + + let first_field = &item_struct.fields.into_iter().collect::>()[0]; + let attrs = parse_bounds(&first_field.attrs).unwrap().r#async.unwrap(); + assert!(attrs.serialize.is_none()); + local_insta_assert_snapshot!(debug_print_vec_of_tokenizable(attrs.deserialize)); + } + + #[test] + fn test_async_bounds_parsing_error() { + let item_struct: ItemStruct = parse_quote! { + struct A { + #[borsh(async_bound(deser = "K: Hash"))] + x: u64, + y: String, + } + }; + + let first_field = &item_struct.fields.into_iter().collect::>()[0]; + let err = match parse_bounds(&first_field.attrs) { + Ok(..) => unreachable!("expecting error here"), + Err(err) => err, + }; + local_insta_assert_debug_snapshot!(err); + } + + #[test] + fn test_async_bounds_parsing_error2() { + let item_struct: ItemStruct = parse_quote! { + struct A { + #[borsh(async_bound(deserialize = "K Hash"))] + x: u64, + y: String, + } + }; + + let first_field = &item_struct.fields.into_iter().collect::>()[0]; + let err = match parse_bounds(&first_field.attrs) { + Ok(..) => unreachable!("expecting error here"), + Err(err) => err, + }; + local_insta_assert_debug_snapshot!(err); + } + + #[test] + fn test_async_bounds_parsing_error3() { + let item_struct: ItemStruct = parse_quote! { + struct A { + #[borsh(async_bound(deserialize = 42))] + x: u64, + y: String, + } + }; let first_field = &item_struct.fields.into_iter().collect::>()[0]; let err = match parse_bounds(&first_field.attrs) { @@ -417,7 +626,7 @@ mod tests { #[test] fn test_ser_de_with_parsing1() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A { #[borsh( serialize_with = "third_party_impl::serialize_third_party", @@ -426,39 +635,57 @@ mod tests { x: u64, y: String, } - }) - .unwrap(); + }; let first_field = &item_struct.fields.into_iter().collect::>()[0]; let attrs = Attributes::parse(&first_field.attrs).unwrap(); local_insta_assert_snapshot!(debug_print_tokenizable(attrs.serialize_with.as_ref())); local_insta_assert_snapshot!(debug_print_tokenizable(attrs.deserialize_with)); } + + #[test] + fn test_async_ser_de_with_parsing1() { + let item_struct: ItemStruct = parse_quote! { + struct A { + #[borsh( + serialize_with_async = "third_party_impl::serialize_third_party", + deserialize_with_async = "third_party_impl::deserialize_third_party", + )] + x: u64, + y: String, + } + }; + + let first_field = &item_struct.fields.into_iter().collect::>()[0]; + let attrs = Attributes::parse(&first_field.attrs).unwrap(); + local_insta_assert_snapshot!(debug_print_tokenizable(attrs.serialize_with_async.as_ref())); + local_insta_assert_snapshot!(debug_print_tokenizable(attrs.deserialize_with_async)); + } + #[test] fn test_borsh_skip() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A { #[borsh(skip)] x: u64, y: String, } - }) - .unwrap(); + }; let first_field = &item_struct.fields.into_iter().collect::>()[0]; let result = Attributes::parse(&first_field.attrs).unwrap(); assert!(result.skip); } + #[test] fn test_borsh_no_skip() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A { x: u64, y: String, } - }) - .unwrap(); + }; let first_field = &item_struct.fields.into_iter().collect::>()[0]; @@ -470,6 +697,9 @@ mod tests { #[cfg(feature = "schema")] #[cfg(test)] mod tests_schema { + use syn::{parse_quote, Attribute, ItemStruct}; + + use super::schema; use crate::internals::{ attributes::field::Attributes, test_helpers::{ @@ -478,10 +708,6 @@ mod tests_schema { }, }; - use quote::quote; - use syn::{Attribute, ItemStruct}; - - use super::schema; fn parse_schema_attrs(attrs: &[Attribute]) -> Result, syn::Error> { // #[borsh(schema(params = "..."))] let borsh_attrs = Attributes::parse(attrs)?; @@ -490,7 +716,7 @@ mod tests_schema { #[test] fn test_root_bounds_and_params_combined() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A { #[borsh( serialize_with = "third_party_impl::serialize_third_party", @@ -500,8 +726,7 @@ mod tests_schema { x: u64, y: String, } - }) - .unwrap(); + }; let first_field = &item_struct.fields.into_iter().collect::>()[0]; @@ -511,13 +736,13 @@ mod tests_schema { local_insta_assert_snapshot!(debug_print_vec_of_tokenizable(bounds.deserialize)); assert!(attrs.deserialize_with.is_none()); let schema = attrs.schema.clone().unwrap(); - local_insta_assert_snapshot!(debug_print_vec_of_tokenizable(schema.params.clone())); + local_insta_assert_snapshot!(debug_print_vec_of_tokenizable(schema.params)); local_insta_assert_snapshot!(debug_print_tokenizable(attrs.serialize_with)); } #[test] fn test_schema_params_parsing1() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct Parametrized where T: TraitName, @@ -528,16 +753,16 @@ mod tests_schema { field: ::Associated, another: V, } - }) - .unwrap(); + }; let first_field = &item_struct.fields.into_iter().collect::>()[0]; let schema_attrs = parse_schema_attrs(&first_field.attrs).unwrap(); local_insta_assert_snapshot!(debug_print_vec_of_tokenizable(schema_attrs.unwrap().params)); } + #[test] fn test_schema_params_parsing_error() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct Parametrized where T: TraitName, @@ -548,8 +773,7 @@ mod tests_schema { field: ::Associated, another: V, } - }) - .unwrap(); + }; let first_field = &item_struct.fields.into_iter().collect::>()[0]; let err = match parse_schema_attrs(&first_field.attrs) { @@ -561,7 +785,7 @@ mod tests_schema { #[test] fn test_schema_params_parsing_error2() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct Parametrized where T: TraitName, @@ -572,8 +796,7 @@ mod tests_schema { field: ::Associated, another: V, } - }) - .unwrap(); + }; let first_field = &item_struct.fields.into_iter().collect::>()[0]; let err = match parse_schema_attrs(&first_field.attrs) { @@ -585,7 +808,7 @@ mod tests_schema { #[test] fn test_schema_params_parsing2() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct Parametrized where T: TraitName, @@ -596,16 +819,16 @@ mod tests_schema { field: ::Associated, another: V, } - }) - .unwrap(); + }; let first_field = &item_struct.fields.into_iter().collect::>()[0]; let schema_attrs = parse_schema_attrs(&first_field.attrs).unwrap(); local_insta_assert_snapshot!(debug_print_vec_of_tokenizable(schema_attrs.unwrap().params)); } + #[test] fn test_schema_params_parsing3() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct Parametrized where T: TraitName, @@ -614,8 +837,7 @@ mod tests_schema { field: ::Associated, another: V, } - }) - .unwrap(); + }; let first_field = &item_struct.fields.into_iter().collect::>()[0]; let schema_attrs = parse_schema_attrs(&first_field.attrs).unwrap(); @@ -624,7 +846,7 @@ mod tests_schema { #[test] fn test_schema_params_parsing4() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct Parametrized where T: TraitName, @@ -632,8 +854,7 @@ mod tests_schema { field: ::Associated, another: V, } - }) - .unwrap(); + }; let first_field = &item_struct.fields.into_iter().collect::>()[0]; let schema_attrs = parse_schema_attrs(&first_field.attrs).unwrap(); @@ -642,7 +863,7 @@ mod tests_schema { #[test] fn test_schema_with_funcs_parsing() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A { #[borsh(schema(with_funcs( declaration = "third_party_impl::declaration::", @@ -651,22 +872,21 @@ mod tests_schema { x: u64, y: String, } - }) - .unwrap(); + }; let first_field = &item_struct.fields.into_iter().collect::>()[0]; let attrs = Attributes::parse(&first_field.attrs).unwrap(); let schema = attrs.schema.unwrap(); let with_funcs = schema.with_funcs.unwrap(); - local_insta_assert_snapshot!(debug_print_tokenizable(with_funcs.declaration.clone())); + local_insta_assert_snapshot!(debug_print_tokenizable(with_funcs.declaration)); local_insta_assert_snapshot!(debug_print_tokenizable(with_funcs.definitions)); } // both `declaration` and `definitions` have to be specified #[test] fn test_schema_with_funcs_parsing_error() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A { #[borsh(schema(with_funcs( declaration = "third_party_impl::declaration::" @@ -674,8 +894,7 @@ mod tests_schema { x: u64, y: String, } - }) - .unwrap(); + }; let first_field = &item_struct.fields.into_iter().collect::>()[0]; let attrs = Attributes::parse(&first_field.attrs); @@ -689,14 +908,13 @@ mod tests_schema { #[test] fn test_root_error() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A { #[borsh(boons)] x: u64, y: String, } - }) - .unwrap(); + }; let first_field = &item_struct.fields.into_iter().collect::>()[0]; let err = match Attributes::parse(&first_field.attrs) { @@ -708,7 +926,7 @@ mod tests_schema { #[test] fn test_root_bounds_and_wrong_key_combined() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A { #[borsh(bound(deserialize = "K: Hash"), schhema(params = "T => ::Associated, V => Vec") @@ -716,8 +934,7 @@ mod tests_schema { x: u64, y: String, } - }) - .unwrap(); + }; let first_field = &item_struct.fields.into_iter().collect::>()[0]; diff --git a/borsh-derive/src/internals/attributes/field/schema.rs b/borsh-derive/src/internals/attributes/field/schema.rs index 40ebec39d..32210c7b1 100644 --- a/borsh-derive/src/internals/attributes/field/schema.rs +++ b/borsh-derive/src/internals/attributes/field/schema.rs @@ -1,10 +1,5 @@ use std::collections::BTreeMap; -use crate::internals::attributes::{ - parsing::{meta_get_by_symbol_keys, parse_lit_into_vec}, - schema_keys::{DECLARATION, DEFINITIONS, PARAMS, WITH_FUNCS}, - Symbol, -}; use once_cell::sync::Lazy; use quote::ToTokens; use syn::{ @@ -14,6 +9,11 @@ use syn::{ }; use self::with_funcs::{WithFuncs, WITH_FUNCS_FIELD_PARSE_MAP}; +use crate::internals::attributes::{ + parsing::{meta_get_by_symbol_keys, parse_lit_into_vec}, + schema_keys::{DECLARATION, DEFINITIONS, PARAMS, WITH_FUNCS}, + Symbol, +}; pub mod with_funcs; @@ -43,7 +43,7 @@ pub static SCHEMA_FIELD_PARSE_MAP: Lazy>> = Lazy:: &meta.path, format!( "both `{}` and `{}` have to be specified at the same time", - DECLARATION.1, DEFINITIONS.1, + DECLARATION.expected, DEFINITIONS.expected, ), )); } diff --git a/borsh-derive/src/internals/attributes/field/snapshots/async_bounds_parsing1-2.snap b/borsh-derive/src/internals/attributes/field/snapshots/async_bounds_parsing1-2.snap new file mode 100644 index 000000000..75ee80942 --- /dev/null +++ b/borsh-derive/src/internals/attributes/field/snapshots/async_bounds_parsing1-2.snap @@ -0,0 +1,6 @@ +--- +source: borsh-derive/src/internals/attributes/field/mod.rs +expression: debug_print_vec_of_tokenizable(attrs.deserialize) +--- +K : Hash + Ord +V : Eq + Ord diff --git a/borsh-derive/src/internals/attributes/field/snapshots/async_bounds_parsing1.snap b/borsh-derive/src/internals/attributes/field/snapshots/async_bounds_parsing1.snap new file mode 100644 index 000000000..182ab0ab3 --- /dev/null +++ b/borsh-derive/src/internals/attributes/field/snapshots/async_bounds_parsing1.snap @@ -0,0 +1,6 @@ +--- +source: borsh-derive/src/internals/attributes/field/mod.rs +expression: debug_print_vec_of_tokenizable(attrs.serialize) +--- +K : Hash + Eq + Ord +V : Ord diff --git a/borsh-derive/src/internals/attributes/field/snapshots/async_bounds_parsing2-2.snap b/borsh-derive/src/internals/attributes/field/snapshots/async_bounds_parsing2-2.snap new file mode 100644 index 000000000..d3c7c7d51 --- /dev/null +++ b/borsh-derive/src/internals/attributes/field/snapshots/async_bounds_parsing2-2.snap @@ -0,0 +1,6 @@ +--- +source: borsh-derive/src/internals/attributes/field/mod.rs +expression: debug_print_vec_of_tokenizable(attrs.deserialize) +--- +K : Hash + Eq + borsh :: de :: BorshDeserializeAsync +V : borsh :: de :: BorshDeserializeAsync diff --git a/borsh-derive/src/internals/attributes/field/snapshots/async_bounds_parsing2.snap b/borsh-derive/src/internals/attributes/field/snapshots/async_bounds_parsing2.snap new file mode 100644 index 000000000..e27068395 --- /dev/null +++ b/borsh-derive/src/internals/attributes/field/snapshots/async_bounds_parsing2.snap @@ -0,0 +1,6 @@ +--- +source: borsh-derive/src/internals/attributes/field/mod.rs +expression: debug_print_vec_of_tokenizable(attrs.serialize) +--- +K : Hash + Eq + borsh :: ser :: BorshSerializeAsync +V : borsh :: ser :: BorshSerializeAsync diff --git a/borsh-derive/src/internals/attributes/field/snapshots/async_bounds_parsing3.snap b/borsh-derive/src/internals/attributes/field/snapshots/async_bounds_parsing3.snap new file mode 100644 index 000000000..d3c7c7d51 --- /dev/null +++ b/borsh-derive/src/internals/attributes/field/snapshots/async_bounds_parsing3.snap @@ -0,0 +1,6 @@ +--- +source: borsh-derive/src/internals/attributes/field/mod.rs +expression: debug_print_vec_of_tokenizable(attrs.deserialize) +--- +K : Hash + Eq + borsh :: de :: BorshDeserializeAsync +V : borsh :: de :: BorshDeserializeAsync diff --git a/borsh-derive/src/internals/attributes/field/snapshots/async_bounds_parsing4.snap b/borsh-derive/src/internals/attributes/field/snapshots/async_bounds_parsing4.snap new file mode 100644 index 000000000..a68309c1b --- /dev/null +++ b/borsh-derive/src/internals/attributes/field/snapshots/async_bounds_parsing4.snap @@ -0,0 +1,5 @@ +--- +source: borsh-derive/src/internals/attributes/field/mod.rs +expression: debug_print_vec_of_tokenizable(attrs.deserialize) +--- +K : Hash diff --git a/borsh-derive/src/internals/attributes/field/snapshots/async_bounds_parsing_error.snap b/borsh-derive/src/internals/attributes/field/snapshots/async_bounds_parsing_error.snap new file mode 100644 index 000000000..da1748fd0 --- /dev/null +++ b/borsh-derive/src/internals/attributes/field/snapshots/async_bounds_parsing_error.snap @@ -0,0 +1,7 @@ +--- +source: borsh-derive/src/internals/attributes/field/mod.rs +expression: err +--- +Error( + "malformed async_bound attribute, expected `async_bound(deserialize = ..., serialize = ...)`", +) diff --git a/borsh-derive/src/internals/attributes/field/snapshots/async_bounds_parsing_error2.snap b/borsh-derive/src/internals/attributes/field/snapshots/async_bounds_parsing_error2.snap new file mode 100644 index 000000000..fc006afe2 --- /dev/null +++ b/borsh-derive/src/internals/attributes/field/snapshots/async_bounds_parsing_error2.snap @@ -0,0 +1,7 @@ +--- +source: borsh-derive/src/internals/attributes/field/mod.rs +expression: err +--- +Error( + "expected `:`", +) diff --git a/borsh-derive/src/internals/attributes/field/snapshots/async_bounds_parsing_error3.snap b/borsh-derive/src/internals/attributes/field/snapshots/async_bounds_parsing_error3.snap new file mode 100644 index 000000000..36e9a0b74 --- /dev/null +++ b/borsh-derive/src/internals/attributes/field/snapshots/async_bounds_parsing_error3.snap @@ -0,0 +1,7 @@ +--- +source: borsh-derive/src/internals/attributes/field/mod.rs +expression: err +--- +Error( + "expected borsh async_bound attribute to be a string: `deserialize = \"...\"`", +) diff --git a/borsh-derive/src/internals/attributes/field/snapshots/async_ser_de_with_parsing1-2.snap b/borsh-derive/src/internals/attributes/field/snapshots/async_ser_de_with_parsing1-2.snap new file mode 100644 index 000000000..2ca40b4fb --- /dev/null +++ b/borsh-derive/src/internals/attributes/field/snapshots/async_ser_de_with_parsing1-2.snap @@ -0,0 +1,5 @@ +--- +source: borsh-derive/src/internals/attributes/field/mod.rs +expression: debug_print_tokenizable(attrs.deserialize_with_async) +--- +third_party_impl :: deserialize_third_party diff --git a/borsh-derive/src/internals/attributes/field/snapshots/async_ser_de_with_parsing1.snap b/borsh-derive/src/internals/attributes/field/snapshots/async_ser_de_with_parsing1.snap new file mode 100644 index 000000000..39366dd42 --- /dev/null +++ b/borsh-derive/src/internals/attributes/field/snapshots/async_ser_de_with_parsing1.snap @@ -0,0 +1,5 @@ +--- +source: borsh-derive/src/internals/attributes/field/mod.rs +expression: debug_print_tokenizable(attrs.serialize_with_async.as_ref()) +--- +third_party_impl :: serialize_third_party diff --git a/borsh-derive/src/internals/attributes/field/snapshots/root_bounds_and_wrong_key_combined.snap b/borsh-derive/src/internals/attributes/field/snapshots/root_bounds_and_wrong_key_combined.snap index 110f4f29f..f62d0826e 100644 --- a/borsh-derive/src/internals/attributes/field/snapshots/root_bounds_and_wrong_key_combined.snap +++ b/borsh-derive/src/internals/attributes/field/snapshots/root_bounds_and_wrong_key_combined.snap @@ -3,5 +3,5 @@ source: borsh-derive/src/internals/attributes/field/mod.rs expression: err --- Error( - "malformed borsh attribute, expected `borsh(bound(...), deserialize_with = ..., schema(...), serialize_with = ..., skip)`", + "malformed borsh attribute, expected `borsh(async_bound(...), bound(...), deserialize_with = ..., deserialize_with_async = ..., schema(...), serialize_with = ..., serialize_with_async = ..., skip)`", ) diff --git a/borsh-derive/src/internals/attributes/field/snapshots/root_error.snap b/borsh-derive/src/internals/attributes/field/snapshots/root_error.snap index 110f4f29f..f62d0826e 100644 --- a/borsh-derive/src/internals/attributes/field/snapshots/root_error.snap +++ b/borsh-derive/src/internals/attributes/field/snapshots/root_error.snap @@ -3,5 +3,5 @@ source: borsh-derive/src/internals/attributes/field/mod.rs expression: err --- Error( - "malformed borsh attribute, expected `borsh(bound(...), deserialize_with = ..., schema(...), serialize_with = ..., skip)`", + "malformed borsh attribute, expected `borsh(async_bound(...), bound(...), deserialize_with = ..., deserialize_with_async = ..., schema(...), serialize_with = ..., serialize_with_async = ..., skip)`", ) diff --git a/borsh-derive/src/internals/attributes/item/mod.rs b/borsh-derive/src/internals/attributes/item/mod.rs index ff3551486..8d25d7472 100644 --- a/borsh-derive/src/internals/attributes/item/mod.rs +++ b/borsh-derive/src/internals/attributes/item/mod.rs @@ -1,8 +1,8 @@ -use crate::internals::attributes::{BORSH, CRATE, INIT, USE_DISCRIMINANT}; use quote::ToTokens; use syn::{spanned::Spanned, Attribute, DeriveInput, Error, Expr, ItemEnum, Path}; use super::{get_one_attribute, parsing}; +use crate::internals::attributes::{BORSH, CRATE, INIT, USE_DISCRIMINANT}; pub fn check_attributes(derive_input: &DeriveInput) -> Result<(), Error> { let borsh = get_one_attribute(&derive_input.attrs)?; @@ -10,7 +10,7 @@ pub fn check_attributes(derive_input: &DeriveInput) -> Result<(), Error> { if let Some(attr) = borsh { attr.parse_nested_meta(|meta| { if meta.path != USE_DISCRIMINANT && meta.path != INIT && meta.path != CRATE { - return Err(syn::Error::new( + return Err(Error::new( meta.path.span(), "`crate`, `use_discriminant` or `init` are the only supported attributes for `borsh`", )); @@ -33,9 +33,9 @@ pub fn check_attributes(derive_input: &DeriveInput) -> Result<(), Error> { Ok(()) } -pub(crate) fn contains_use_discriminant(input: &ItemEnum) -> Result { +pub(crate) fn contains_use_discriminant(input: &ItemEnum) -> Result { if input.variants.len() > 256 { - return Err(syn::Error::new( + return Err(Error::new( input.span(), "up to 256 enum variants are supported", )); @@ -120,52 +120,50 @@ pub(crate) fn get_crate(attrs: &[Attribute]) -> Result, Error> { #[cfg(test)] mod tests { - use crate::internals::test_helpers::local_insta_assert_debug_snapshot; - use quote::{quote, ToTokens}; - use syn::ItemEnum; + use quote::ToTokens; + use syn::{parse_quote, ItemEnum}; use super::*; + use crate::internals::test_helpers::local_insta_assert_debug_snapshot; + #[test] fn test_use_discriminant() { - let item_enum: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { #[derive(BorshDeserialize, Debug)] #[borsh(use_discriminant = false)] enum AWithUseDiscriminantFalse { X, Y, } - }) - .unwrap(); + }; let actual = contains_use_discriminant(&item_enum); assert!(!actual.unwrap()); } #[test] fn test_use_discriminant_true() { - let item_enum: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { #[derive(BorshDeserialize, Debug)] #[borsh(use_discriminant = true)] enum AWithUseDiscriminantTrue { X, Y, } - }) - .unwrap(); + }; let actual = contains_use_discriminant(&item_enum); assert!(actual.unwrap()); } #[test] fn test_use_discriminant_wrong_value() { - let item_enum: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { #[derive(BorshDeserialize, Debug)] #[borsh(use_discriminant = 111)] enum AWithUseDiscriminantFalse { X, Y, } - }) - .unwrap(); + }; let actual = contains_use_discriminant(&item_enum); let err = match actual { Ok(..) => unreachable!("expecting error here"), @@ -175,64 +173,60 @@ mod tests { } #[test] fn test_check_attrs_use_discriminant_on_struct() { - let item_enum: DeriveInput = syn::parse2(quote! { + let derive_input: DeriveInput = parse_quote! { #[derive(BorshDeserialize, Debug)] #[borsh(use_discriminant = false)] struct AWithUseDiscriminantFalse { x: X, y: Y, } - }) - .unwrap(); - let actual = check_attributes(&item_enum); + }; + let actual = check_attributes(&derive_input); local_insta_assert_debug_snapshot!(actual.unwrap_err()); } #[test] fn test_check_attrs_borsh_skip_on_whole_item() { - let item_enum: DeriveInput = syn::parse2(quote! { + let derive_input: DeriveInput = parse_quote! { #[derive(BorshDeserialize, Debug)] #[borsh(skip)] struct AWithUseDiscriminantFalse { x: X, y: Y, } - }) - .unwrap(); - let actual = check_attributes(&item_enum); + }; + let actual = check_attributes(&derive_input); local_insta_assert_debug_snapshot!(actual.unwrap_err()); } #[test] fn test_check_attrs_borsh_invalid_on_whole_item() { - let item_enum: DeriveInput = syn::parse2(quote! { + let derive_input: DeriveInput = parse_quote! { #[derive(BorshDeserialize, Debug)] #[borsh(invalid)] enum AWithUseDiscriminantFalse { X, Y, } - }) - .unwrap(); - let actual = check_attributes(&item_enum); + }; + let actual = check_attributes(&derive_input); local_insta_assert_debug_snapshot!(actual.unwrap_err()); } #[test] fn test_check_attrs_init_function() { - let item_struct = syn::parse2::(quote! { + let derive_input: DeriveInput = parse_quote! { #[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)] #[borsh(init = initialization_method)] struct A<'a> { x: u64, } - }) - .unwrap(); + }; - let actual = check_attributes(&item_struct); + let actual = check_attributes(&derive_input); assert!(actual.is_ok()); } #[test] fn test_check_attrs_init_function_with_use_discriminant_reversed() { - let item_struct = syn::parse2::(quote! { + let derive_input: DeriveInput = parse_quote! { #[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)] #[borsh(use_discriminant=true, init = initialization_method)] enum A { @@ -240,16 +234,15 @@ mod tests { C, D= 10, } - }) - .unwrap(); + }; - let actual = check_attributes(&item_struct); + let actual = check_attributes(&derive_input); assert!(actual.is_ok()); } #[test] fn test_reject_multiple_borsh_attrs() { - let item_struct = syn::parse2::(quote! { + let derive_input: DeriveInput = parse_quote! { #[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)] #[borsh(use_discriminant=true)] #[borsh(init = initialization_method)] @@ -258,16 +251,15 @@ mod tests { C, D= 10, } - }) - .unwrap(); + }; - let actual = check_attributes(&item_struct); + let actual = check_attributes(&derive_input); local_insta_assert_debug_snapshot!(actual.unwrap_err()); } #[test] fn test_check_attrs_init_function_with_use_discriminant() { - let item_struct = syn::parse2::(quote! { + let derive_input: DeriveInput = parse_quote! { #[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)] #[borsh(init = initialization_method, use_discriminant=true)] enum A { @@ -275,16 +267,15 @@ mod tests { C, D= 10, } - }) - .unwrap(); + }; - let actual = check_attributes(&item_struct); + let actual = check_attributes(&derive_input); assert!(actual.is_ok()); } #[test] fn test_check_attrs_init_function_wrong_format() { - let item_struct: DeriveInput = syn::parse2(quote! { + let derive_input: DeriveInput = parse_quote! { #[derive(BorshDeserialize, Debug)] #[borsh(init_func = initialization_method)] struct A<'a> { @@ -295,23 +286,21 @@ mod tests { v: Vec, } - }) - .unwrap(); - let actual = check_attributes(&item_struct); + }; + let actual = check_attributes(&derive_input); local_insta_assert_debug_snapshot!(actual.unwrap_err()); } #[test] fn test_init_function() { - let item_struct = syn::parse2::(quote! { + let derive_input: DeriveInput = parse_quote! { #[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)] #[borsh(init = initialization_method)] struct A<'a> { x: u64, } - }) - .unwrap(); + }; - let actual = contains_initialize_with(&item_struct.attrs); + let actual = contains_initialize_with(&derive_input.attrs); assert_eq!( actual.unwrap().to_token_stream().to_string(), "initialization_method" @@ -320,16 +309,15 @@ mod tests { #[test] fn test_init_function_parsing_error() { - let item_struct = syn::parse2::(quote! { + let derive_input: DeriveInput = parse_quote! { #[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)] #[borsh(init={strange; blocky})] struct A { lazy: Option, } - }) - .unwrap(); + }; - let actual = contains_initialize_with(&item_struct.attrs); + let actual = contains_initialize_with(&derive_input.attrs); let err = match actual { Ok(..) => unreachable!("expecting error here"), Err(err) => err, @@ -339,7 +327,7 @@ mod tests { #[test] fn test_init_function_with_use_discriminant() { - let item_struct = syn::parse2::(quote! { + let item_enum: ItemEnum = parse_quote! { #[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)] #[borsh(init = initialization_method, use_discriminant=true)] enum A { @@ -347,21 +335,20 @@ mod tests { C, D, } - }) - .unwrap(); + }; - let actual = contains_initialize_with(&item_struct.attrs); + let actual = contains_initialize_with(&item_enum.attrs); assert_eq!( actual.unwrap().to_token_stream().to_string(), "initialization_method" ); - let actual = contains_use_discriminant(&item_struct); + let actual = contains_use_discriminant(&item_enum); assert!(actual.unwrap()); } #[test] fn test_init_function_with_use_discriminant_reversed() { - let item_struct = syn::parse2::(quote! { + let item_enum: ItemEnum = parse_quote! { #[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)] #[borsh(use_discriminant=true, init = initialization_method)] enum A { @@ -369,21 +356,20 @@ mod tests { C, D, } - }) - .unwrap(); + }; - let actual = contains_initialize_with(&item_struct.attrs); + let actual = contains_initialize_with(&item_enum.attrs); assert_eq!( actual.unwrap().to_token_stream().to_string(), "initialization_method" ); - let actual = contains_use_discriminant(&item_struct); + let actual = contains_use_discriminant(&item_enum); assert!(actual.unwrap()); } #[test] fn test_init_function_with_use_discriminant_with_crate() { - let item_struct = syn::parse2::(quote! { + let item_enum: ItemEnum = parse_quote! { #[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)] #[borsh(init = initialization_method, crate = "reexporter::borsh", use_discriminant=true)] enum A { @@ -391,18 +377,17 @@ mod tests { C, D, } - }) - .unwrap(); + }; - let actual = contains_initialize_with(&item_struct.attrs); + let actual = contains_initialize_with(&item_enum.attrs); assert_eq!( actual.unwrap().to_token_stream().to_string(), "initialization_method" ); - let actual = contains_use_discriminant(&item_struct); + let actual = contains_use_discriminant(&item_enum); assert!(actual.unwrap()); - let crate_ = get_crate(&item_struct.attrs); + let crate_ = get_crate(&item_enum.attrs); assert_eq!( crate_.unwrap().to_token_stream().to_string(), "reexporter :: borsh" diff --git a/borsh-derive/src/internals/attributes/mod.rs b/borsh-derive/src/internals/attributes/mod.rs index 4c5a69d4d..a069bc1ec 100644 --- a/borsh-derive/src/internals/attributes/mod.rs +++ b/borsh-derive/src/internals/attributes/mod.rs @@ -7,44 +7,100 @@ pub mod parsing; /// first field is attr name /// second field is its expected value format representation for error printing #[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord)] -pub struct Symbol(pub &'static str, pub &'static str); +pub struct Symbol { + pub name: &'static str, + pub expected: &'static str, + support: AsyncSupport, +} + +#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord)] +enum AsyncSupport { + Sync, + Async, + Both, +} + +impl Symbol { + pub const fn new(name: &'static str, expected: &'static str) -> Self { + Self { + name, + expected, + support: AsyncSupport::Both, + } + } + + pub const fn new_sync(name: &'static str, expected: &'static str) -> Self { + Self { + name, + expected, + support: AsyncSupport::Sync, + } + } + + pub const fn new_async(name: &'static str, expected: &'static str) -> Self { + Self { + name, + expected, + support: AsyncSupport::Async, + } + } + + pub const fn test_support(&self) -> bool { + if IS_ASYNC { + matches!(self.support, AsyncSupport::Async | AsyncSupport::Both) + } else { + matches!(self.support, AsyncSupport::Sync | AsyncSupport::Both) + } + } +} -/// borsh - top level prefix in nested meta attribute -pub const BORSH: Symbol = Symbol("borsh", "borsh(...)"); -/// bound - sub-borsh nested meta, field-level only, `BorshSerialize` and `BorshDeserialize` contexts -pub const BOUND: Symbol = Symbol("bound", "bound(...)"); -// use_discriminant - sub-borsh nested meta, item-level only, enums only, `BorshSerialize` and `BorshDeserialize` contexts -pub const USE_DISCRIMINANT: Symbol = Symbol("use_discriminant", "use_discriminant = ..."); -/// serialize - sub-bound nested meta attribute -pub const SERIALIZE: Symbol = Symbol("serialize", "serialize = ..."); -/// deserialize - sub-bound nested meta attribute -pub const DESERIALIZE: Symbol = Symbol("deserialize", "deserialize = ..."); -/// skip - sub-borsh nested meta, field-level only attribute, `BorshSerialize`, `BorshDeserialize`, `BorshSchema` contexts -pub const SKIP: Symbol = Symbol("skip", "skip"); -/// init - sub-borsh nested meta, item-level only attribute `BorshDeserialize` context -pub const INIT: Symbol = Symbol("init", "init = ..."); -/// serialize_with - sub-borsh nested meta, field-level only, `BorshSerialize` context -pub const SERIALIZE_WITH: Symbol = Symbol("serialize_with", "serialize_with = ..."); -/// deserialize_with - sub-borsh nested meta, field-level only, `BorshDeserialize` context -pub const DESERIALIZE_WITH: Symbol = Symbol("deserialize_with", "deserialize_with = ..."); -/// crate - sub-borsh nested meta, item-level only, `BorshSerialize`, `BorshDeserialize`, `BorshSchema` contexts -pub const CRATE: Symbol = Symbol("crate", "crate = ..."); +/// `borsh` - top level prefix in nested meta attribute +pub const BORSH: Symbol = Symbol::new("borsh", "borsh(...)"); +/// `bound` - sub-borsh nested meta, field-level only; `BorshSerialize` and `BorshDeserialize` contexts +pub const BOUND: Symbol = Symbol::new("bound", "bound(...)"); +/// `async_bound` - sub-borsh nested meta, field-level only; `BorshSerializeAsync` and `BorshDeserializeAsync` contexts +pub const ASYNC_BOUND: Symbol = Symbol::new_async("async_bound", "async_bound(...)"); +/// `use_discriminant` - sub-borsh nested meta, item-level only, enums only; +/// `BorshSerialize`, `BorshDeserialize`, `BorshSerializeAsync` and `BorshDeserializeAsync` contexts +pub const USE_DISCRIMINANT: Symbol = Symbol::new("use_discriminant", "use_discriminant = ..."); +/// `serialize` - sub-bound nested meta attribute +pub const SERIALIZE: Symbol = Symbol::new("serialize", "serialize = ..."); +/// `deserialize` - sub-bound nested meta attribute +pub const DESERIALIZE: Symbol = Symbol::new("deserialize", "deserialize = ..."); +/// `skip` - sub-borsh nested meta, field-level only attribute; +/// `BorshSerialize`, `BorshDeserialize`, `BorshSerializeAsync`, `BorshDeserializeAsync` and `BorshSchema` contexts +pub const SKIP: Symbol = Symbol::new("skip", "skip"); +/// `init` - sub-borsh nested meta, item-level only attribute; `BorshDeserialize` and `BorshDeserializeAsync` contexts +pub const INIT: Symbol = Symbol::new("init", "init = ..."); +/// `serialize_with` - sub-borsh nested meta, field-level only; `BorshSerialize` context +pub const SERIALIZE_WITH: Symbol = Symbol::new_sync("serialize_with", "serialize_with = ..."); +/// `deserialize_with` - sub-borsh nested meta, field-level only; `BorshDeserialize` context +pub const DESERIALIZE_WITH: Symbol = Symbol::new_sync("deserialize_with", "deserialize_with = ..."); +/// `serialize_with_async` - sub-borsh nested meta, field-level only; `BorshSerializeAsync` context +pub const SERIALIZE_WITH_ASYNC: Symbol = + Symbol::new_async("serialize_with_async", "serialize_with_async = ..."); +/// `deserialize_with_async` - sub-borsh nested meta, field-level only; `BorshDeserializeAsync` context +pub const DESERIALIZE_WITH_ASYNC: Symbol = + Symbol::new_async("deserialize_with_async", "deserialize_with_async = ..."); +/// `crate` - sub-borsh nested meta, item-level only; +/// `BorshSerialize`, `BorshDeserialize`, `BorshSerializeAsync`, `BorshDeserializeAsync` and `BorshSchema` contexts +pub const CRATE: Symbol = Symbol::new("crate", "crate = ..."); #[cfg(feature = "schema")] pub mod schema_keys { use super::Symbol; - /// schema - sub-borsh nested meta, `BorshSchema` context - pub const SCHEMA: Symbol = Symbol("schema", "schema(...)"); - /// params - sub-schema nested meta, field-level only attribute - pub const PARAMS: Symbol = Symbol("params", "params = ..."); - /// serialize_with - sub-borsh nested meta, field-level only, `BorshSerialize` context - /// with_funcs - sub-schema nested meta, field-level only attribute - pub const WITH_FUNCS: Symbol = Symbol("with_funcs", "with_funcs(...)"); - /// declaration - sub-with_funcs nested meta, field-level only attribute - pub const DECLARATION: Symbol = Symbol("declaration", "declaration = ..."); - /// definitions - sub-with_funcs nested meta, field-level only attribute - pub const DEFINITIONS: Symbol = Symbol("definitions", "definitions = ..."); + /// `schema` - sub-borsh nested meta, `BorshSchema` context + pub const SCHEMA: Symbol = Symbol::new("schema", "schema(...)"); + /// `params` - sub-schema nested meta, field-level only attribute + pub const PARAMS: Symbol = Symbol::new("params", "params = ..."); + /// `serialize_with` - sub-borsh nested meta, field-level only, `BorshSerialize` context + /// `with_funcs` - sub-schema nested meta, field-level only attribute + pub const WITH_FUNCS: Symbol = Symbol::new("with_funcs", "with_funcs(...)"); + /// `declaration` - sub-with_funcs nested meta, field-level only attribute + pub const DECLARATION: Symbol = Symbol::new("declaration", "declaration = ..."); + /// `definitions` - sub-with_funcs nested meta, field-level only attribute + pub const DEFINITIONS: Symbol = Symbol::new("definitions", "definitions = ..."); } #[derive(Clone, Copy)] @@ -54,23 +110,23 @@ pub enum BoundType { } impl PartialEq for Path { fn eq(&self, word: &Symbol) -> bool { - self.is_ident(word.0) + self.is_ident(word.name) } } impl<'a> PartialEq for &'a Path { fn eq(&self, word: &Symbol) -> bool { - self.is_ident(word.0) + self.is_ident(word.name) } } fn get_one_attribute(attrs: &[Attribute]) -> syn::Result> { - let count = attrs.iter().filter(|attr| attr.path() == BORSH).count(); - let borsh = attrs.iter().find(|attr| attr.path() == BORSH); - if count > 1 { + let mut attrs = attrs.iter().filter(|attr| attr.path() == BORSH); + let borsh = attrs.next(); + if let Some(other_borsh) = attrs.next() { return Err(syn::Error::new_spanned( - borsh.unwrap(), - format!("multiple `{}` attributes not allowed", BORSH.0), + other_borsh, + format!("multiple `{}` attributes not allowed", BORSH.name), )); } Ok(borsh) diff --git a/borsh-derive/src/internals/attributes/parsing.rs b/borsh-derive/src/internals/attributes/parsing.rs index 7ebf8e778..4eebee807 100644 --- a/borsh-derive/src/internals/attributes/parsing.rs +++ b/borsh-derive/src/internals/attributes/parsing.rs @@ -27,7 +27,7 @@ fn get_lit_str2( expr, format!( "expected borsh {} attribute to be a string: `{} = \"...\"`", - attr_name.0, meta_item_name.0 + attr_name.name, meta_item_name.name ), )) } @@ -77,11 +77,11 @@ where } } if !match_ { - let keys_strs = map.keys().map(|symbol| symbol.1).collect::>(); + let keys_strs = map.keys().map(|symbol| symbol.expected).collect::>(); let keys_strs = keys_strs.join(", "); return Err(meta.error(format_args!( "malformed {0} attribute, expected `{0}({1})`", - attr_name.0, keys_strs + attr_name.name, keys_strs ))); } Ok(()) diff --git a/borsh-derive/src/internals/deserialize/enums/mod.rs b/borsh-derive/src/internals/deserialize/enums/mod.rs index fb405e90d..925d73301 100644 --- a/borsh-derive/src/internals/deserialize/enums/mod.rs +++ b/borsh-derive/src/internals/deserialize/enums/mod.rs @@ -1,65 +1,87 @@ -use proc_macro2::TokenStream as TokenStream2; +use proc_macro2::{Ident, Span, TokenStream as TokenStream2}; use quote::quote; -use syn::{Fields, ItemEnum, Path, Variant}; +use syn::{Fields, ItemEnum, Path, Token, Variant}; use crate::internals::{attributes::item, deserialize, enum_discriminant::Discriminants, generics}; -pub fn process(input: &ItemEnum, cratename: Path) -> syn::Result { +pub fn process( + input: ItemEnum, + cratename: Path, +) -> syn::Result { let name = &input.ident; - let generics = generics::without_defaults(&input.generics); + let use_discriminant = item::contains_use_discriminant(&input)?; + let generics = generics::without_defaults(input.generics); let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); let mut where_clause = generics::default_where(where_clause); let mut variant_arms = TokenStream2::new(); - let use_discriminant = item::contains_use_discriminant(input)?; let discriminants = Discriminants::new(&input.variants); let mut generics_output = deserialize::GenericsOutput::new(&generics); - for (variant_idx, variant) in input.variants.iter().enumerate() { - let variant_body = process_variant(variant, &cratename, &mut generics_output)?; - let variant_ident = &variant.ident; + for (variant_idx, variant) in input.variants.into_iter().enumerate() { + let variant_body = process_variant::(&variant, &cratename, &mut generics_output)?; + let variant_ident = variant.ident; + + let discriminant_value = + discriminants.get(&variant_ident, use_discriminant, variant_idx)?; - let discriminant_value = discriminants.get(variant_ident, use_discriminant, variant_idx)?; + // `if` branches are used instead of `match` branches, because `discriminant_value` might be a function call variant_arms.extend(quote! { if variant_tag == #discriminant_value { #name::#variant_ident #variant_body } else }); } - let init = if let Some(method_ident) = item::contains_initialize_with(&input.attrs)? { - quote! { - return_value.#method_ident(); - } + let init = item::contains_initialize_with(&input.attrs)? + .map(|method_ident| quote! { return_value.#method_ident(); }); + let r#mut = init.is_some().then(|| Token![mut](Span::call_site())); + generics_output.extend::(&mut where_clause, &cratename); + + let deserialize_trait = Ident::new( + if IS_ASYNC { + "BorshDeserializeAsync" + } else { + "BorshDeserialize" + }, + Span::call_site(), + ); + let enum_ext = Ident::new( + if IS_ASYNC { "EnumExtAsync" } else { "EnumExt" }, + Span::call_site(), + ); + let read_trait_path = if IS_ASYNC { + quote! { async_io::AsyncRead } } else { - quote! {} + quote! { io::Read } }; - generics_output.extend(&mut where_clause, &cratename); + let r#async = IS_ASYNC.then(|| Token![async](Span::call_site())); + let dot_await = IS_ASYNC.then(|| quote! { .await }); Ok(quote! { - impl #impl_generics #cratename::de::BorshDeserialize for #name #ty_generics #where_clause { - fn deserialize_reader<__R: #cratename::io::Read>(reader: &mut __R) -> ::core::result::Result { - let tag = ::deserialize_reader(reader)?; - ::deserialize_variant(reader, tag) + impl #impl_generics #cratename::de::#deserialize_trait for #name #ty_generics #where_clause { + #r#async fn deserialize_reader<__R: #cratename::#read_trait_path>(reader: &mut __R) -> ::core::result::Result { + let tag = ::deserialize_reader(reader)#dot_await?; + ::deserialize_variant(reader, tag)#dot_await } } - impl #impl_generics #cratename::de::EnumExt for #name #ty_generics #where_clause { - fn deserialize_variant<__R: #cratename::io::Read>( + impl #impl_generics #cratename::de::#enum_ext for #name #ty_generics #where_clause { + #r#async fn deserialize_variant<__R: #cratename::#read_trait_path>( reader: &mut __R, variant_tag: u8, ) -> ::core::result::Result { - let mut return_value = + let #r#mut return_value = #variant_arms { - return Err(#cratename::io::Error::new( + return ::core::result::Result::Err(#cratename::io::Error::new( #cratename::io::ErrorKind::InvalidData, #cratename::__private::maybestd::format!("Unexpected variant tag: {:?}", variant_tag), )) }; #init - Ok(return_value) + ::core::result::Result::Ok(return_value) } } }) } -fn process_variant( +fn process_variant( variant: &Variant, cratename: &Path, generics: &mut deserialize::GenericsOutput, @@ -68,13 +90,13 @@ fn process_variant( match &variant.fields { Fields::Named(fields) => { for field in &fields.named { - deserialize::process_field(field, cratename, &mut body, generics)?; + deserialize::process_field::(field, cratename, &mut body, generics)?; } body = quote! { { #body }}; } Fields::Unnamed(fields) => { for field in fields.unnamed.iter() { - deserialize::process_field(field, cratename, &mut body, generics)?; + deserialize::process_field::(field, cratename, &mut body, generics)?; } body = quote! { ( #body )}; } @@ -85,15 +107,16 @@ fn process_variant( #[cfg(test)] mod tests { + use syn::parse_quote; + + use super::*; use crate::internals::test_helpers::{ default_cratename, local_insta_assert_snapshot, pretty_print_syn_str, }; - use super::*; - #[test] fn borsh_skip_struct_variant_field() { - let item_enum: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum AA { B { #[borsh(skip)] @@ -104,16 +127,18 @@ mod tests { beta: u8, } } - }) - .unwrap(); - let actual = process(&item_enum, default_cratename()).unwrap(); + }; + + let actual = process::(item_enum.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_enum, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn borsh_skip_tuple_variant_field() { - let item_enum: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum AAT { B(#[borsh(skip)] i32, u32), @@ -121,16 +146,18 @@ mod tests { beta: u8, } } - }) - .unwrap(); - let actual = process(&item_enum, default_cratename()).unwrap(); + }; + + let actual = process::(item_enum.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_enum, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn simple_enum_with_custom_crate() { - let item_struct: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum A { B { x: HashMap, @@ -138,17 +165,20 @@ mod tests { }, C(K, Vec), } - }) - .unwrap(); + }; + + let crate_: Path = parse_quote! { reexporter::borsh }; + + let actual = process::(item_enum.clone(), crate_.clone()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - let crate_: Path = syn::parse2(quote! { reexporter::borsh }).unwrap(); - let actual = process(&item_struct, crate_).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_enum, crate_).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn simple_generics() { - let item_struct: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum A { B { x: HashMap, @@ -156,16 +186,18 @@ mod tests { }, C(K, Vec), } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_enum.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); + + let actual = process::(item_enum, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn bound_generics() { - let item_struct: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum A where V: Value { B { x: HashMap, @@ -173,16 +205,18 @@ mod tests { }, C(K, Vec), } - }) - .unwrap(); + }; + + let actual = process::(item_enum.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - let actual = process(&item_struct, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_enum, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn recursive_enum() { - let item_struct: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum A where V: Value { B { x: HashMap, @@ -190,16 +224,17 @@ mod tests { }, C(K, Vec), } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process::(item_enum.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_enum, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn generic_borsh_skip_struct_field() { - let item_struct: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum A where V: Value { B { #[borsh(skip)] @@ -208,17 +243,18 @@ mod tests { }, C(K, Vec), } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process::(item_enum.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_enum, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn generic_borsh_skip_tuple_field() { - let item_struct: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum A where V: Value { B { x: HashMap, @@ -226,17 +262,18 @@ mod tests { }, C(K, #[borsh(skip)] Vec), } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process::(item_enum.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_enum, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn generic_deserialize_bound() { - let item_struct: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum A { C { a: String, @@ -248,17 +285,41 @@ mod tests { }, D(u32, u32), } - }) - .unwrap(); + }; + + let actual = process::(item_enum.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); + + let actual = process::(item_enum, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); + } + + #[test] + fn generic_deserialize_async_bound() { + let item_enum: ItemEnum = parse_quote! { + enum A { + C { + a: String, + #[borsh(async_bound(deserialize = + "T: PartialOrd + Hash + Eq + borsh::de::BorshDeserializeAsync, + U: borsh::de::BorshDeserializeAsync" + ))] + b: HashMap, + }, + D(u32, u32), + } + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process::(item_enum.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_enum, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn check_deserialize_with_attr() { - let item_struct: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum C { C3(u64, u64), C4 { @@ -267,17 +328,38 @@ mod tests { y: ThirdParty }, } - }) - .unwrap(); + }; + + let actual = process::(item_enum.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); + + let actual = process::(item_enum, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); + } + + #[test] + fn check_deserialize_with_async_attr() { + let item_enum: ItemEnum = parse_quote! { + enum C { + C3(u64, u64), + C4 { + x: u64, + #[borsh(deserialize_with_async = "third_party_impl::deserialize_third_party")] + y: ThirdParty + }, + } + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process::(item_enum.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_enum, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn borsh_discriminant_false() { - let item_enum: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { #[borsh(use_discriminant = false)] enum X { A, @@ -287,15 +369,18 @@ mod tests { E = 10, F, } - }) - .unwrap(); - let actual = process(&item_enum, default_cratename()).unwrap(); + }; + + let actual = process::(item_enum.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).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! { + let item_enum: ItemEnum = parse_quote! { #[borsh(use_discriminant = true)] enum X { A, @@ -305,15 +390,18 @@ mod tests { E = 10, F, } - }) - .unwrap(); - let actual = process(&item_enum, default_cratename()).unwrap(); + }; + + let actual = process::(item_enum.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_enum, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } + #[test] fn borsh_init_func() { - let item_enum: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { #[borsh(init = initialization_method)] enum A { A, @@ -323,9 +411,12 @@ mod tests { E, F, } - }) - .unwrap(); - let actual = process(&item_enum, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + }; + + let actual = process::(item_enum.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); + + let actual = process::(item_enum, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } } diff --git a/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_discriminant_false-2.snap b/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_discriminant_false-2.snap new file mode 100644 index 000000000..2d8c2ec53 --- /dev/null +++ b/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_discriminant_false-2.snap @@ -0,0 +1,43 @@ +--- +source: borsh-derive/src/internals/deserialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::de::BorshDeserializeAsync for X { + async fn deserialize_reader<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + ) -> ::core::result::Result { + let tag = ::deserialize_reader(reader) + .await?; + ::deserialize_variant(reader, tag).await + } +} +impl borsh::de::EnumExtAsync for X { + async fn deserialize_variant<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + variant_tag: u8, + ) -> ::core::result::Result { + let return_value = if variant_tag == 0u8 { + X::A + } else if variant_tag == 1u8 { + X::B + } else if variant_tag == 2u8 { + X::C + } else if variant_tag == 3u8 { + X::D + } else if variant_tag == 4u8 { + X::E + } else if variant_tag == 5u8 { + X::F + } else { + return ::core::result::Result::Err( + borsh::io::Error::new( + borsh::io::ErrorKind::InvalidData, + borsh::__private::maybestd::format!( + "Unexpected variant tag: {:?}", variant_tag + ), + ), + ) + }; + ::core::result::Result::Ok(return_value) + } +} diff --git a/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_discriminant_false.snap b/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_discriminant_false.snap index 1e0446681..14c718d83 100644 --- a/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_discriminant_false.snap +++ b/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_discriminant_false.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/deserialize/enums/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::de::BorshDeserialize for X { fn deserialize_reader<__R: borsh::io::Read>( @@ -15,7 +15,7 @@ impl borsh::de::EnumExt for X { reader: &mut __R, variant_tag: u8, ) -> ::core::result::Result { - let mut return_value = if variant_tag == 0u8 { + let return_value = if variant_tag == 0u8 { X::A } else if variant_tag == 1u8 { X::B @@ -28,7 +28,7 @@ impl borsh::de::EnumExt for X { } else if variant_tag == 5u8 { X::F } else { - return Err( + return ::core::result::Result::Err( borsh::io::Error::new( borsh::io::ErrorKind::InvalidData, borsh::__private::maybestd::format!( @@ -37,6 +37,6 @@ impl borsh::de::EnumExt for X { ), ) }; - Ok(return_value) + ::core::result::Result::Ok(return_value) } } diff --git a/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_discriminant_true-2.snap b/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_discriminant_true-2.snap new file mode 100644 index 000000000..5a617705e --- /dev/null +++ b/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_discriminant_true-2.snap @@ -0,0 +1,43 @@ +--- +source: borsh-derive/src/internals/deserialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::de::BorshDeserializeAsync for X { + async fn deserialize_reader<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + ) -> ::core::result::Result { + let tag = ::deserialize_reader(reader) + .await?; + ::deserialize_variant(reader, tag).await + } +} +impl borsh::de::EnumExtAsync for X { + async fn deserialize_variant<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + variant_tag: u8, + ) -> ::core::result::Result { + let return_value = if variant_tag == 0 { + X::A + } else if variant_tag == 20 { + X::B + } else if variant_tag == 20 + 1 { + X::C + } else if variant_tag == 20 + 1 + 1 { + X::D + } else if variant_tag == 10 { + X::E + } else if variant_tag == 10 + 1 { + X::F + } else { + return ::core::result::Result::Err( + borsh::io::Error::new( + borsh::io::ErrorKind::InvalidData, + borsh::__private::maybestd::format!( + "Unexpected variant tag: {:?}", variant_tag + ), + ), + ) + }; + ::core::result::Result::Ok(return_value) + } +} diff --git a/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_discriminant_true.snap b/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_discriminant_true.snap index add0f62ed..65e363b07 100644 --- a/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_discriminant_true.snap +++ b/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_discriminant_true.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/deserialize/enums/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::de::BorshDeserialize for X { fn deserialize_reader<__R: borsh::io::Read>( @@ -15,7 +15,7 @@ impl borsh::de::EnumExt for X { reader: &mut __R, variant_tag: u8, ) -> ::core::result::Result { - let mut return_value = if variant_tag == 0 { + let return_value = if variant_tag == 0 { X::A } else if variant_tag == 20 { X::B @@ -28,7 +28,7 @@ impl borsh::de::EnumExt for X { } else if variant_tag == 10 + 1 { X::F } else { - return Err( + return ::core::result::Result::Err( borsh::io::Error::new( borsh::io::ErrorKind::InvalidData, borsh::__private::maybestd::format!( @@ -37,6 +37,6 @@ impl borsh::de::EnumExt for X { ), ) }; - Ok(return_value) + ::core::result::Result::Ok(return_value) } } diff --git a/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_init_func-2.snap b/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_init_func-2.snap new file mode 100644 index 000000000..dec3fd255 --- /dev/null +++ b/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_init_func-2.snap @@ -0,0 +1,44 @@ +--- +source: borsh-derive/src/internals/deserialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::de::BorshDeserializeAsync for A { + async fn deserialize_reader<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + ) -> ::core::result::Result { + let tag = ::deserialize_reader(reader) + .await?; + ::deserialize_variant(reader, tag).await + } +} +impl borsh::de::EnumExtAsync for A { + async fn deserialize_variant<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + variant_tag: u8, + ) -> ::core::result::Result { + let mut return_value = if variant_tag == 0u8 { + A::A + } else if variant_tag == 1u8 { + A::B + } else if variant_tag == 2u8 { + A::C + } else if variant_tag == 3u8 { + A::D + } else if variant_tag == 4u8 { + A::E + } else if variant_tag == 5u8 { + A::F + } else { + return ::core::result::Result::Err( + borsh::io::Error::new( + borsh::io::ErrorKind::InvalidData, + borsh::__private::maybestd::format!( + "Unexpected variant tag: {:?}", variant_tag + ), + ), + ) + }; + return_value.initialization_method(); + ::core::result::Result::Ok(return_value) + } +} diff --git a/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_init_func.snap b/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_init_func.snap index 28dd7dbce..54a14823e 100644 --- a/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_init_func.snap +++ b/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_init_func.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/deserialize/enums/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::de::BorshDeserialize for A { fn deserialize_reader<__R: borsh::io::Read>( @@ -28,7 +28,7 @@ impl borsh::de::EnumExt for A { } else if variant_tag == 5u8 { A::F } else { - return Err( + return ::core::result::Result::Err( borsh::io::Error::new( borsh::io::ErrorKind::InvalidData, borsh::__private::maybestd::format!( @@ -38,6 +38,6 @@ impl borsh::de::EnumExt for A { ) }; return_value.initialization_method(); - Ok(return_value) + ::core::result::Result::Ok(return_value) } } diff --git a/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_skip_struct_variant_field-2.snap b/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_skip_struct_variant_field-2.snap new file mode 100644 index 000000000..b95070208 --- /dev/null +++ b/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_skip_struct_variant_field-2.snap @@ -0,0 +1,42 @@ +--- +source: borsh-derive/src/internals/deserialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::de::BorshDeserializeAsync for AA { + async fn deserialize_reader<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + ) -> ::core::result::Result { + let tag = ::deserialize_reader(reader) + .await?; + ::deserialize_variant(reader, tag).await + } +} +impl borsh::de::EnumExtAsync for AA { + async fn deserialize_variant<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + variant_tag: u8, + ) -> ::core::result::Result { + let return_value = if variant_tag == 0u8 { + AA::B { + c: ::core::default::Default::default(), + d: ::deserialize_reader(reader) + .await?, + } + } else if variant_tag == 1u8 { + AA::NegatedVariant { + beta: ::deserialize_reader(reader) + .await?, + } + } else { + return ::core::result::Result::Err( + borsh::io::Error::new( + borsh::io::ErrorKind::InvalidData, + borsh::__private::maybestd::format!( + "Unexpected variant tag: {:?}", variant_tag + ), + ), + ) + }; + ::core::result::Result::Ok(return_value) + } +} diff --git a/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_skip_struct_variant_field.snap b/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_skip_struct_variant_field.snap index a8a2d9e1a..5938210dc 100644 --- a/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_skip_struct_variant_field.snap +++ b/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_skip_struct_variant_field.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/deserialize/enums/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::de::BorshDeserialize for AA { fn deserialize_reader<__R: borsh::io::Read>( @@ -15,17 +15,17 @@ impl borsh::de::EnumExt for AA { reader: &mut __R, variant_tag: u8, ) -> ::core::result::Result { - let mut return_value = if variant_tag == 0u8 { + let return_value = if variant_tag == 0u8 { AA::B { - c: core::default::Default::default(), - d: borsh::BorshDeserialize::deserialize_reader(reader)?, + c: ::core::default::Default::default(), + d: ::deserialize_reader(reader)?, } } else if variant_tag == 1u8 { AA::NegatedVariant { - beta: borsh::BorshDeserialize::deserialize_reader(reader)?, + beta: ::deserialize_reader(reader)?, } } else { - return Err( + return ::core::result::Result::Err( borsh::io::Error::new( borsh::io::ErrorKind::InvalidData, borsh::__private::maybestd::format!( @@ -34,6 +34,6 @@ impl borsh::de::EnumExt for AA { ), ) }; - Ok(return_value) + ::core::result::Result::Ok(return_value) } } diff --git a/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_skip_tuple_variant_field-2.snap b/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_skip_tuple_variant_field-2.snap new file mode 100644 index 000000000..51758af91 --- /dev/null +++ b/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_skip_tuple_variant_field-2.snap @@ -0,0 +1,41 @@ +--- +source: borsh-derive/src/internals/deserialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::de::BorshDeserializeAsync for AAT { + async fn deserialize_reader<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + ) -> ::core::result::Result { + let tag = ::deserialize_reader(reader) + .await?; + ::deserialize_variant(reader, tag).await + } +} +impl borsh::de::EnumExtAsync for AAT { + async fn deserialize_variant<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + variant_tag: u8, + ) -> ::core::result::Result { + let return_value = if variant_tag == 0u8 { + AAT::B( + ::core::default::Default::default(), + ::deserialize_reader(reader).await?, + ) + } else if variant_tag == 1u8 { + AAT::NegatedVariant { + beta: ::deserialize_reader(reader) + .await?, + } + } else { + return ::core::result::Result::Err( + borsh::io::Error::new( + borsh::io::ErrorKind::InvalidData, + borsh::__private::maybestd::format!( + "Unexpected variant tag: {:?}", variant_tag + ), + ), + ) + }; + ::core::result::Result::Ok(return_value) + } +} diff --git a/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_skip_tuple_variant_field.snap b/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_skip_tuple_variant_field.snap index 60149fc60..7303215f7 100644 --- a/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_skip_tuple_variant_field.snap +++ b/borsh-derive/src/internals/deserialize/enums/snapshots/borsh_skip_tuple_variant_field.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/deserialize/enums/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::de::BorshDeserialize for AAT { fn deserialize_reader<__R: borsh::io::Read>( @@ -15,17 +15,17 @@ impl borsh::de::EnumExt for AAT { reader: &mut __R, variant_tag: u8, ) -> ::core::result::Result { - let mut return_value = if variant_tag == 0u8 { + let return_value = if variant_tag == 0u8 { AAT::B( - core::default::Default::default(), - borsh::BorshDeserialize::deserialize_reader(reader)?, + ::core::default::Default::default(), + ::deserialize_reader(reader)?, ) } else if variant_tag == 1u8 { AAT::NegatedVariant { - beta: borsh::BorshDeserialize::deserialize_reader(reader)?, + beta: ::deserialize_reader(reader)?, } } else { - return Err( + return ::core::result::Result::Err( borsh::io::Error::new( borsh::io::ErrorKind::InvalidData, borsh::__private::maybestd::format!( @@ -34,6 +34,6 @@ impl borsh::de::EnumExt for AAT { ), ) }; - Ok(return_value) + ::core::result::Result::Ok(return_value) } } diff --git a/borsh-derive/src/internals/deserialize/enums/snapshots/bound_generics-2.snap b/borsh-derive/src/internals/deserialize/enums/snapshots/bound_generics-2.snap new file mode 100644 index 000000000..1b3648e82 --- /dev/null +++ b/borsh-derive/src/internals/deserialize/enums/snapshots/bound_generics-2.snap @@ -0,0 +1,59 @@ +--- +source: borsh-derive/src/internals/deserialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::de::BorshDeserializeAsync for A +where + V: Value, + K: borsh::de::BorshDeserializeAsync, + V: borsh::de::BorshDeserializeAsync, + U: borsh::de::BorshDeserializeAsync, +{ + async fn deserialize_reader<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + ) -> ::core::result::Result { + let tag = ::deserialize_reader(reader) + .await?; + ::deserialize_variant(reader, tag).await + } +} +impl borsh::de::EnumExtAsync for A +where + V: Value, + K: borsh::de::BorshDeserializeAsync, + V: borsh::de::BorshDeserializeAsync, + U: borsh::de::BorshDeserializeAsync, +{ + async fn deserialize_variant<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + variant_tag: u8, + ) -> ::core::result::Result { + let return_value = if variant_tag == 0u8 { + A::B { + x: as borsh::BorshDeserializeAsync>::deserialize_reader(reader) + .await?, + y: ::deserialize_reader(reader) + .await?, + } + } else if variant_tag == 1u8 { + A::C( + ::deserialize_reader(reader).await?, + as borsh::BorshDeserializeAsync>::deserialize_reader(reader) + .await?, + ) + } else { + return ::core::result::Result::Err( + borsh::io::Error::new( + borsh::io::ErrorKind::InvalidData, + borsh::__private::maybestd::format!( + "Unexpected variant tag: {:?}", variant_tag + ), + ), + ) + }; + ::core::result::Result::Ok(return_value) + } +} diff --git a/borsh-derive/src/internals/deserialize/enums/snapshots/bound_generics.snap b/borsh-derive/src/internals/deserialize/enums/snapshots/bound_generics.snap index 6b31f4bc6..abae695c1 100644 --- a/borsh-derive/src/internals/deserialize/enums/snapshots/bound_generics.snap +++ b/borsh-derive/src/internals/deserialize/enums/snapshots/bound_generics.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/deserialize/enums/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::de::BorshDeserialize for A where @@ -27,18 +27,21 @@ where reader: &mut __R, variant_tag: u8, ) -> ::core::result::Result { - let mut return_value = if variant_tag == 0u8 { + let return_value = if variant_tag == 0u8 { A::B { - x: borsh::BorshDeserialize::deserialize_reader(reader)?, - y: borsh::BorshDeserialize::deserialize_reader(reader)?, + x: as borsh::BorshDeserialize>::deserialize_reader(reader)?, + y: ::deserialize_reader(reader)?, } } else if variant_tag == 1u8 { A::C( - borsh::BorshDeserialize::deserialize_reader(reader)?, - borsh::BorshDeserialize::deserialize_reader(reader)?, + ::deserialize_reader(reader)?, + as borsh::BorshDeserialize>::deserialize_reader(reader)?, ) } else { - return Err( + return ::core::result::Result::Err( borsh::io::Error::new( borsh::io::ErrorKind::InvalidData, borsh::__private::maybestd::format!( @@ -47,6 +50,6 @@ where ), ) }; - Ok(return_value) + ::core::result::Result::Ok(return_value) } } diff --git a/borsh-derive/src/internals/deserialize/enums/snapshots/check_deserialize_with_async_attr-2.snap b/borsh-derive/src/internals/deserialize/enums/snapshots/check_deserialize_with_async_attr-2.snap new file mode 100644 index 000000000..6ae29e32e --- /dev/null +++ b/borsh-derive/src/internals/deserialize/enums/snapshots/check_deserialize_with_async_attr-2.snap @@ -0,0 +1,50 @@ +--- +source: borsh-derive/src/internals/deserialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::de::BorshDeserializeAsync for C +where + K: borsh::de::BorshDeserializeAsync, + V: borsh::de::BorshDeserializeAsync, +{ + async fn deserialize_reader<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + ) -> ::core::result::Result { + let tag = ::deserialize_reader(reader) + .await?; + ::deserialize_variant(reader, tag).await + } +} +impl borsh::de::EnumExtAsync for C +where + K: borsh::de::BorshDeserializeAsync, + V: borsh::de::BorshDeserializeAsync, +{ + async fn deserialize_variant<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + variant_tag: u8, + ) -> ::core::result::Result { + let return_value = if variant_tag == 0u8 { + C::C3( + ::deserialize_reader(reader).await?, + ::deserialize_reader(reader).await?, + ) + } else if variant_tag == 1u8 { + C::C4 { + x: ::deserialize_reader(reader) + .await?, + y: third_party_impl::deserialize_third_party(reader).await?, + } + } else { + return ::core::result::Result::Err( + borsh::io::Error::new( + borsh::io::ErrorKind::InvalidData, + borsh::__private::maybestd::format!( + "Unexpected variant tag: {:?}", variant_tag + ), + ), + ) + }; + ::core::result::Result::Ok(return_value) + } +} diff --git a/borsh-derive/src/internals/deserialize/enums/snapshots/check_deserialize_with_async_attr.snap b/borsh-derive/src/internals/deserialize/enums/snapshots/check_deserialize_with_async_attr.snap new file mode 100644 index 000000000..63c7c21d3 --- /dev/null +++ b/borsh-derive/src/internals/deserialize/enums/snapshots/check_deserialize_with_async_attr.snap @@ -0,0 +1,51 @@ +--- +source: borsh-derive/src/internals/deserialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::de::BorshDeserialize for C +where + K: borsh::de::BorshDeserialize, + V: borsh::de::BorshDeserialize, +{ + fn deserialize_reader<__R: borsh::io::Read>( + reader: &mut __R, + ) -> ::core::result::Result { + let tag = ::deserialize_reader(reader)?; + ::deserialize_variant(reader, tag) + } +} +impl borsh::de::EnumExt for C +where + K: borsh::de::BorshDeserialize, + V: borsh::de::BorshDeserialize, +{ + fn deserialize_variant<__R: borsh::io::Read>( + reader: &mut __R, + variant_tag: u8, + ) -> ::core::result::Result { + let return_value = if variant_tag == 0u8 { + C::C3( + ::deserialize_reader(reader)?, + ::deserialize_reader(reader)?, + ) + } else if variant_tag == 1u8 { + C::C4 { + x: ::deserialize_reader(reader)?, + y: as borsh::BorshDeserialize>::deserialize_reader(reader)?, + } + } else { + return ::core::result::Result::Err( + borsh::io::Error::new( + borsh::io::ErrorKind::InvalidData, + borsh::__private::maybestd::format!( + "Unexpected variant tag: {:?}", variant_tag + ), + ), + ) + }; + ::core::result::Result::Ok(return_value) + } +} diff --git a/borsh-derive/src/internals/deserialize/enums/snapshots/check_deserialize_with_attr-2.snap b/borsh-derive/src/internals/deserialize/enums/snapshots/check_deserialize_with_attr-2.snap new file mode 100644 index 000000000..4be6ba10b --- /dev/null +++ b/borsh-derive/src/internals/deserialize/enums/snapshots/check_deserialize_with_attr-2.snap @@ -0,0 +1,54 @@ +--- +source: borsh-derive/src/internals/deserialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::de::BorshDeserializeAsync for C +where + K: borsh::de::BorshDeserializeAsync, + V: borsh::de::BorshDeserializeAsync, +{ + async fn deserialize_reader<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + ) -> ::core::result::Result { + let tag = ::deserialize_reader(reader) + .await?; + ::deserialize_variant(reader, tag).await + } +} +impl borsh::de::EnumExtAsync for C +where + K: borsh::de::BorshDeserializeAsync, + V: borsh::de::BorshDeserializeAsync, +{ + async fn deserialize_variant<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + variant_tag: u8, + ) -> ::core::result::Result { + let return_value = if variant_tag == 0u8 { + C::C3( + ::deserialize_reader(reader).await?, + ::deserialize_reader(reader).await?, + ) + } else if variant_tag == 1u8 { + C::C4 { + x: ::deserialize_reader(reader) + .await?, + y: as borsh::BorshDeserializeAsync>::deserialize_reader(reader) + .await?, + } + } else { + return ::core::result::Result::Err( + borsh::io::Error::new( + borsh::io::ErrorKind::InvalidData, + borsh::__private::maybestd::format!( + "Unexpected variant tag: {:?}", variant_tag + ), + ), + ) + }; + ::core::result::Result::Ok(return_value) + } +} diff --git a/borsh-derive/src/internals/deserialize/enums/snapshots/check_deserialize_with_attr.snap b/borsh-derive/src/internals/deserialize/enums/snapshots/check_deserialize_with_attr.snap index 968e0c3b5..fe50c66c2 100644 --- a/borsh-derive/src/internals/deserialize/enums/snapshots/check_deserialize_with_attr.snap +++ b/borsh-derive/src/internals/deserialize/enums/snapshots/check_deserialize_with_attr.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/deserialize/enums/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::de::BorshDeserialize for C where @@ -23,18 +23,18 @@ where reader: &mut __R, variant_tag: u8, ) -> ::core::result::Result { - let mut return_value = if variant_tag == 0u8 { + let return_value = if variant_tag == 0u8 { C::C3( - borsh::BorshDeserialize::deserialize_reader(reader)?, - borsh::BorshDeserialize::deserialize_reader(reader)?, + ::deserialize_reader(reader)?, + ::deserialize_reader(reader)?, ) } else if variant_tag == 1u8 { C::C4 { - x: borsh::BorshDeserialize::deserialize_reader(reader)?, + x: ::deserialize_reader(reader)?, y: third_party_impl::deserialize_third_party(reader)?, } } else { - return Err( + return ::core::result::Result::Err( borsh::io::Error::new( borsh::io::ErrorKind::InvalidData, borsh::__private::maybestd::format!( @@ -43,6 +43,6 @@ where ), ) }; - Ok(return_value) + ::core::result::Result::Ok(return_value) } } diff --git a/borsh-derive/src/internals/deserialize/enums/snapshots/generic_borsh_skip_struct_field-2.snap b/borsh-derive/src/internals/deserialize/enums/snapshots/generic_borsh_skip_struct_field-2.snap new file mode 100644 index 000000000..4329633ca --- /dev/null +++ b/borsh-derive/src/internals/deserialize/enums/snapshots/generic_borsh_skip_struct_field-2.snap @@ -0,0 +1,57 @@ +--- +source: borsh-derive/src/internals/deserialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::de::BorshDeserializeAsync for A +where + V: Value, + K: borsh::de::BorshDeserializeAsync, + U: borsh::de::BorshDeserializeAsync, + K: ::core::default::Default, + V: ::core::default::Default, +{ + async fn deserialize_reader<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + ) -> ::core::result::Result { + let tag = ::deserialize_reader(reader) + .await?; + ::deserialize_variant(reader, tag).await + } +} +impl borsh::de::EnumExtAsync for A +where + V: Value, + K: borsh::de::BorshDeserializeAsync, + U: borsh::de::BorshDeserializeAsync, + K: ::core::default::Default, + V: ::core::default::Default, +{ + async fn deserialize_variant<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + variant_tag: u8, + ) -> ::core::result::Result { + let return_value = if variant_tag == 0u8 { + A::B { + x: ::core::default::Default::default(), + y: ::deserialize_reader(reader) + .await?, + } + } else if variant_tag == 1u8 { + A::C( + ::deserialize_reader(reader).await?, + as borsh::BorshDeserializeAsync>::deserialize_reader(reader) + .await?, + ) + } else { + return ::core::result::Result::Err( + borsh::io::Error::new( + borsh::io::ErrorKind::InvalidData, + borsh::__private::maybestd::format!( + "Unexpected variant tag: {:?}", variant_tag + ), + ), + ) + }; + ::core::result::Result::Ok(return_value) + } +} diff --git a/borsh-derive/src/internals/deserialize/enums/snapshots/generic_borsh_skip_struct_field.snap b/borsh-derive/src/internals/deserialize/enums/snapshots/generic_borsh_skip_struct_field.snap index cde62e488..5c6546e30 100644 --- a/borsh-derive/src/internals/deserialize/enums/snapshots/generic_borsh_skip_struct_field.snap +++ b/borsh-derive/src/internals/deserialize/enums/snapshots/generic_borsh_skip_struct_field.snap @@ -1,14 +1,14 @@ --- source: borsh-derive/src/internals/deserialize/enums/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::de::BorshDeserialize for A where V: Value, K: borsh::de::BorshDeserialize, U: borsh::de::BorshDeserialize, - K: core::default::Default, - V: core::default::Default, + K: ::core::default::Default, + V: ::core::default::Default, { fn deserialize_reader<__R: borsh::io::Read>( reader: &mut __R, @@ -22,25 +22,25 @@ where V: Value, K: borsh::de::BorshDeserialize, U: borsh::de::BorshDeserialize, - K: core::default::Default, - V: core::default::Default, + K: ::core::default::Default, + V: ::core::default::Default, { fn deserialize_variant<__R: borsh::io::Read>( reader: &mut __R, variant_tag: u8, ) -> ::core::result::Result { - let mut return_value = if variant_tag == 0u8 { + let return_value = if variant_tag == 0u8 { A::B { - x: core::default::Default::default(), - y: borsh::BorshDeserialize::deserialize_reader(reader)?, + x: ::core::default::Default::default(), + y: ::deserialize_reader(reader)?, } } else if variant_tag == 1u8 { A::C( - borsh::BorshDeserialize::deserialize_reader(reader)?, - borsh::BorshDeserialize::deserialize_reader(reader)?, + ::deserialize_reader(reader)?, + as borsh::BorshDeserialize>::deserialize_reader(reader)?, ) } else { - return Err( + return ::core::result::Result::Err( borsh::io::Error::new( borsh::io::ErrorKind::InvalidData, borsh::__private::maybestd::format!( @@ -49,6 +49,6 @@ where ), ) }; - Ok(return_value) + ::core::result::Result::Ok(return_value) } } diff --git a/borsh-derive/src/internals/deserialize/enums/snapshots/generic_borsh_skip_tuple_field-2.snap b/borsh-derive/src/internals/deserialize/enums/snapshots/generic_borsh_skip_tuple_field-2.snap new file mode 100644 index 000000000..0910625cb --- /dev/null +++ b/borsh-derive/src/internals/deserialize/enums/snapshots/generic_borsh_skip_tuple_field-2.snap @@ -0,0 +1,58 @@ +--- +source: borsh-derive/src/internals/deserialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::de::BorshDeserializeAsync for A +where + V: Value, + K: borsh::de::BorshDeserializeAsync, + V: borsh::de::BorshDeserializeAsync, + U: ::core::default::Default, +{ + async fn deserialize_reader<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + ) -> ::core::result::Result { + let tag = ::deserialize_reader(reader) + .await?; + ::deserialize_variant(reader, tag).await + } +} +impl borsh::de::EnumExtAsync for A +where + V: Value, + K: borsh::de::BorshDeserializeAsync, + V: borsh::de::BorshDeserializeAsync, + U: ::core::default::Default, +{ + async fn deserialize_variant<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + variant_tag: u8, + ) -> ::core::result::Result { + let return_value = if variant_tag == 0u8 { + A::B { + x: as borsh::BorshDeserializeAsync>::deserialize_reader(reader) + .await?, + y: ::deserialize_reader(reader) + .await?, + } + } else if variant_tag == 1u8 { + A::C( + ::deserialize_reader(reader).await?, + ::core::default::Default::default(), + ) + } else { + return ::core::result::Result::Err( + borsh::io::Error::new( + borsh::io::ErrorKind::InvalidData, + borsh::__private::maybestd::format!( + "Unexpected variant tag: {:?}", variant_tag + ), + ), + ) + }; + ::core::result::Result::Ok(return_value) + } +} diff --git a/borsh-derive/src/internals/deserialize/enums/snapshots/generic_borsh_skip_tuple_field.snap b/borsh-derive/src/internals/deserialize/enums/snapshots/generic_borsh_skip_tuple_field.snap index 0cc108681..d4087a395 100644 --- a/borsh-derive/src/internals/deserialize/enums/snapshots/generic_borsh_skip_tuple_field.snap +++ b/borsh-derive/src/internals/deserialize/enums/snapshots/generic_borsh_skip_tuple_field.snap @@ -1,13 +1,13 @@ --- source: borsh-derive/src/internals/deserialize/enums/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::de::BorshDeserialize for A where V: Value, K: borsh::de::BorshDeserialize, V: borsh::de::BorshDeserialize, - U: core::default::Default, + U: ::core::default::Default, { fn deserialize_reader<__R: borsh::io::Read>( reader: &mut __R, @@ -21,24 +21,27 @@ where V: Value, K: borsh::de::BorshDeserialize, V: borsh::de::BorshDeserialize, - U: core::default::Default, + U: ::core::default::Default, { fn deserialize_variant<__R: borsh::io::Read>( reader: &mut __R, variant_tag: u8, ) -> ::core::result::Result { - let mut return_value = if variant_tag == 0u8 { + let return_value = if variant_tag == 0u8 { A::B { - x: borsh::BorshDeserialize::deserialize_reader(reader)?, - y: borsh::BorshDeserialize::deserialize_reader(reader)?, + x: as borsh::BorshDeserialize>::deserialize_reader(reader)?, + y: ::deserialize_reader(reader)?, } } else if variant_tag == 1u8 { A::C( - borsh::BorshDeserialize::deserialize_reader(reader)?, - core::default::Default::default(), + ::deserialize_reader(reader)?, + ::core::default::Default::default(), ) } else { - return Err( + return ::core::result::Result::Err( borsh::io::Error::new( borsh::io::ErrorKind::InvalidData, borsh::__private::maybestd::format!( @@ -47,6 +50,6 @@ where ), ) }; - Ok(return_value) + ::core::result::Result::Ok(return_value) } } diff --git a/borsh-derive/src/internals/deserialize/enums/snapshots/generic_deserialize_async_bound-2.snap b/borsh-derive/src/internals/deserialize/enums/snapshots/generic_deserialize_async_bound-2.snap new file mode 100644 index 000000000..0635c01ac --- /dev/null +++ b/borsh-derive/src/internals/deserialize/enums/snapshots/generic_deserialize_async_bound-2.snap @@ -0,0 +1,54 @@ +--- +source: borsh-derive/src/internals/deserialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::de::BorshDeserializeAsync for A +where + T: PartialOrd + Hash + Eq + borsh::de::BorshDeserializeAsync, + U: borsh::de::BorshDeserializeAsync, +{ + async fn deserialize_reader<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + ) -> ::core::result::Result { + let tag = ::deserialize_reader(reader) + .await?; + ::deserialize_variant(reader, tag).await + } +} +impl borsh::de::EnumExtAsync for A +where + T: PartialOrd + Hash + Eq + borsh::de::BorshDeserializeAsync, + U: borsh::de::BorshDeserializeAsync, +{ + async fn deserialize_variant<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + variant_tag: u8, + ) -> ::core::result::Result { + let return_value = if variant_tag == 0u8 { + A::C { + a: ::deserialize_reader(reader) + .await?, + b: as borsh::BorshDeserializeAsync>::deserialize_reader(reader) + .await?, + } + } else if variant_tag == 1u8 { + A::D( + ::deserialize_reader(reader).await?, + ::deserialize_reader(reader).await?, + ) + } else { + return ::core::result::Result::Err( + borsh::io::Error::new( + borsh::io::ErrorKind::InvalidData, + borsh::__private::maybestd::format!( + "Unexpected variant tag: {:?}", variant_tag + ), + ), + ) + }; + ::core::result::Result::Ok(return_value) + } +} diff --git a/borsh-derive/src/internals/deserialize/enums/snapshots/generic_deserialize_async_bound.snap b/borsh-derive/src/internals/deserialize/enums/snapshots/generic_deserialize_async_bound.snap new file mode 100644 index 000000000..7463da4e0 --- /dev/null +++ b/borsh-derive/src/internals/deserialize/enums/snapshots/generic_deserialize_async_bound.snap @@ -0,0 +1,51 @@ +--- +source: borsh-derive/src/internals/deserialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::de::BorshDeserialize for A +where + T: borsh::de::BorshDeserialize, + U: borsh::de::BorshDeserialize, +{ + fn deserialize_reader<__R: borsh::io::Read>( + reader: &mut __R, + ) -> ::core::result::Result { + let tag = ::deserialize_reader(reader)?; + ::deserialize_variant(reader, tag) + } +} +impl borsh::de::EnumExt for A +where + T: borsh::de::BorshDeserialize, + U: borsh::de::BorshDeserialize, +{ + fn deserialize_variant<__R: borsh::io::Read>( + reader: &mut __R, + variant_tag: u8, + ) -> ::core::result::Result { + let return_value = if variant_tag == 0u8 { + A::C { + a: ::deserialize_reader(reader)?, + b: as borsh::BorshDeserialize>::deserialize_reader(reader)?, + } + } else if variant_tag == 1u8 { + A::D( + ::deserialize_reader(reader)?, + ::deserialize_reader(reader)?, + ) + } else { + return ::core::result::Result::Err( + borsh::io::Error::new( + borsh::io::ErrorKind::InvalidData, + borsh::__private::maybestd::format!( + "Unexpected variant tag: {:?}", variant_tag + ), + ), + ) + }; + ::core::result::Result::Ok(return_value) + } +} diff --git a/borsh-derive/src/internals/deserialize/enums/snapshots/generic_deserialize_bound-2.snap b/borsh-derive/src/internals/deserialize/enums/snapshots/generic_deserialize_bound-2.snap new file mode 100644 index 000000000..0eedb6981 --- /dev/null +++ b/borsh-derive/src/internals/deserialize/enums/snapshots/generic_deserialize_bound-2.snap @@ -0,0 +1,54 @@ +--- +source: borsh-derive/src/internals/deserialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::de::BorshDeserializeAsync for A +where + T: borsh::de::BorshDeserializeAsync, + U: borsh::de::BorshDeserializeAsync, +{ + async fn deserialize_reader<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + ) -> ::core::result::Result { + let tag = ::deserialize_reader(reader) + .await?; + ::deserialize_variant(reader, tag).await + } +} +impl borsh::de::EnumExtAsync for A +where + T: borsh::de::BorshDeserializeAsync, + U: borsh::de::BorshDeserializeAsync, +{ + async fn deserialize_variant<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + variant_tag: u8, + ) -> ::core::result::Result { + let return_value = if variant_tag == 0u8 { + A::C { + a: ::deserialize_reader(reader) + .await?, + b: as borsh::BorshDeserializeAsync>::deserialize_reader(reader) + .await?, + } + } else if variant_tag == 1u8 { + A::D( + ::deserialize_reader(reader).await?, + ::deserialize_reader(reader).await?, + ) + } else { + return ::core::result::Result::Err( + borsh::io::Error::new( + borsh::io::ErrorKind::InvalidData, + borsh::__private::maybestd::format!( + "Unexpected variant tag: {:?}", variant_tag + ), + ), + ) + }; + ::core::result::Result::Ok(return_value) + } +} diff --git a/borsh-derive/src/internals/deserialize/enums/snapshots/generic_deserialize_bound.snap b/borsh-derive/src/internals/deserialize/enums/snapshots/generic_deserialize_bound.snap index adf641118..75ac1987e 100644 --- a/borsh-derive/src/internals/deserialize/enums/snapshots/generic_deserialize_bound.snap +++ b/borsh-derive/src/internals/deserialize/enums/snapshots/generic_deserialize_bound.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/deserialize/enums/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::de::BorshDeserialize for A where @@ -23,18 +23,21 @@ where reader: &mut __R, variant_tag: u8, ) -> ::core::result::Result { - let mut return_value = if variant_tag == 0u8 { + let return_value = if variant_tag == 0u8 { A::C { - a: borsh::BorshDeserialize::deserialize_reader(reader)?, - b: borsh::BorshDeserialize::deserialize_reader(reader)?, + a: ::deserialize_reader(reader)?, + b: as borsh::BorshDeserialize>::deserialize_reader(reader)?, } } else if variant_tag == 1u8 { A::D( - borsh::BorshDeserialize::deserialize_reader(reader)?, - borsh::BorshDeserialize::deserialize_reader(reader)?, + ::deserialize_reader(reader)?, + ::deserialize_reader(reader)?, ) } else { - return Err( + return ::core::result::Result::Err( borsh::io::Error::new( borsh::io::ErrorKind::InvalidData, borsh::__private::maybestd::format!( @@ -43,6 +46,6 @@ where ), ) }; - Ok(return_value) + ::core::result::Result::Ok(return_value) } } diff --git a/borsh-derive/src/internals/deserialize/enums/snapshots/recursive_enum-2.snap b/borsh-derive/src/internals/deserialize/enums/snapshots/recursive_enum-2.snap new file mode 100644 index 000000000..705858356 --- /dev/null +++ b/borsh-derive/src/internals/deserialize/enums/snapshots/recursive_enum-2.snap @@ -0,0 +1,57 @@ +--- +source: borsh-derive/src/internals/deserialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::de::BorshDeserializeAsync for A +where + V: Value, + K: borsh::de::BorshDeserializeAsync, + V: borsh::de::BorshDeserializeAsync, +{ + async fn deserialize_reader<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + ) -> ::core::result::Result { + let tag = ::deserialize_reader(reader) + .await?; + ::deserialize_variant(reader, tag).await + } +} +impl borsh::de::EnumExtAsync for A +where + V: Value, + K: borsh::de::BorshDeserializeAsync, + V: borsh::de::BorshDeserializeAsync, +{ + async fn deserialize_variant<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + variant_tag: u8, + ) -> ::core::result::Result { + let return_value = if variant_tag == 0u8 { + A::B { + x: as borsh::BorshDeserializeAsync>::deserialize_reader(reader) + .await?, + y: ::deserialize_reader(reader) + .await?, + } + } else if variant_tag == 1u8 { + A::C( + ::deserialize_reader(reader).await?, + as borsh::BorshDeserializeAsync>::deserialize_reader(reader) + .await?, + ) + } else { + return ::core::result::Result::Err( + borsh::io::Error::new( + borsh::io::ErrorKind::InvalidData, + borsh::__private::maybestd::format!( + "Unexpected variant tag: {:?}", variant_tag + ), + ), + ) + }; + ::core::result::Result::Ok(return_value) + } +} diff --git a/borsh-derive/src/internals/deserialize/enums/snapshots/recursive_enum.snap b/borsh-derive/src/internals/deserialize/enums/snapshots/recursive_enum.snap index b3c8f7790..852382274 100644 --- a/borsh-derive/src/internals/deserialize/enums/snapshots/recursive_enum.snap +++ b/borsh-derive/src/internals/deserialize/enums/snapshots/recursive_enum.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/deserialize/enums/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::de::BorshDeserialize for A where @@ -25,18 +25,21 @@ where reader: &mut __R, variant_tag: u8, ) -> ::core::result::Result { - let mut return_value = if variant_tag == 0u8 { + let return_value = if variant_tag == 0u8 { A::B { - x: borsh::BorshDeserialize::deserialize_reader(reader)?, - y: borsh::BorshDeserialize::deserialize_reader(reader)?, + x: as borsh::BorshDeserialize>::deserialize_reader(reader)?, + y: ::deserialize_reader(reader)?, } } else if variant_tag == 1u8 { A::C( - borsh::BorshDeserialize::deserialize_reader(reader)?, - borsh::BorshDeserialize::deserialize_reader(reader)?, + ::deserialize_reader(reader)?, + as borsh::BorshDeserialize>::deserialize_reader(reader)?, ) } else { - return Err( + return ::core::result::Result::Err( borsh::io::Error::new( borsh::io::ErrorKind::InvalidData, borsh::__private::maybestd::format!( @@ -45,6 +48,6 @@ where ), ) }; - Ok(return_value) + ::core::result::Result::Ok(return_value) } } diff --git a/borsh-derive/src/internals/deserialize/enums/snapshots/simple_enum_with_custom_crate-2.snap b/borsh-derive/src/internals/deserialize/enums/snapshots/simple_enum_with_custom_crate-2.snap new file mode 100644 index 000000000..a6eb2c787 --- /dev/null +++ b/borsh-derive/src/internals/deserialize/enums/snapshots/simple_enum_with_custom_crate-2.snap @@ -0,0 +1,61 @@ +--- +source: borsh-derive/src/internals/deserialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl reexporter::borsh::de::BorshDeserializeAsync for A { + async fn deserialize_reader<__R: reexporter::borsh::async_io::AsyncRead>( + reader: &mut __R, + ) -> ::core::result::Result { + let tag = ::deserialize_reader( + reader, + ) + .await?; + ::deserialize_variant(reader, tag) + .await + } +} +impl reexporter::borsh::de::EnumExtAsync for A { + async fn deserialize_variant<__R: reexporter::borsh::async_io::AsyncRead>( + reader: &mut __R, + variant_tag: u8, + ) -> ::core::result::Result { + let return_value = if variant_tag == 0u8 { + A::B { + x: as reexporter::borsh::BorshDeserializeAsync>::deserialize_reader( + reader, + ) + .await?, + y: ::deserialize_reader( + reader, + ) + .await?, + } + } else if variant_tag == 1u8 { + A::C( + ::deserialize_reader( + reader, + ) + .await?, + as reexporter::borsh::BorshDeserializeAsync>::deserialize_reader( + reader, + ) + .await?, + ) + } else { + return ::core::result::Result::Err( + reexporter::borsh::io::Error::new( + reexporter::borsh::io::ErrorKind::InvalidData, + reexporter::borsh::__private::maybestd::format!( + "Unexpected variant tag: {:?}", variant_tag + ), + ), + ) + }; + ::core::result::Result::Ok(return_value) + } +} diff --git a/borsh-derive/src/internals/deserialize/enums/snapshots/simple_enum_with_custom_crate.snap b/borsh-derive/src/internals/deserialize/enums/snapshots/simple_enum_with_custom_crate.snap index 88457ee99..16400f884 100644 --- a/borsh-derive/src/internals/deserialize/enums/snapshots/simple_enum_with_custom_crate.snap +++ b/borsh-derive/src/internals/deserialize/enums/snapshots/simple_enum_with_custom_crate.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/deserialize/enums/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl reexporter::borsh::de::BorshDeserialize for A { fn deserialize_reader<__R: reexporter::borsh::io::Read>( @@ -17,18 +17,25 @@ impl reexporter::borsh::de::EnumExt for A { reader: &mut __R, variant_tag: u8, ) -> ::core::result::Result { - let mut return_value = if variant_tag == 0u8 { + let return_value = if variant_tag == 0u8 { A::B { - x: reexporter::borsh::BorshDeserialize::deserialize_reader(reader)?, - y: reexporter::borsh::BorshDeserialize::deserialize_reader(reader)?, + x: as reexporter::borsh::BorshDeserialize>::deserialize_reader(reader)?, + y: ::deserialize_reader( + reader, + )?, } } else if variant_tag == 1u8 { A::C( - reexporter::borsh::BorshDeserialize::deserialize_reader(reader)?, - reexporter::borsh::BorshDeserialize::deserialize_reader(reader)?, + ::deserialize_reader(reader)?, + as reexporter::borsh::BorshDeserialize>::deserialize_reader(reader)?, ) } else { - return Err( + return ::core::result::Result::Err( reexporter::borsh::io::Error::new( reexporter::borsh::io::ErrorKind::InvalidData, reexporter::borsh::__private::maybestd::format!( @@ -37,6 +44,6 @@ impl reexporter::borsh::de::EnumExt for A { ), ) }; - Ok(return_value) + ::core::result::Result::Ok(return_value) } } diff --git a/borsh-derive/src/internals/deserialize/enums/snapshots/simple_generics-2.snap b/borsh-derive/src/internals/deserialize/enums/snapshots/simple_generics-2.snap new file mode 100644 index 000000000..e39c1335d --- /dev/null +++ b/borsh-derive/src/internals/deserialize/enums/snapshots/simple_generics-2.snap @@ -0,0 +1,57 @@ +--- +source: borsh-derive/src/internals/deserialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::de::BorshDeserializeAsync for A +where + K: borsh::de::BorshDeserializeAsync, + V: borsh::de::BorshDeserializeAsync, + U: borsh::de::BorshDeserializeAsync, +{ + async fn deserialize_reader<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + ) -> ::core::result::Result { + let tag = ::deserialize_reader(reader) + .await?; + ::deserialize_variant(reader, tag).await + } +} +impl borsh::de::EnumExtAsync for A +where + K: borsh::de::BorshDeserializeAsync, + V: borsh::de::BorshDeserializeAsync, + U: borsh::de::BorshDeserializeAsync, +{ + async fn deserialize_variant<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + variant_tag: u8, + ) -> ::core::result::Result { + let return_value = if variant_tag == 0u8 { + A::B { + x: as borsh::BorshDeserializeAsync>::deserialize_reader(reader) + .await?, + y: ::deserialize_reader(reader) + .await?, + } + } else if variant_tag == 1u8 { + A::C( + ::deserialize_reader(reader).await?, + as borsh::BorshDeserializeAsync>::deserialize_reader(reader) + .await?, + ) + } else { + return ::core::result::Result::Err( + borsh::io::Error::new( + borsh::io::ErrorKind::InvalidData, + borsh::__private::maybestd::format!( + "Unexpected variant tag: {:?}", variant_tag + ), + ), + ) + }; + ::core::result::Result::Ok(return_value) + } +} diff --git a/borsh-derive/src/internals/deserialize/enums/snapshots/simple_generics.snap b/borsh-derive/src/internals/deserialize/enums/snapshots/simple_generics.snap index d8b85259c..ef9765ea6 100644 --- a/borsh-derive/src/internals/deserialize/enums/snapshots/simple_generics.snap +++ b/borsh-derive/src/internals/deserialize/enums/snapshots/simple_generics.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/deserialize/enums/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::de::BorshDeserialize for A where @@ -25,18 +25,21 @@ where reader: &mut __R, variant_tag: u8, ) -> ::core::result::Result { - let mut return_value = if variant_tag == 0u8 { + let return_value = if variant_tag == 0u8 { A::B { - x: borsh::BorshDeserialize::deserialize_reader(reader)?, - y: borsh::BorshDeserialize::deserialize_reader(reader)?, + x: as borsh::BorshDeserialize>::deserialize_reader(reader)?, + y: ::deserialize_reader(reader)?, } } else if variant_tag == 1u8 { A::C( - borsh::BorshDeserialize::deserialize_reader(reader)?, - borsh::BorshDeserialize::deserialize_reader(reader)?, + ::deserialize_reader(reader)?, + as borsh::BorshDeserialize>::deserialize_reader(reader)?, ) } else { - return Err( + return ::core::result::Result::Err( borsh::io::Error::new( borsh::io::ErrorKind::InvalidData, borsh::__private::maybestd::format!( @@ -45,6 +48,6 @@ where ), ) }; - Ok(return_value) + ::core::result::Result::Ok(return_value) } } diff --git a/borsh-derive/src/internals/deserialize/mod.rs b/borsh-derive/src/internals/deserialize/mod.rs index f9732c05f..166841979 100644 --- a/borsh-derive/src/internals/deserialize/mod.rs +++ b/borsh-derive/src/internals/deserialize/mod.rs @@ -1,6 +1,6 @@ use proc_macro2::TokenStream as TokenStream2; use quote::quote; -use syn::{ExprPath, Generics, Ident, Path}; +use syn::{parse_quote, ExprPath, Generics, Ident, Path, Type}; use super::{ attributes::{field, BoundType}, @@ -25,9 +25,14 @@ impl GenericsOutput { default_visitor: generics::FindTyParams::new(generics), } } - fn extend(self, where_clause: &mut syn::WhereClause, cratename: &Path) { - let de_trait: Path = syn::parse2(quote! { #cratename::de::BorshDeserialize }).unwrap(); - let default_trait: Path = syn::parse2(quote! { core::default::Default }).unwrap(); + + fn extend(self, where_clause: &mut syn::WhereClause, cratename: &Path) { + let de_trait: Path = if IS_ASYNC { + parse_quote! { #cratename::de::BorshDeserializeAsync } + } else { + parse_quote! { #cratename::de::BorshDeserialize } + }; + let default_trait: Path = parse_quote! { ::core::default::Default }; let de_predicates = generics::compute_predicates(self.deserialize_visitor.process_for_bounds(), &de_trait); let default_predicates = @@ -38,7 +43,7 @@ impl GenericsOutput { } } -fn process_field( +fn process_field( field: &syn::Field, cratename: &Path, body: &mut TokenStream2, @@ -46,10 +51,16 @@ fn process_field( ) -> syn::Result<()> { let parsed = field::Attributes::parse(&field.attrs)?; - generics - .overrides - .extend(parsed.collect_bounds(BoundType::Deserialize)); - let needs_bounds_derive = parsed.needs_bounds_derive(BoundType::Deserialize); + generics.overrides.extend(if IS_ASYNC { + parsed.collect_async_bounds(BoundType::Deserialize) + } else { + parsed.collect_bounds(BoundType::Deserialize) + }); + let needs_bounds_derive = if IS_ASYNC { + parsed.needs_async_bounds_derive(BoundType::Deserialize) + } else { + parsed.needs_bounds_derive(BoundType::Deserialize) + }; let field_name = field.ident.as_ref(); let delta = if parsed.skip { @@ -61,7 +72,16 @@ fn process_field( if needs_bounds_derive { generics.deserialize_visitor.visit_field(field); } - field_output(field_name, cratename, parsed.deserialize_with) + field_output::( + field_name, + &field.ty, + cratename, + if IS_ASYNC { + parsed.deserialize_with_async + } else { + parsed.deserialize_with + }, + ) }; body.extend(delta); Ok(()) @@ -69,22 +89,31 @@ fn process_field( /// function which computes derive output [proc_macro2::TokenStream] /// of code, which deserializes single field -fn field_output( +fn field_output( field_name: Option<&Ident>, + field_type: &Type, cratename: &Path, deserialize_with: Option, ) -> TokenStream2 { - let default_path: ExprPath = - syn::parse2(quote! { #cratename::BorshDeserialize::deserialize_reader }).unwrap(); - let path: ExprPath = deserialize_with.unwrap_or(default_path); + let default_path = || { + let deserialize_trait = Ident::new( + if IS_ASYNC { + "BorshDeserializeAsync" + } else { + "BorshDeserialize" + }, + proc_macro2::Span::call_site(), + ); + parse_quote! { <#field_type as #cratename::#deserialize_trait>::deserialize_reader } + }; + + let path: ExprPath = deserialize_with.unwrap_or_else(default_path); + let dot_await = IS_ASYNC.then(|| quote! { .await }); + if let Some(field_name) = field_name { - quote! { - #field_name: #path(reader)?, - } + quote! { #field_name: #path(reader)#dot_await?, } } else { - quote! { - #path(reader)?, - } + quote! { #path(reader)#dot_await?, } } } @@ -92,10 +121,8 @@ fn field_output( /// of code, which deserializes single skipped field fn field_default_output(field_name: Option<&Ident>) -> TokenStream2 { if let Some(field_name) = field_name { - quote! { - #field_name: core::default::Default::default(), - } + quote! { #field_name: ::core::default::Default::default(), } } else { - quote! { core::default::Default::default(), } + quote! { ::core::default::Default::default(), } } } diff --git a/borsh-derive/src/internals/deserialize/structs/mod.rs b/borsh-derive/src/internals/deserialize/structs/mod.rs index 0faaec309..759628f76 100644 --- a/borsh-derive/src/internals/deserialize/structs/mod.rs +++ b/borsh-derive/src/internals/deserialize/structs/mod.rs @@ -1,12 +1,15 @@ -use proc_macro2::TokenStream as TokenStream2; +use proc_macro2::{Ident, Span, TokenStream as TokenStream2}; use quote::quote; -use syn::{Fields, ItemStruct, Path}; +use syn::{Fields, ItemStruct, Path, Token}; use crate::internals::{attributes::item, deserialize, generics}; -pub fn process(input: &ItemStruct, cratename: Path) -> syn::Result { +pub fn process( + input: ItemStruct, + cratename: Path, +) -> syn::Result { let name = &input.ident; - let generics = generics::without_defaults(&input.generics); + let generics = generics::without_defaults(input.generics); let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); let mut where_clause = generics::default_where(where_clause); let mut body = TokenStream2::new(); @@ -15,193 +18,222 @@ pub fn process(input: &ItemStruct, cratename: Path) -> syn::Result let return_value = match &input.fields { Fields::Named(fields) => { for field in &fields.named { - deserialize::process_field(field, &cratename, &mut body, &mut generics_output)?; - } - quote! { - Self { #body } + deserialize::process_field::( + field, + &cratename, + &mut body, + &mut generics_output, + )?; } + quote! { Self { #body } } } Fields::Unnamed(fields) => { for field in fields.unnamed.iter() { - deserialize::process_field(field, &cratename, &mut body, &mut generics_output)?; - } - quote! { - Self( #body ) - } - } - Fields::Unit => { - quote! { - Self {} + deserialize::process_field::( + field, + &cratename, + &mut body, + &mut generics_output, + )?; } + quote! { Self( #body ) } } + Fields::Unit => quote! { Self {} }, }; - generics_output.extend(&mut where_clause, &cratename); - - if let Some(method_ident) = item::contains_initialize_with(&input.attrs)? { - Ok(quote! { - impl #impl_generics #cratename::de::BorshDeserialize for #name #ty_generics #where_clause { - fn deserialize_reader<__R: #cratename::io::Read>(reader: &mut __R) -> ::core::result::Result { - let mut return_value = #return_value; - return_value.#method_ident(); - Ok(return_value) - } - } - }) + generics_output.extend::(&mut where_clause, &cratename); + + let deserialize_trait = Ident::new( + if IS_ASYNC { + "BorshDeserializeAsync" + } else { + "BorshDeserialize" + }, + Span::call_site(), + ); + let read_trait_path = if IS_ASYNC { + quote! { async_io::AsyncRead } } else { - Ok(quote! { - impl #impl_generics #cratename::de::BorshDeserialize for #name #ty_generics #where_clause { - fn deserialize_reader<__R: #cratename::io::Read>(reader: &mut __R) -> ::core::result::Result { - Ok(#return_value) - } + quote! { io::Read } + }; + let r#async = IS_ASYNC.then(|| Token![async](Span::call_site())); + + let body = if let Some(method_ident) = item::contains_initialize_with(&input.attrs)? { + quote! { + let mut return_value = #return_value; + return_value.#method_ident(); + ::core::result::Result::Ok(return_value) + } + } else { + quote! { ::core::result::Result::Ok(#return_value) } + }; + + Ok(quote! { + impl #impl_generics #cratename::de::#deserialize_trait for #name #ty_generics #where_clause { + #r#async fn deserialize_reader<__R: #cratename::#read_trait_path>(reader: &mut __R) -> ::core::result::Result { + #body } - }) - } + } + }) } #[cfg(test)] mod tests { + use syn::parse_quote; + + use super::*; use crate::internals::test_helpers::{ default_cratename, local_insta_assert_snapshot, pretty_print_syn_str, }; - use super::*; - #[test] fn simple_struct() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A { x: u64, y: String, } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process::(item_struct.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn simple_struct_with_custom_crate() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A { x: u64, y: String, } - }) - .unwrap(); + }; - let crate_: Path = syn::parse2(quote! { reexporter::borsh }).unwrap(); - let actual = process(&item_struct, crate_).unwrap(); + let crate_: Path = parse_quote! { reexporter::borsh }; - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_struct.clone(), crate_.clone()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); + + let actual = process::(item_struct, crate_).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn simple_generics() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A { x: HashMap, y: String, } - }) - .unwrap(); + }; + + let actual = process::(item_struct.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - let actual = process(&item_struct, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn simple_generic_tuple_struct() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct TupleA(T, u32); - }) - .unwrap(); + }; + + let actual = process::(item_struct.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - let actual = process(&item_struct, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn bound_generics() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A where V: Value { x: HashMap, y: String, } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_struct.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); + + let actual = process::(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn recursive_struct() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct CRecC { a: String, b: HashMap, } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process::(item_struct.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn generic_tuple_struct_borsh_skip1() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct G ( #[borsh(skip)] HashMap, U, ); - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process::(item_struct.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn generic_tuple_struct_borsh_skip2() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct G ( HashMap, #[borsh(skip)] U, ); - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process::(item_struct.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn generic_named_fields_struct_borsh_skip() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct G { #[borsh(skip)] x: HashMap, y: U, } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process::(item_struct.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn generic_deserialize_bound() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct C { a: String, #[borsh(bound(deserialize = @@ -210,56 +242,117 @@ mod tests { ))] b: HashMap, } - }) - .unwrap(); + }; + + let actual = process::(item_struct.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); + + let actual = process::(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); + } + + #[test] + fn generic_deserialize_async_bound() { + let item_struct: ItemStruct = parse_quote! { + struct C { + a: String, + #[borsh(async_bound(deserialize = + "T: PartialOrd + Hash + Eq + borsh::de::BorshDeserializeAsync, + U: borsh::de::BorshDeserializeAsync" + ))] + b: HashMap, + } + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process::(item_struct.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn test_override_automatically_added_default_trait() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct G1( #[borsh(skip,bound(deserialize = ""))] HashMap, U ); - }) - .unwrap(); + }; + + let actual = process::(item_struct.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); + + let actual = process::(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); + } + + #[test] + fn test_override_automatically_added_default_trait_async() { + let item_struct: ItemStruct = parse_quote! { + struct G1( + #[borsh(skip,async_bound(deserialize = ""))] + HashMap, + U + ); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process::(item_struct.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn check_deserialize_with_attr() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A { #[borsh(deserialize_with = "third_party_impl::deserialize_third_party")] x: ThirdParty, y: u64, } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process::(item_struct.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } + + #[test] + fn check_deserialize_with_async_attr() { + let item_struct: ItemStruct = parse_quote! { + struct A { + #[borsh(deserialize_with_async = "third_party_impl::deserialize_third_party")] + x: ThirdParty, + y: u64, + } + }; + + let actual = process::(item_struct.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); + + let actual = process::(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); + } + #[test] fn borsh_init_func() { - let item_enum: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { #[borsh(init=initialization_method)] struct A { x: u64, y: String, } - }) - .unwrap(); - let actual = process(&item_enum, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + }; + + let actual = process::(item_struct.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); + + let actual = process::(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } } diff --git a/borsh-derive/src/internals/deserialize/structs/snapshots/borsh_init_func-2.snap b/borsh-derive/src/internals/deserialize/structs/snapshots/borsh_init_func-2.snap new file mode 100644 index 000000000..5c52c0507 --- /dev/null +++ b/borsh-derive/src/internals/deserialize/structs/snapshots/borsh_init_func-2.snap @@ -0,0 +1,17 @@ +--- +source: borsh-derive/src/internals/deserialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::de::BorshDeserializeAsync for A { + async fn deserialize_reader<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + ) -> ::core::result::Result { + let mut return_value = Self { + x: ::deserialize_reader(reader).await?, + y: ::deserialize_reader(reader) + .await?, + }; + return_value.initialization_method(); + ::core::result::Result::Ok(return_value) + } +} diff --git a/borsh-derive/src/internals/deserialize/structs/snapshots/borsh_init_func.snap b/borsh-derive/src/internals/deserialize/structs/snapshots/borsh_init_func.snap index 61f51e48e..e449e90f7 100644 --- a/borsh-derive/src/internals/deserialize/structs/snapshots/borsh_init_func.snap +++ b/borsh-derive/src/internals/deserialize/structs/snapshots/borsh_init_func.snap @@ -1,16 +1,16 @@ --- source: borsh-derive/src/internals/deserialize/structs/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::de::BorshDeserialize for A { fn deserialize_reader<__R: borsh::io::Read>( reader: &mut __R, ) -> ::core::result::Result { let mut return_value = Self { - x: borsh::BorshDeserialize::deserialize_reader(reader)?, - y: borsh::BorshDeserialize::deserialize_reader(reader)?, + x: ::deserialize_reader(reader)?, + y: ::deserialize_reader(reader)?, }; return_value.initialization_method(); - Ok(return_value) + ::core::result::Result::Ok(return_value) } } diff --git a/borsh-derive/src/internals/deserialize/structs/snapshots/bound_generics-2.snap b/borsh-derive/src/internals/deserialize/structs/snapshots/bound_generics-2.snap new file mode 100644 index 000000000..ef7898f88 --- /dev/null +++ b/borsh-derive/src/internals/deserialize/structs/snapshots/bound_generics-2.snap @@ -0,0 +1,24 @@ +--- +source: borsh-derive/src/internals/deserialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::de::BorshDeserializeAsync for A +where + V: Value, + K: borsh::de::BorshDeserializeAsync, + V: borsh::de::BorshDeserializeAsync, +{ + async fn deserialize_reader<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + ) -> ::core::result::Result { + ::core::result::Result::Ok(Self { + x: as borsh::BorshDeserializeAsync>::deserialize_reader(reader) + .await?, + y: ::deserialize_reader(reader) + .await?, + }) + } +} diff --git a/borsh-derive/src/internals/deserialize/structs/snapshots/bound_generics.snap b/borsh-derive/src/internals/deserialize/structs/snapshots/bound_generics.snap index dc4514d64..81363ce72 100644 --- a/borsh-derive/src/internals/deserialize/structs/snapshots/bound_generics.snap +++ b/borsh-derive/src/internals/deserialize/structs/snapshots/bound_generics.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/deserialize/structs/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::de::BorshDeserialize for A where @@ -11,9 +11,9 @@ where fn deserialize_reader<__R: borsh::io::Read>( reader: &mut __R, ) -> ::core::result::Result { - Ok(Self { - x: borsh::BorshDeserialize::deserialize_reader(reader)?, - y: borsh::BorshDeserialize::deserialize_reader(reader)?, + ::core::result::Result::Ok(Self { + x: as borsh::BorshDeserialize>::deserialize_reader(reader)?, + y: ::deserialize_reader(reader)?, }) } } diff --git a/borsh-derive/src/internals/deserialize/structs/snapshots/check_deserialize_with_async_attr-2.snap b/borsh-derive/src/internals/deserialize/structs/snapshots/check_deserialize_with_async_attr-2.snap new file mode 100644 index 000000000..a4a594f06 --- /dev/null +++ b/borsh-derive/src/internals/deserialize/structs/snapshots/check_deserialize_with_async_attr-2.snap @@ -0,0 +1,18 @@ +--- +source: borsh-derive/src/internals/deserialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::de::BorshDeserializeAsync for A +where + K: borsh::de::BorshDeserializeAsync, + V: borsh::de::BorshDeserializeAsync, +{ + async fn deserialize_reader<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + ) -> ::core::result::Result { + ::core::result::Result::Ok(Self { + x: third_party_impl::deserialize_third_party(reader).await?, + y: ::deserialize_reader(reader).await?, + }) + } +} diff --git a/borsh-derive/src/internals/deserialize/structs/snapshots/check_deserialize_with_async_attr.snap b/borsh-derive/src/internals/deserialize/structs/snapshots/check_deserialize_with_async_attr.snap new file mode 100644 index 000000000..7d0159738 --- /dev/null +++ b/borsh-derive/src/internals/deserialize/structs/snapshots/check_deserialize_with_async_attr.snap @@ -0,0 +1,21 @@ +--- +source: borsh-derive/src/internals/deserialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::de::BorshDeserialize for A +where + K: borsh::de::BorshDeserialize, + V: borsh::de::BorshDeserialize, +{ + fn deserialize_reader<__R: borsh::io::Read>( + reader: &mut __R, + ) -> ::core::result::Result { + ::core::result::Result::Ok(Self { + x: as borsh::BorshDeserialize>::deserialize_reader(reader)?, + y: ::deserialize_reader(reader)?, + }) + } +} diff --git a/borsh-derive/src/internals/deserialize/structs/snapshots/check_deserialize_with_attr-2.snap b/borsh-derive/src/internals/deserialize/structs/snapshots/check_deserialize_with_attr-2.snap new file mode 100644 index 000000000..f9f1899de --- /dev/null +++ b/borsh-derive/src/internals/deserialize/structs/snapshots/check_deserialize_with_attr-2.snap @@ -0,0 +1,22 @@ +--- +source: borsh-derive/src/internals/deserialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::de::BorshDeserializeAsync for A +where + K: borsh::de::BorshDeserializeAsync, + V: borsh::de::BorshDeserializeAsync, +{ + async fn deserialize_reader<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + ) -> ::core::result::Result { + ::core::result::Result::Ok(Self { + x: as borsh::BorshDeserializeAsync>::deserialize_reader(reader) + .await?, + y: ::deserialize_reader(reader).await?, + }) + } +} diff --git a/borsh-derive/src/internals/deserialize/structs/snapshots/check_deserialize_with_attr.snap b/borsh-derive/src/internals/deserialize/structs/snapshots/check_deserialize_with_attr.snap index 79a844803..8eb7e2997 100644 --- a/borsh-derive/src/internals/deserialize/structs/snapshots/check_deserialize_with_attr.snap +++ b/borsh-derive/src/internals/deserialize/structs/snapshots/check_deserialize_with_attr.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/deserialize/structs/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::de::BorshDeserialize for A where @@ -10,9 +10,9 @@ where fn deserialize_reader<__R: borsh::io::Read>( reader: &mut __R, ) -> ::core::result::Result { - Ok(Self { + ::core::result::Result::Ok(Self { x: third_party_impl::deserialize_third_party(reader)?, - y: borsh::BorshDeserialize::deserialize_reader(reader)?, + y: ::deserialize_reader(reader)?, }) } } diff --git a/borsh-derive/src/internals/deserialize/structs/snapshots/generic_deserialize_async_bound-2.snap b/borsh-derive/src/internals/deserialize/structs/snapshots/generic_deserialize_async_bound-2.snap new file mode 100644 index 000000000..48f831c7c --- /dev/null +++ b/borsh-derive/src/internals/deserialize/structs/snapshots/generic_deserialize_async_bound-2.snap @@ -0,0 +1,23 @@ +--- +source: borsh-derive/src/internals/deserialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::de::BorshDeserializeAsync for C +where + T: PartialOrd + Hash + Eq + borsh::de::BorshDeserializeAsync, + U: borsh::de::BorshDeserializeAsync, +{ + async fn deserialize_reader<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + ) -> ::core::result::Result { + ::core::result::Result::Ok(Self { + a: ::deserialize_reader(reader) + .await?, + b: as borsh::BorshDeserializeAsync>::deserialize_reader(reader) + .await?, + }) + } +} diff --git a/borsh-derive/src/internals/deserialize/structs/snapshots/generic_deserialize_async_bound.snap b/borsh-derive/src/internals/deserialize/structs/snapshots/generic_deserialize_async_bound.snap new file mode 100644 index 000000000..634f837ce --- /dev/null +++ b/borsh-derive/src/internals/deserialize/structs/snapshots/generic_deserialize_async_bound.snap @@ -0,0 +1,18 @@ +--- +source: borsh-derive/src/internals/deserialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::de::BorshDeserialize for C +where + T: borsh::de::BorshDeserialize, + U: borsh::de::BorshDeserialize, +{ + fn deserialize_reader<__R: borsh::io::Read>( + reader: &mut __R, + ) -> ::core::result::Result { + ::core::result::Result::Ok(Self { + a: ::deserialize_reader(reader)?, + b: as borsh::BorshDeserialize>::deserialize_reader(reader)?, + }) + } +} diff --git a/borsh-derive/src/internals/deserialize/structs/snapshots/generic_deserialize_bound-2.snap b/borsh-derive/src/internals/deserialize/structs/snapshots/generic_deserialize_bound-2.snap new file mode 100644 index 000000000..808a8ee96 --- /dev/null +++ b/borsh-derive/src/internals/deserialize/structs/snapshots/generic_deserialize_bound-2.snap @@ -0,0 +1,23 @@ +--- +source: borsh-derive/src/internals/deserialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::de::BorshDeserializeAsync for C +where + T: borsh::de::BorshDeserializeAsync, + U: borsh::de::BorshDeserializeAsync, +{ + async fn deserialize_reader<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + ) -> ::core::result::Result { + ::core::result::Result::Ok(Self { + a: ::deserialize_reader(reader) + .await?, + b: as borsh::BorshDeserializeAsync>::deserialize_reader(reader) + .await?, + }) + } +} diff --git a/borsh-derive/src/internals/deserialize/structs/snapshots/generic_deserialize_bound.snap b/borsh-derive/src/internals/deserialize/structs/snapshots/generic_deserialize_bound.snap index 7e4a0317b..0eaeeed68 100644 --- a/borsh-derive/src/internals/deserialize/structs/snapshots/generic_deserialize_bound.snap +++ b/borsh-derive/src/internals/deserialize/structs/snapshots/generic_deserialize_bound.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/deserialize/structs/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::de::BorshDeserialize for C where @@ -10,9 +10,9 @@ where fn deserialize_reader<__R: borsh::io::Read>( reader: &mut __R, ) -> ::core::result::Result { - Ok(Self { - a: borsh::BorshDeserialize::deserialize_reader(reader)?, - b: borsh::BorshDeserialize::deserialize_reader(reader)?, + ::core::result::Result::Ok(Self { + a: ::deserialize_reader(reader)?, + b: as borsh::BorshDeserialize>::deserialize_reader(reader)?, }) } } diff --git a/borsh-derive/src/internals/deserialize/structs/snapshots/generic_named_fields_struct_borsh_skip-2.snap b/borsh-derive/src/internals/deserialize/structs/snapshots/generic_named_fields_struct_borsh_skip-2.snap new file mode 100644 index 000000000..aece060e2 --- /dev/null +++ b/borsh-derive/src/internals/deserialize/structs/snapshots/generic_named_fields_struct_borsh_skip-2.snap @@ -0,0 +1,19 @@ +--- +source: borsh-derive/src/internals/deserialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::de::BorshDeserializeAsync for G +where + U: borsh::de::BorshDeserializeAsync, + K: ::core::default::Default, + V: ::core::default::Default, +{ + async fn deserialize_reader<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + ) -> ::core::result::Result { + ::core::result::Result::Ok(Self { + x: ::core::default::Default::default(), + y: ::deserialize_reader(reader).await?, + }) + } +} diff --git a/borsh-derive/src/internals/deserialize/structs/snapshots/generic_named_fields_struct_borsh_skip.snap b/borsh-derive/src/internals/deserialize/structs/snapshots/generic_named_fields_struct_borsh_skip.snap index c094081c6..380e5b217 100644 --- a/borsh-derive/src/internals/deserialize/structs/snapshots/generic_named_fields_struct_borsh_skip.snap +++ b/borsh-derive/src/internals/deserialize/structs/snapshots/generic_named_fields_struct_borsh_skip.snap @@ -1,19 +1,19 @@ --- source: borsh-derive/src/internals/deserialize/structs/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::de::BorshDeserialize for G where U: borsh::de::BorshDeserialize, - K: core::default::Default, - V: core::default::Default, + K: ::core::default::Default, + V: ::core::default::Default, { fn deserialize_reader<__R: borsh::io::Read>( reader: &mut __R, ) -> ::core::result::Result { - Ok(Self { - x: core::default::Default::default(), - y: borsh::BorshDeserialize::deserialize_reader(reader)?, + ::core::result::Result::Ok(Self { + x: ::core::default::Default::default(), + y: ::deserialize_reader(reader)?, }) } } diff --git a/borsh-derive/src/internals/deserialize/structs/snapshots/generic_tuple_struct_borsh_skip1-2.snap b/borsh-derive/src/internals/deserialize/structs/snapshots/generic_tuple_struct_borsh_skip1-2.snap new file mode 100644 index 000000000..e3b9f09c3 --- /dev/null +++ b/borsh-derive/src/internals/deserialize/structs/snapshots/generic_tuple_struct_borsh_skip1-2.snap @@ -0,0 +1,21 @@ +--- +source: borsh-derive/src/internals/deserialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::de::BorshDeserializeAsync for G +where + U: borsh::de::BorshDeserializeAsync, + K: ::core::default::Default, + V: ::core::default::Default, +{ + async fn deserialize_reader<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + Self( + ::core::default::Default::default(), + ::deserialize_reader(reader).await?, + ), + ) + } +} diff --git a/borsh-derive/src/internals/deserialize/structs/snapshots/generic_tuple_struct_borsh_skip1.snap b/borsh-derive/src/internals/deserialize/structs/snapshots/generic_tuple_struct_borsh_skip1.snap index 492cc2b14..a9a2aec29 100644 --- a/borsh-derive/src/internals/deserialize/structs/snapshots/generic_tuple_struct_borsh_skip1.snap +++ b/borsh-derive/src/internals/deserialize/structs/snapshots/generic_tuple_struct_borsh_skip1.snap @@ -1,20 +1,20 @@ --- source: borsh-derive/src/internals/deserialize/structs/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::de::BorshDeserialize for G where U: borsh::de::BorshDeserialize, - K: core::default::Default, - V: core::default::Default, + K: ::core::default::Default, + V: ::core::default::Default, { fn deserialize_reader<__R: borsh::io::Read>( reader: &mut __R, ) -> ::core::result::Result { - Ok( + ::core::result::Result::Ok( Self( - core::default::Default::default(), - borsh::BorshDeserialize::deserialize_reader(reader)?, + ::core::default::Default::default(), + ::deserialize_reader(reader)?, ), ) } diff --git a/borsh-derive/src/internals/deserialize/structs/snapshots/generic_tuple_struct_borsh_skip2-2.snap b/borsh-derive/src/internals/deserialize/structs/snapshots/generic_tuple_struct_borsh_skip2-2.snap new file mode 100644 index 000000000..d2c09ca42 --- /dev/null +++ b/borsh-derive/src/internals/deserialize/structs/snapshots/generic_tuple_struct_borsh_skip2-2.snap @@ -0,0 +1,25 @@ +--- +source: borsh-derive/src/internals/deserialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::de::BorshDeserializeAsync for G +where + K: borsh::de::BorshDeserializeAsync, + V: borsh::de::BorshDeserializeAsync, + U: ::core::default::Default, +{ + async fn deserialize_reader<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + Self( + as borsh::BorshDeserializeAsync>::deserialize_reader(reader) + .await?, + ::core::default::Default::default(), + ), + ) + } +} diff --git a/borsh-derive/src/internals/deserialize/structs/snapshots/generic_tuple_struct_borsh_skip2.snap b/borsh-derive/src/internals/deserialize/structs/snapshots/generic_tuple_struct_borsh_skip2.snap index 5abdae6be..3caa0dc1c 100644 --- a/borsh-derive/src/internals/deserialize/structs/snapshots/generic_tuple_struct_borsh_skip2.snap +++ b/borsh-derive/src/internals/deserialize/structs/snapshots/generic_tuple_struct_borsh_skip2.snap @@ -1,20 +1,20 @@ --- source: borsh-derive/src/internals/deserialize/structs/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::de::BorshDeserialize for G where K: borsh::de::BorshDeserialize, V: borsh::de::BorshDeserialize, - U: core::default::Default, + U: ::core::default::Default, { fn deserialize_reader<__R: borsh::io::Read>( reader: &mut __R, ) -> ::core::result::Result { - Ok( + ::core::result::Result::Ok( Self( - borsh::BorshDeserialize::deserialize_reader(reader)?, - core::default::Default::default(), + as borsh::BorshDeserialize>::deserialize_reader(reader)?, + ::core::default::Default::default(), ), ) } diff --git a/borsh-derive/src/internals/deserialize/structs/snapshots/override_automatically_added_default_trait-2.snap b/borsh-derive/src/internals/deserialize/structs/snapshots/override_automatically_added_default_trait-2.snap new file mode 100644 index 000000000..edc0aaa54 --- /dev/null +++ b/borsh-derive/src/internals/deserialize/structs/snapshots/override_automatically_added_default_trait-2.snap @@ -0,0 +1,21 @@ +--- +source: borsh-derive/src/internals/deserialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::de::BorshDeserializeAsync for G1 +where + U: borsh::de::BorshDeserializeAsync, + K: ::core::default::Default, + V: ::core::default::Default, +{ + async fn deserialize_reader<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + Self( + ::core::default::Default::default(), + ::deserialize_reader(reader).await?, + ), + ) + } +} diff --git a/borsh-derive/src/internals/deserialize/structs/snapshots/override_automatically_added_default_trait.snap b/borsh-derive/src/internals/deserialize/structs/snapshots/override_automatically_added_default_trait.snap index 546931471..7110ab816 100644 --- a/borsh-derive/src/internals/deserialize/structs/snapshots/override_automatically_added_default_trait.snap +++ b/borsh-derive/src/internals/deserialize/structs/snapshots/override_automatically_added_default_trait.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/deserialize/structs/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::de::BorshDeserialize for G1 where @@ -9,10 +9,10 @@ where fn deserialize_reader<__R: borsh::io::Read>( reader: &mut __R, ) -> ::core::result::Result { - Ok( + ::core::result::Result::Ok( Self( - core::default::Default::default(), - borsh::BorshDeserialize::deserialize_reader(reader)?, + ::core::default::Default::default(), + ::deserialize_reader(reader)?, ), ) } diff --git a/borsh-derive/src/internals/deserialize/structs/snapshots/override_automatically_added_default_trait_async-2.snap b/borsh-derive/src/internals/deserialize/structs/snapshots/override_automatically_added_default_trait_async-2.snap new file mode 100644 index 000000000..d6174b721 --- /dev/null +++ b/borsh-derive/src/internals/deserialize/structs/snapshots/override_automatically_added_default_trait_async-2.snap @@ -0,0 +1,19 @@ +--- +source: borsh-derive/src/internals/deserialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::de::BorshDeserializeAsync for G1 +where + U: borsh::de::BorshDeserializeAsync, +{ + async fn deserialize_reader<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + Self( + ::core::default::Default::default(), + ::deserialize_reader(reader).await?, + ), + ) + } +} diff --git a/borsh-derive/src/internals/deserialize/structs/snapshots/override_automatically_added_default_trait_async.snap b/borsh-derive/src/internals/deserialize/structs/snapshots/override_automatically_added_default_trait_async.snap new file mode 100644 index 000000000..3b6968bc9 --- /dev/null +++ b/borsh-derive/src/internals/deserialize/structs/snapshots/override_automatically_added_default_trait_async.snap @@ -0,0 +1,21 @@ +--- +source: borsh-derive/src/internals/deserialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::de::BorshDeserialize for G1 +where + U: borsh::de::BorshDeserialize, + K: ::core::default::Default, + V: ::core::default::Default, +{ + fn deserialize_reader<__R: borsh::io::Read>( + reader: &mut __R, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + Self( + ::core::default::Default::default(), + ::deserialize_reader(reader)?, + ), + ) + } +} diff --git a/borsh-derive/src/internals/deserialize/structs/snapshots/recursive_struct-2.snap b/borsh-derive/src/internals/deserialize/structs/snapshots/recursive_struct-2.snap new file mode 100644 index 000000000..1a9ab454b --- /dev/null +++ b/borsh-derive/src/internals/deserialize/structs/snapshots/recursive_struct-2.snap @@ -0,0 +1,19 @@ +--- +source: borsh-derive/src/internals/deserialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::de::BorshDeserializeAsync for CRecC { + async fn deserialize_reader<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + ) -> ::core::result::Result { + ::core::result::Result::Ok(Self { + a: ::deserialize_reader(reader) + .await?, + b: as borsh::BorshDeserializeAsync>::deserialize_reader(reader) + .await?, + }) + } +} diff --git a/borsh-derive/src/internals/deserialize/structs/snapshots/recursive_struct.snap b/borsh-derive/src/internals/deserialize/structs/snapshots/recursive_struct.snap index 0dd795c39..2336313ce 100644 --- a/borsh-derive/src/internals/deserialize/structs/snapshots/recursive_struct.snap +++ b/borsh-derive/src/internals/deserialize/structs/snapshots/recursive_struct.snap @@ -1,14 +1,17 @@ --- source: borsh-derive/src/internals/deserialize/structs/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::de::BorshDeserialize for CRecC { fn deserialize_reader<__R: borsh::io::Read>( reader: &mut __R, ) -> ::core::result::Result { - Ok(Self { - a: borsh::BorshDeserialize::deserialize_reader(reader)?, - b: borsh::BorshDeserialize::deserialize_reader(reader)?, + ::core::result::Result::Ok(Self { + a: ::deserialize_reader(reader)?, + b: as borsh::BorshDeserialize>::deserialize_reader(reader)?, }) } } diff --git a/borsh-derive/src/internals/deserialize/structs/snapshots/simple_generic_tuple_struct-2.snap b/borsh-derive/src/internals/deserialize/structs/snapshots/simple_generic_tuple_struct-2.snap new file mode 100644 index 000000000..5b8829d6b --- /dev/null +++ b/borsh-derive/src/internals/deserialize/structs/snapshots/simple_generic_tuple_struct-2.snap @@ -0,0 +1,19 @@ +--- +source: borsh-derive/src/internals/deserialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::de::BorshDeserializeAsync for TupleA +where + T: borsh::de::BorshDeserializeAsync, +{ + async fn deserialize_reader<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + Self( + ::deserialize_reader(reader).await?, + ::deserialize_reader(reader).await?, + ), + ) + } +} diff --git a/borsh-derive/src/internals/deserialize/structs/snapshots/simple_generic_tuple_struct.snap b/borsh-derive/src/internals/deserialize/structs/snapshots/simple_generic_tuple_struct.snap index c1d69d951..8a5cdabd4 100644 --- a/borsh-derive/src/internals/deserialize/structs/snapshots/simple_generic_tuple_struct.snap +++ b/borsh-derive/src/internals/deserialize/structs/snapshots/simple_generic_tuple_struct.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/deserialize/structs/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::de::BorshDeserialize for TupleA where @@ -9,10 +9,10 @@ where fn deserialize_reader<__R: borsh::io::Read>( reader: &mut __R, ) -> ::core::result::Result { - Ok( + ::core::result::Result::Ok( Self( - borsh::BorshDeserialize::deserialize_reader(reader)?, - borsh::BorshDeserialize::deserialize_reader(reader)?, + ::deserialize_reader(reader)?, + ::deserialize_reader(reader)?, ), ) } diff --git a/borsh-derive/src/internals/deserialize/structs/snapshots/simple_generics-2.snap b/borsh-derive/src/internals/deserialize/structs/snapshots/simple_generics-2.snap new file mode 100644 index 000000000..482878f49 --- /dev/null +++ b/borsh-derive/src/internals/deserialize/structs/snapshots/simple_generics-2.snap @@ -0,0 +1,23 @@ +--- +source: borsh-derive/src/internals/deserialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::de::BorshDeserializeAsync for A +where + K: borsh::de::BorshDeserializeAsync, + V: borsh::de::BorshDeserializeAsync, +{ + async fn deserialize_reader<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + ) -> ::core::result::Result { + ::core::result::Result::Ok(Self { + x: as borsh::BorshDeserializeAsync>::deserialize_reader(reader) + .await?, + y: ::deserialize_reader(reader) + .await?, + }) + } +} diff --git a/borsh-derive/src/internals/deserialize/structs/snapshots/simple_generics.snap b/borsh-derive/src/internals/deserialize/structs/snapshots/simple_generics.snap index f2a8c7c4b..e1566514c 100644 --- a/borsh-derive/src/internals/deserialize/structs/snapshots/simple_generics.snap +++ b/borsh-derive/src/internals/deserialize/structs/snapshots/simple_generics.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/deserialize/structs/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::de::BorshDeserialize for A where @@ -10,9 +10,9 @@ where fn deserialize_reader<__R: borsh::io::Read>( reader: &mut __R, ) -> ::core::result::Result { - Ok(Self { - x: borsh::BorshDeserialize::deserialize_reader(reader)?, - y: borsh::BorshDeserialize::deserialize_reader(reader)?, + ::core::result::Result::Ok(Self { + x: as borsh::BorshDeserialize>::deserialize_reader(reader)?, + y: ::deserialize_reader(reader)?, }) } } diff --git a/borsh-derive/src/internals/deserialize/structs/snapshots/simple_struct-2.snap b/borsh-derive/src/internals/deserialize/structs/snapshots/simple_struct-2.snap new file mode 100644 index 000000000..c6676bac8 --- /dev/null +++ b/borsh-derive/src/internals/deserialize/structs/snapshots/simple_struct-2.snap @@ -0,0 +1,15 @@ +--- +source: borsh-derive/src/internals/deserialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::de::BorshDeserializeAsync for A { + async fn deserialize_reader<__R: borsh::async_io::AsyncRead>( + reader: &mut __R, + ) -> ::core::result::Result { + ::core::result::Result::Ok(Self { + x: ::deserialize_reader(reader).await?, + y: ::deserialize_reader(reader) + .await?, + }) + } +} diff --git a/borsh-derive/src/internals/deserialize/structs/snapshots/simple_struct.snap b/borsh-derive/src/internals/deserialize/structs/snapshots/simple_struct.snap index 6026d09f0..feaaa0d5e 100644 --- a/borsh-derive/src/internals/deserialize/structs/snapshots/simple_struct.snap +++ b/borsh-derive/src/internals/deserialize/structs/snapshots/simple_struct.snap @@ -1,14 +1,14 @@ --- source: borsh-derive/src/internals/deserialize/structs/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::de::BorshDeserialize for A { fn deserialize_reader<__R: borsh::io::Read>( reader: &mut __R, ) -> ::core::result::Result { - Ok(Self { - x: borsh::BorshDeserialize::deserialize_reader(reader)?, - y: borsh::BorshDeserialize::deserialize_reader(reader)?, + ::core::result::Result::Ok(Self { + x: ::deserialize_reader(reader)?, + y: ::deserialize_reader(reader)?, }) } } diff --git a/borsh-derive/src/internals/deserialize/structs/snapshots/simple_struct_with_custom_crate-2.snap b/borsh-derive/src/internals/deserialize/structs/snapshots/simple_struct_with_custom_crate-2.snap new file mode 100644 index 000000000..8cc625bae --- /dev/null +++ b/borsh-derive/src/internals/deserialize/structs/snapshots/simple_struct_with_custom_crate-2.snap @@ -0,0 +1,20 @@ +--- +source: borsh-derive/src/internals/deserialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl reexporter::borsh::de::BorshDeserializeAsync for A { + async fn deserialize_reader<__R: reexporter::borsh::async_io::AsyncRead>( + reader: &mut __R, + ) -> ::core::result::Result { + ::core::result::Result::Ok(Self { + x: ::deserialize_reader( + reader, + ) + .await?, + y: ::deserialize_reader( + reader, + ) + .await?, + }) + } +} diff --git a/borsh-derive/src/internals/deserialize/structs/snapshots/simple_struct_with_custom_crate.snap b/borsh-derive/src/internals/deserialize/structs/snapshots/simple_struct_with_custom_crate.snap index ad7fb3788..5d2e208e6 100644 --- a/borsh-derive/src/internals/deserialize/structs/snapshots/simple_struct_with_custom_crate.snap +++ b/borsh-derive/src/internals/deserialize/structs/snapshots/simple_struct_with_custom_crate.snap @@ -1,14 +1,16 @@ --- source: borsh-derive/src/internals/deserialize/structs/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl reexporter::borsh::de::BorshDeserialize for A { fn deserialize_reader<__R: reexporter::borsh::io::Read>( reader: &mut __R, ) -> ::core::result::Result { - Ok(Self { - x: reexporter::borsh::BorshDeserialize::deserialize_reader(reader)?, - y: reexporter::borsh::BorshDeserialize::deserialize_reader(reader)?, + ::core::result::Result::Ok(Self { + x: ::deserialize_reader(reader)?, + y: ::deserialize_reader( + reader, + )?, }) } } diff --git a/borsh-derive/src/internals/deserialize/unions/mod.rs b/borsh-derive/src/internals/deserialize/unions/mod.rs index 3806821bd..89200b4ea 100644 --- a/borsh-derive/src/internals/deserialize/unions/mod.rs +++ b/borsh-derive/src/internals/deserialize/unions/mod.rs @@ -1,6 +1,9 @@ use proc_macro2::TokenStream as TokenStream2; use syn::{ItemUnion, Path}; -pub fn process(_input: &ItemUnion, _cratename: Path) -> syn::Result { +pub fn process( + _input: ItemUnion, + _cratename: Path, +) -> syn::Result { unimplemented!() } diff --git a/borsh-derive/src/internals/enum_discriminant.rs b/borsh-derive/src/internals/enum_discriminant.rs index 03b3f5829..a3e8fcc94 100644 --- a/borsh-derive/src/internals/enum_discriminant.rs +++ b/borsh-derive/src/internals/enum_discriminant.rs @@ -1,8 +1,7 @@ -use std::collections::HashMap; -use std::convert::TryFrom; +use std::{collections::HashMap, convert::TryFrom}; use proc_macro2::{Ident, TokenStream}; -use quote::quote; +use quote::{quote, ToTokens}; use syn::{punctuated::Punctuated, token::Comma, Variant}; pub struct Discriminants(HashMap); @@ -15,8 +14,8 @@ impl Discriminants { for variant in variants { let this_discriminant = variant.discriminant.clone().map_or_else( - || quote! { #next_discriminant_if_not_specified }, - |(_, e)| quote! { #e }, + || next_discriminant_if_not_specified, + |(_, e)| e.into_token_stream(), ); next_discriminant_if_not_specified = quote! { #this_discriminant + 1 }; @@ -39,8 +38,7 @@ impl Discriminants { ) })?; let result = if use_discriminant { - let discriminant_value = self.0.get(variant_ident).unwrap(); - quote! { #discriminant_value } + self.0.get(variant_ident).unwrap().clone() // discriminant value } else { quote! { #variant_idx } }; diff --git a/borsh-derive/src/internals/generics.rs b/borsh-derive/src/internals/generics.rs index 7914b3b00..3b29bb4f2 100644 --- a/borsh-derive/src/internals/generics.rs +++ b/borsh-derive/src/internals/generics.rs @@ -1,9 +1,10 @@ use std::collections::{HashMap, HashSet}; -use quote::{quote, ToTokens}; +use quote::ToTokens; use syn::{ - punctuated::Pair, Field, GenericArgument, Generics, Ident, Macro, Path, PathArguments, - PathSegment, ReturnType, Type, TypeParamBound, TypePath, WhereClause, WherePredicate, + parse_quote, punctuated::Pair, Field, GenericArgument, Generics, Ident, Macro, Path, + PathArguments, PathSegment, ReturnType, Type, TypeParamBound, TypePath, WhereClause, + WherePredicate, }; pub fn default_where(where_clause: Option<&WhereClause>) -> WhereClause { @@ -20,10 +21,7 @@ pub fn compute_predicates(params: Vec, traitname: &Path) -> Vec, traitname: &Path) -> Vec Generics { - syn::Generics { +pub fn without_defaults(generics: Generics) -> Generics { + Generics { params: generics .params - .iter() + .into_iter() .map(|param| match param { syn::GenericParam::Type(param) => syn::GenericParam::Type(syn::TypeParam { eq_token: None, default: None, - ..param.clone() + ..param }), - _ => param.clone(), + _ => param, }) .collect(), - ..generics.clone() + ..generics } } diff --git a/borsh-derive/src/internals/schema/enums/mod.rs b/borsh-derive/src/internals/schema/enums/mod.rs index 95bbed06b..0d5394986 100644 --- a/borsh-derive/src/internals/schema/enums/mod.rs +++ b/borsh-derive/src/internals/schema/enums/mod.rs @@ -1,6 +1,7 @@ +use std::collections::HashSet; + use proc_macro2::{Span, TokenStream as TokenStream2}; use quote::{quote, ToTokens}; -use std::collections::HashSet; use syn::{Fields, Generics, Ident, ItemEnum, ItemStruct, Path, Variant, Visibility}; use crate::internals::{ @@ -28,14 +29,14 @@ fn transform_variant_fields(mut input: Fields) -> Fields { input } -pub fn process(input: &ItemEnum, cratename: Path) -> syn::Result { +pub fn process(input: ItemEnum, cratename: Path) -> syn::Result { let name = &input.ident; let enum_name = name.to_token_stream().to_string(); - let generics = generics::without_defaults(&input.generics); + let use_discriminant = item::contains_use_discriminant(&input)?; + let generics = generics::without_defaults(input.generics); let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); let mut where_clause = generics::default_where(where_clause); let mut generics_output = schema::GenericsOutput::new(&generics); - let use_discriminant = item::contains_use_discriminant(input)?; let discriminants = Discriminants::new(&input.variants); // Generate functions that return the schema for variants. @@ -137,8 +138,8 @@ fn process_variant( }, variant_entry: quote! { (u8::from(#discriminant_value) as i64, - #variant_name.into(), - #variant_type::declaration()) + #variant_name.into(), + #variant_type::declaration()) }, }) } @@ -181,47 +182,46 @@ fn inner_struct_definition( #[cfg(test)] mod tests { + use syn::parse_quote; + + use super::*; use crate::internals::test_helpers::{ default_cratename, local_insta_assert_debug_snapshot, local_insta_assert_snapshot, pretty_print_syn_str, }; - use super::*; - #[test] fn simple_enum() { - let item_enum: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum A { Bacon, Eggs } - }) - .unwrap(); + }; - let actual = process(&item_enum, default_cratename()).unwrap(); + let actual = process(item_enum, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn simple_enum_with_custom_crate() { - let item_enum: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum A { Bacon, Eggs } - }) - .unwrap(); + }; - let crate_: Path = syn::parse2(quote! { reexporter::borsh }).unwrap(); - let actual = process(&item_enum, crate_).unwrap(); + let crate_: Path = parse_quote! { reexporter::borsh }; + let actual = process(item_enum, crate_).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn borsh_discriminant_false() { - let item_enum: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { #[borsh(use_discriminant = false)] enum X { A, @@ -231,15 +231,14 @@ mod tests { E = 10, F, } - }) - .unwrap(); - let actual = process(&item_enum, default_cratename()).unwrap(); + }; + let actual = process(item_enum, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn borsh_discriminant_true() { - let item_enum: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { #[borsh(use_discriminant = true)] enum X { A, @@ -249,61 +248,57 @@ mod tests { E = 10, F, } - }) - .unwrap(); - let actual = process(&item_enum, default_cratename()).unwrap(); + }; + let actual = process(item_enum, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn single_field_enum() { - let item_enum: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum A { Bacon, } - }) - .unwrap(); + }; - let actual = process(&item_enum, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process(item_enum, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn complex_enum() { - let item_enum: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum A { Bacon, Eggs, Salad(Tomatoes, Cucumber, Oil), Sausage{wrapper: Wrapper, filling: Filling}, } - }) - .unwrap(); + }; - let actual = process(&item_enum, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process(item_enum, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn complex_enum_generics() { - let item_enum: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum A { Bacon, Eggs, Salad(Tomatoes, C, Oil), Sausage{wrapper: W, filling: Filling}, } - }) - .unwrap(); + }; - let actual = process(&item_enum, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process(item_enum, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn trailing_comma_generics() { - let item_struct: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum Side where A: Display + Debug, @@ -312,16 +307,15 @@ mod tests { Left(A), Right(B), } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process(item_enum, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn test_filter_foreign_attrs() { - let item_struct: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum A { #[serde(rename = "ab")] B { @@ -335,33 +329,31 @@ mod tests { beta: String, } } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process(item_enum, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn complex_enum_generics_borsh_skip_tuple_field() { - let item_enum: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum A where W: Hash { Bacon, Eggs, Salad(Tomatoes, #[borsh(skip)] C, Oil), Sausage{wrapper: W, filling: Filling}, } - }) - .unwrap(); + }; - let actual = process(&item_enum, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process(item_enum, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn complex_enum_generics_borsh_skip_named_field() { - let item_enum: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum A { Bacon, Eggs, @@ -373,16 +365,15 @@ mod tests { unexpected: U, }, } - }) - .unwrap(); + }; - let actual = process(&item_enum, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process(item_enum, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn recursive_enum() { - let item_struct: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum A where V: Value { B { x: HashMap, @@ -390,17 +381,16 @@ mod tests { }, C(K, Vec), } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process(item_enum, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn generic_associated_type() { - let item_struct: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum EnumParametrized where K: TraitName, @@ -415,16 +405,15 @@ mod tests { }, C(T, u16), } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process(item_enum, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn generic_associated_type_param_override() { - let item_struct: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum EnumParametrized where K: TraitName, @@ -440,17 +429,16 @@ mod tests { }, C(T, u16), } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process(item_enum, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn generic_associated_type_param_override_conflict() { - let item_struct: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum EnumParametrized where K: TraitName, @@ -462,17 +450,16 @@ mod tests { }, C(T, u16), } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()); + let actual = process(item_enum, default_cratename()); local_insta_assert_debug_snapshot!(actual.unwrap_err()); } #[test] fn check_with_funcs_skip_conflict() { - let item_struct: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum C { C3(u64, u64), C4( @@ -484,17 +471,16 @@ mod tests { ThirdParty, ), } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()); + let actual = process(item_enum, default_cratename()); local_insta_assert_debug_snapshot!(actual.unwrap_err()); } #[test] fn with_funcs_attr() { - let item_struct: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum C { C3(u64, u64), C4( @@ -506,11 +492,10 @@ mod tests { ThirdParty, ), } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process(item_enum, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } } diff --git a/borsh-derive/src/internals/schema/mod.rs b/borsh-derive/src/internals/schema/mod.rs index b094a4452..d1104d9d0 100644 --- a/borsh-derive/src/internals/schema/mod.rs +++ b/borsh-derive/src/internals/schema/mod.rs @@ -3,8 +3,8 @@ use std::collections::HashSet; use proc_macro2::TokenStream as TokenStream2; use quote::quote; use syn::{ - punctuated::Punctuated, token::Comma, Field, Fields, GenericParam, Generics, Ident, Path, Type, - WherePredicate, + parse_quote, punctuated::Punctuated, token::Comma, Field, Fields, GenericParam, Generics, + Ident, Path, Type, WherePredicate, }; use crate::internals::{attributes::field, generics}; @@ -22,8 +22,9 @@ impl GenericsOutput { params_visitor: generics::FindTyParams::new(generics), } } + fn result(self, item_name: &str, cratename: &Path) -> (Vec, TokenStream2) { - let trait_path: Path = syn::parse2(quote! { #cratename::BorshSchema }).unwrap(); + let trait_path: Path = parse_quote! { #cratename::BorshSchema }; let predicates = generics::compute_predicates( self.params_visitor.clone().process_for_bounds(), &trait_path, @@ -48,13 +49,11 @@ fn declaration(ident_str: &str, cratename: Path, params_for_bounds: Vec) - }); } if declaration_params.is_empty() { - quote! { - #ident_str.to_string() - } + quote! { #ident_str.to_string() } } else { quote! { - let params = #cratename::__private::maybestd::vec![#(#declaration_params),*]; - format!(r#"{}<{}>"#, #ident_str, params.join(", ")) + let params = #cratename::__private::maybestd::vec![#(#declaration_params),*]; + format!(r#"{}<{}>"#, #ident_str, params.join(", ")) } } } diff --git a/borsh-derive/src/internals/schema/structs/mod.rs b/borsh-derive/src/internals/schema/structs/mod.rs index 8e388430f..19b09f5b6 100644 --- a/borsh-derive/src/internals/schema/structs/mod.rs +++ b/borsh-derive/src/internals/schema/structs/mod.rs @@ -1,6 +1,6 @@ use proc_macro2::TokenStream as TokenStream2; use quote::{quote, ToTokens}; -use syn::{ExprPath, Fields, Ident, ItemStruct, Path, Type}; +use syn::{parse_quote, ExprPath, Fields, Ident, ItemStruct, Path, Type}; use crate::internals::{attributes::field, generics, schema}; @@ -13,10 +13,9 @@ fn field_declaration_output( cratename: &Path, declaration_override: Option, ) -> TokenStream2 { - let default_path: ExprPath = - syn::parse2(quote! { <#field_type as #cratename::BorshSchema>::declaration }).unwrap(); + let default_path = || parse_quote! { <#field_type as #cratename::BorshSchema>::declaration }; - let path = declaration_override.unwrap_or(default_path); + let path = declaration_override.unwrap_or_else(default_path); if let Some(field_name) = field_name { let field_name = field_name.to_token_stream().to_string(); @@ -37,21 +36,19 @@ fn field_definitions_output( cratename: &Path, definitions_override: Option, ) -> TokenStream2 { - let default_path: ExprPath = syn::parse2( - quote! { <#field_type as #cratename::BorshSchema>::add_definitions_recursively }, - ) - .unwrap(); - let path = definitions_override.unwrap_or(default_path); + let default_path = + || parse_quote! { <#field_type as #cratename::BorshSchema>::add_definitions_recursively }; + let path = definitions_override.unwrap_or_else(default_path); quote! { #path(definitions); } } -pub fn process(input: &ItemStruct, cratename: Path) -> syn::Result { +pub fn process(input: ItemStruct, cratename: Path) -> syn::Result { let name = &input.ident; let struct_name = name.to_token_stream().to_string(); - let generics = generics::without_defaults(&input.generics); + let generics = generics::without_defaults(input.generics); let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); let mut where_clause = generics::default_where(where_clause); let mut generics_output = schema::GenericsOutput::new(&generics); @@ -135,6 +132,7 @@ fn process_fields( } Ok((struct_fields, add_definitions_recursively)) } + fn process_field( field: &syn::Field, cratename: &Path, @@ -162,103 +160,97 @@ fn process_field( #[cfg(test)] mod tests { + use syn::parse_quote; + + use super::*; use crate::internals::test_helpers::{ default_cratename, local_insta_assert_debug_snapshot, local_insta_assert_snapshot, pretty_print_syn_str, }; - use super::*; - #[test] fn unit_struct() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A; - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn wrapper_struct() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A(T); - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn tuple_struct() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A(u64, String); - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn tuple_struct_params() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A(K, V); - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn simple_struct() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A { x: u64, y: String, } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn simple_struct_with_custom_crate() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A { x: u64, y: String, } - }) - .unwrap(); + }; - let crate_: Path = syn::parse2(quote! { reexporter::borsh }).unwrap(); - let actual = process(&item_struct, crate_).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let crate_: Path = parse_quote! { reexporter::borsh }; + let actual = process(item_struct, crate_).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn simple_generics() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A { x: HashMap, y: String, } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn trailing_comma_generics() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A where K: Display + Debug, @@ -266,130 +258,121 @@ mod tests { x: HashMap, y: String, } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn tuple_struct_whole_skip() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A(#[borsh(skip)] String); - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn tuple_struct_partial_skip() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A(#[borsh(skip)] u64, String); - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn generic_tuple_struct_borsh_skip1() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct G ( #[borsh(skip)] HashMap, U, ); - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process(item_struct, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn generic_tuple_struct_borsh_skip2() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct G ( HashMap, #[borsh(skip)] U, ); - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process(item_struct, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn generic_tuple_struct_borsh_skip3() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct G ( #[borsh(skip)] HashMap, U, K, ); - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process(item_struct, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn generic_tuple_struct_borsh_skip4() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct ASalad(Tomatoes, #[borsh(skip)] C, Oil); - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process(item_struct, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn generic_named_fields_struct_borsh_skip() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct G { #[borsh(skip)] x: HashMap, y: U, } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process(item_struct, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn recursive_struct() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct CRecC { a: String, b: HashMap, } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process(item_struct, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn generic_associated_type() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct Parametrized where T: TraitName, @@ -397,17 +380,16 @@ mod tests { field: T::Associated, another: V, } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process(item_struct, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn generic_associated_type_param_override() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct Parametrized where T: TraitName, @@ -418,17 +400,16 @@ mod tests { field: ::Associated, another: V, } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process(item_struct, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn generic_associated_type_param_override2() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct Parametrized where T: TraitName, @@ -439,17 +420,16 @@ mod tests { field: (::Associated, T), another: V, } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process(item_struct, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn generic_associated_type_param_override_conflict() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct Parametrized where T: TraitName, @@ -460,17 +440,16 @@ mod tests { field: ::Associated, another: V, } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()); + let actual = process(item_struct, default_cratename()); local_insta_assert_debug_snapshot!(actual.unwrap_err()); } #[test] fn check_with_funcs_skip_conflict() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A { #[borsh(skip,schema(with_funcs( declaration = "third_party_impl::declaration::", @@ -479,17 +458,16 @@ mod tests { x: ThirdParty, y: u64, } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()); + let actual = process(item_struct, default_cratename()); local_insta_assert_debug_snapshot!(actual.unwrap_err()); } #[test] fn with_funcs_attr() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A { #[borsh(schema(with_funcs( declaration = "third_party_impl::declaration::", @@ -498,17 +476,16 @@ mod tests { x: ThirdParty, y: u64, } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process(item_struct, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn schema_param_override3() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A { #[borsh( schema( @@ -518,11 +495,10 @@ mod tests { x: PrimaryMap, y: String, } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process(item_struct, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } } diff --git a/borsh-derive/src/internals/serialize/enums/mod.rs b/borsh-derive/src/internals/serialize/enums/mod.rs index 4e86ca2d4..0eee414f3 100644 --- a/borsh-derive/src/internals/serialize/enums/mod.rs +++ b/borsh-derive/src/internals/serialize/enums/mod.rs @@ -1,6 +1,6 @@ -use proc_macro2::TokenStream as TokenStream2; +use proc_macro2::{Span, TokenStream as TokenStream2}; use quote::quote; -use syn::{Fields, Ident, ItemEnum, Path, Variant}; +use syn::{Fields, Ident, ItemEnum, Lifetime, Path, Token, Variant}; use crate::internals::{ attributes::{field, item, BoundType}, @@ -8,22 +8,25 @@ use crate::internals::{ generics, serialize, }; -pub fn process(input: &ItemEnum, cratename: Path) -> syn::Result { +pub fn process( + input: ItemEnum, + cratename: Path, +) -> syn::Result { let enum_ident = &input.ident; - let generics = generics::without_defaults(&input.generics); + let use_discriminant = item::contains_use_discriminant(&input)?; + let generics = generics::without_defaults(input.generics); let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); let mut where_clause = generics::default_where(where_clause); let mut generics_output = serialize::GenericsOutput::new(&generics); let mut all_variants_idx_body = TokenStream2::new(); let mut fields_body = TokenStream2::new(); - let use_discriminant = item::contains_use_discriminant(input)?; let discriminants = Discriminants::new(&input.variants); let mut has_unit_variant = false; for (variant_idx, variant) in input.variants.iter().enumerate() { let variant_ident = &variant.ident; let discriminant_value = discriminants.get(variant_ident, use_discriminant, variant_idx)?; - let variant_output = process_variant( + let variant_output = process_variant::( variant, enum_ident, &discriminant_value, @@ -41,18 +44,44 @@ pub fn process(input: &ItemEnum, cratename: Path) -> syn::Result { } } let fields_body = optimize_fields_body(fields_body, has_unit_variant); - generics_output.extend(&mut where_clause, &cratename); + generics_output.extend::(&mut where_clause, &cratename); + + let serialize_trait = Ident::new( + if IS_ASYNC { + "BorshSerializeAsync" + } else { + "BorshSerialize" + }, + Span::call_site(), + ); + let writer_trait = if IS_ASYNC { + quote! { async_io::AsyncWrite } + } else { + quote! { io::Write } + }; + let r#async = IS_ASYNC.then(|| Token![async](Span::call_site())); + let lifetime = IS_ASYNC.then(|| Lifetime::new("'async_variant", Span::call_site())); + let lt_comma = IS_ASYNC.then(|| Token![,](Span::call_site())); + + let write_variant_idx = if IS_ASYNC { + quote! { writer.write_u8(variant_idx).await } + } else { + quote! { writer.write_all(&variant_idx.to_le_bytes()) } + }; Ok(quote! { - impl #impl_generics #cratename::ser::BorshSerialize for #enum_ident #ty_generics #where_clause { - fn serialize<__W: #cratename::io::Write>(&self, writer: &mut __W) -> ::core::result::Result<(), #cratename::io::Error> { + impl #impl_generics #cratename::ser::#serialize_trait for #enum_ident #ty_generics #where_clause { + #r#async fn serialize<#lifetime #lt_comma __W: #cratename::#writer_trait>( + &#lifetime self, + writer: &#lifetime mut __W, + ) -> ::core::result::Result<(), #cratename::io::Error> { let variant_idx: u8 = match self { #all_variants_idx_body }; - writer.write_all(&variant_idx.to_le_bytes())?; + #write_variant_idx?; #fields_body - Ok(()) + ::core::result::Result::Ok(()) } } }) @@ -123,7 +152,7 @@ struct VariantOutput { variant_idx_body: TokenStream2, } -fn process_variant( +fn process_variant( variant: &Variant, enum_ident: &Ident, discriminant_value: &TokenStream2, @@ -136,7 +165,13 @@ fn process_variant( let mut variant_fields = VariantFields::default(); for field in &fields.named { let field_id = serialize::FieldId::Enum(field.ident.clone().unwrap()); - process_field(field, field_id, cratename, generics, &mut variant_fields)?; + process_field::( + field, + field_id, + cratename, + generics, + &mut variant_fields, + )?; } VariantOutput { body: VariantBody::Fields(variant_fields.named_header()), @@ -149,7 +184,13 @@ fn process_variant( let mut variant_fields = VariantFields::default(); for (field_idx, field) in fields.unnamed.iter().enumerate() { let field_id = serialize::FieldId::new_enum_unnamed(field_idx)?; - process_field(field, field_id, cratename, generics, &mut variant_fields)?; + process_field::( + field, + field_id, + cratename, + generics, + &mut variant_fields, + )?; } VariantOutput { body: VariantBody::Fields(variant_fields.unnamed_header()), @@ -168,7 +209,7 @@ fn process_variant( Ok(variant_output) } -fn process_field( +fn process_field( field: &syn::Field, field_id: serialize::FieldId, cratename: &Path, @@ -177,10 +218,16 @@ fn process_field( ) -> syn::Result<()> { let parsed = field::Attributes::parse(&field.attrs)?; - let needs_bounds_derive = parsed.needs_bounds_derive(BoundType::Serialize); - generics - .overrides - .extend(parsed.collect_bounds(BoundType::Serialize)); + let needs_bounds_derive = if IS_ASYNC { + parsed.needs_async_bounds_derive(BoundType::Serialize) + } else { + parsed.needs_bounds_derive(BoundType::Serialize) + }; + generics.overrides.extend(if IS_ASYNC { + parsed.collect_async_bounds(BoundType::Serialize) + } else { + parsed.collect_bounds(BoundType::Serialize) + }); let field_variant_header = field_id.enum_variant_header(parsed.skip); if let Some(field_variant_header) = field_variant_header { @@ -188,7 +235,15 @@ fn process_field( } if !parsed.skip { - let delta = field_id.serialize_output(cratename, parsed.serialize_with); + let delta = field_id.serialize_output::( + &field.ty, + cratename, + if IS_ASYNC { + parsed.serialize_with_async + } else { + parsed.serialize_with + }, + ); output.body.extend(delta); if needs_bounds_derive { generics.serialize_visitor.visit_field(field); @@ -199,14 +254,15 @@ fn process_field( #[cfg(test)] mod tests { + use syn::parse_quote; + + use super::*; use crate::internals::test_helpers::{ default_cratename, local_insta_assert_snapshot, pretty_print_syn_str, }; - - use super::*; #[test] fn borsh_skip_tuple_variant_field() { - let item_enum: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum AATTB { B(#[borsh(skip)] i32, #[borsh(skip)] u32), @@ -214,16 +270,18 @@ mod tests { beta: u8, } } - }) - .unwrap(); - let actual = process(&item_enum, default_cratename()).unwrap(); + }; - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_enum.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); + + let actual = process::(item_enum, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn struct_variant_field() { - let item_enum: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum AB { B { c: i32, @@ -234,17 +292,18 @@ mod tests { beta: String, } } - }) - .unwrap(); + }; - let actual = process(&item_enum, default_cratename()).unwrap(); + let actual = process::(item_enum.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_enum, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn simple_enum_with_custom_crate() { - let item_enum: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum AB { B { c: i32, @@ -255,18 +314,20 @@ mod tests { beta: String, } } - }) - .unwrap(); + }; + + let crate_: Path = parse_quote! { reexporter::borsh }; - let crate_: Path = syn::parse2(quote! { reexporter::borsh }).unwrap(); - let actual = process(&item_enum, crate_).unwrap(); + let actual = process::(item_enum.clone(), crate_.clone()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_enum, crate_).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn borsh_skip_struct_variant_field() { - let item_enum: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum AB { B { @@ -280,17 +341,18 @@ mod tests { beta: String, } } - }) - .unwrap(); + }; - let actual = process(&item_enum, default_cratename()).unwrap(); + let actual = process::(item_enum.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_enum, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn borsh_skip_struct_variant_all_fields() { - let item_enum: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum AAB { B { @@ -305,17 +367,18 @@ mod tests { beta: String, } } - }) - .unwrap(); + }; - let actual = process(&item_enum, default_cratename()).unwrap(); + let actual = process::(item_enum.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_enum, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn simple_generics() { - let item_struct: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum A { B { x: HashMap, @@ -323,16 +386,18 @@ mod tests { }, C(K, Vec), } - }) - .unwrap(); + }; + + let actual = process::(item_enum.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - let actual = process(&item_struct, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_enum, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn bound_generics() { - let item_struct: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum A where V: Value { B { x: HashMap, @@ -340,16 +405,18 @@ mod tests { }, C(K, Vec), } - }) - .unwrap(); + }; + + let actual = process::(item_enum.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - let actual = process(&item_struct, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_enum, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn recursive_enum() { - let item_struct: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum A where V: Value { B { x: HashMap, @@ -357,17 +424,18 @@ mod tests { }, C(K, Vec), } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process::(item_enum.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_enum, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn generic_borsh_skip_struct_field() { - let item_struct: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum A where V: Value { B { #[borsh(skip)] @@ -376,17 +444,18 @@ mod tests { }, C(K, Vec), } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process::(item_enum.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_enum, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn generic_borsh_skip_tuple_field() { - let item_struct: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum A where V: Value { B { x: HashMap, @@ -394,17 +463,18 @@ mod tests { }, C(K, #[borsh(skip)] Vec), } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process::(item_enum.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_enum, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn generic_serialize_bound() { - let item_struct: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum A { C { a: String, @@ -416,17 +486,41 @@ mod tests { }, D(u32, u32), } - }) - .unwrap(); + }; + + let actual = process::(item_enum.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); + + let actual = process::(item_enum, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); + } + + #[test] + fn generic_serialize_async_bound() { + let item_enum: ItemEnum = parse_quote! { + enum A { + C { + a: String, + #[borsh(async_bound(serialize = + "T: borsh::ser::BorshSerializeAsync + PartialOrd, + U: borsh::ser::BorshSerializeAsync" + ))] + b: HashMap, + }, + D(u32, u32), + } + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process::(item_enum.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_enum, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn check_serialize_with_attr() { - let item_struct: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum C { C3(u64, u64), C4 { @@ -435,17 +529,38 @@ mod tests { y: ThirdParty }, } - }) - .unwrap(); + }; + + let actual = process::(item_enum.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); + + let actual = process::(item_enum, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); + } + + #[test] + fn check_serialize_with_async_attr() { + let item_enum: ItemEnum = parse_quote! { + enum C { + C3(u64, u64), + C4 { + x: u64, + #[borsh(serialize_with_async = "third_party_impl::serialize_third_party")] + y: ThirdParty + }, + } + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process::(item_enum.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_enum, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn borsh_discriminant_false() { - let item_enum: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { #[borsh(use_discriminant = false)] enum X { A, @@ -455,15 +570,17 @@ mod tests { E = 10, F, } - }) - .unwrap(); - let actual = process(&item_enum, default_cratename()).unwrap(); + }; + + let actual = process::(item_enum.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).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! { + let item_enum: ItemEnum = parse_quote! { #[borsh(use_discriminant = true)] enum X { A, @@ -473,26 +590,30 @@ mod tests { E = 10, F, } - }) - .unwrap(); - let actual = process(&item_enum, default_cratename()).unwrap(); + }; + + let actual = process::(item_enum.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_enum, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn mixed_with_unit_variants() { - let item_enum: ItemEnum = syn::parse2(quote! { + let item_enum: ItemEnum = parse_quote! { enum X { A(u16), B, C {x: i32, y: i32}, D, } - }) - .unwrap(); - let actual = process(&item_enum, default_cratename()).unwrap(); + }; + + let actual = process::(item_enum.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_enum, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } } diff --git a/borsh-derive/src/internals/serialize/enums/snapshots/borsh_discriminant_false-2.snap b/borsh-derive/src/internals/serialize/enums/snapshots/borsh_discriminant_false-2.snap new file mode 100644 index 000000000..0722ddbcd --- /dev/null +++ b/borsh-derive/src/internals/serialize/enums/snapshots/borsh_discriminant_false-2.snap @@ -0,0 +1,21 @@ +--- +source: borsh-derive/src/internals/serialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::ser::BorshSerializeAsync for X { + async fn serialize<'async_variant, __W: borsh::async_io::AsyncWrite>( + &'async_variant self, + writer: &'async_variant mut __W, + ) -> ::core::result::Result<(), borsh::io::Error> { + let variant_idx: u8 = match self { + X::A => 0u8, + X::B => 1u8, + X::C => 2u8, + X::D => 3u8, + X::E => 4u8, + X::F => 5u8, + }; + writer.write_u8(variant_idx).await?; + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/enums/snapshots/borsh_discriminant_false.snap b/borsh-derive/src/internals/serialize/enums/snapshots/borsh_discriminant_false.snap index 05e1f88e9..f7d142a0a 100644 --- a/borsh-derive/src/internals/serialize/enums/snapshots/borsh_discriminant_false.snap +++ b/borsh-derive/src/internals/serialize/enums/snapshots/borsh_discriminant_false.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/serialize/enums/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::ser::BorshSerialize for X { fn serialize<__W: borsh::io::Write>( @@ -16,6 +16,6 @@ impl borsh::ser::BorshSerialize for X { X::F => 5u8, }; writer.write_all(&variant_idx.to_le_bytes())?; - Ok(()) + ::core::result::Result::Ok(()) } } diff --git a/borsh-derive/src/internals/serialize/enums/snapshots/borsh_discriminant_true-2.snap b/borsh-derive/src/internals/serialize/enums/snapshots/borsh_discriminant_true-2.snap new file mode 100644 index 000000000..f2067c71f --- /dev/null +++ b/borsh-derive/src/internals/serialize/enums/snapshots/borsh_discriminant_true-2.snap @@ -0,0 +1,21 @@ +--- +source: borsh-derive/src/internals/serialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::ser::BorshSerializeAsync for X { + async fn serialize<'async_variant, __W: borsh::async_io::AsyncWrite>( + &'async_variant self, + writer: &'async_variant mut __W, + ) -> ::core::result::Result<(), borsh::io::Error> { + let variant_idx: u8 = match self { + X::A => 0, + X::B => 20, + X::C => 20 + 1, + X::D => 20 + 1 + 1, + X::E => 10, + X::F => 10 + 1, + }; + writer.write_u8(variant_idx).await?; + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/enums/snapshots/borsh_discriminant_true.snap b/borsh-derive/src/internals/serialize/enums/snapshots/borsh_discriminant_true.snap index ee3371232..51e3dedaa 100644 --- a/borsh-derive/src/internals/serialize/enums/snapshots/borsh_discriminant_true.snap +++ b/borsh-derive/src/internals/serialize/enums/snapshots/borsh_discriminant_true.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/serialize/enums/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::ser::BorshSerialize for X { fn serialize<__W: borsh::io::Write>( @@ -16,6 +16,6 @@ impl borsh::ser::BorshSerialize for X { X::F => 10 + 1, }; writer.write_all(&variant_idx.to_le_bytes())?; - Ok(()) + ::core::result::Result::Ok(()) } } diff --git a/borsh-derive/src/internals/serialize/enums/snapshots/borsh_skip_struct_variant_all_fields-2.snap b/borsh-derive/src/internals/serialize/enums/snapshots/borsh_skip_struct_variant_all_fields-2.snap new file mode 100644 index 000000000..9160687b9 --- /dev/null +++ b/borsh-derive/src/internals/serialize/enums/snapshots/borsh_skip_struct_variant_all_fields-2.snap @@ -0,0 +1,23 @@ +--- +source: borsh-derive/src/internals/serialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::ser::BorshSerializeAsync for AAB { + async fn serialize<'async_variant, __W: borsh::async_io::AsyncWrite>( + &'async_variant self, + writer: &'async_variant mut __W, + ) -> ::core::result::Result<(), borsh::io::Error> { + let variant_idx: u8 = match self { + AAB::B { .. } => 0u8, + AAB::NegatedVariant { .. } => 1u8, + }; + writer.write_u8(variant_idx).await?; + match self { + AAB::B { .. } => {} + AAB::NegatedVariant { beta, .. } => { + ::serialize(beta, writer).await?; + } + } + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/enums/snapshots/borsh_skip_struct_variant_all_fields.snap b/borsh-derive/src/internals/serialize/enums/snapshots/borsh_skip_struct_variant_all_fields.snap index b8943a467..359f454b5 100644 --- a/borsh-derive/src/internals/serialize/enums/snapshots/borsh_skip_struct_variant_all_fields.snap +++ b/borsh-derive/src/internals/serialize/enums/snapshots/borsh_skip_struct_variant_all_fields.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/serialize/enums/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::ser::BorshSerialize for AAB { fn serialize<__W: borsh::io::Write>( @@ -15,9 +15,9 @@ impl borsh::ser::BorshSerialize for AAB { match self { AAB::B { .. } => {} AAB::NegatedVariant { beta, .. } => { - borsh::BorshSerialize::serialize(beta, writer)?; + ::serialize(beta, writer)?; } } - Ok(()) + ::core::result::Result::Ok(()) } } diff --git a/borsh-derive/src/internals/serialize/enums/snapshots/borsh_skip_struct_variant_field-2.snap b/borsh-derive/src/internals/serialize/enums/snapshots/borsh_skip_struct_variant_field-2.snap new file mode 100644 index 000000000..1a0b50e04 --- /dev/null +++ b/borsh-derive/src/internals/serialize/enums/snapshots/borsh_skip_struct_variant_field-2.snap @@ -0,0 +1,25 @@ +--- +source: borsh-derive/src/internals/serialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::ser::BorshSerializeAsync for AB { + async fn serialize<'async_variant, __W: borsh::async_io::AsyncWrite>( + &'async_variant self, + writer: &'async_variant mut __W, + ) -> ::core::result::Result<(), borsh::io::Error> { + let variant_idx: u8 = match self { + AB::B { .. } => 0u8, + AB::NegatedVariant { .. } => 1u8, + }; + writer.write_u8(variant_idx).await?; + match self { + AB::B { d, .. } => { + ::serialize(d, writer).await?; + } + AB::NegatedVariant { beta, .. } => { + ::serialize(beta, writer).await?; + } + } + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/enums/snapshots/borsh_skip_struct_variant_field.snap b/borsh-derive/src/internals/serialize/enums/snapshots/borsh_skip_struct_variant_field.snap index f5ff6946d..a8b419de0 100644 --- a/borsh-derive/src/internals/serialize/enums/snapshots/borsh_skip_struct_variant_field.snap +++ b/borsh-derive/src/internals/serialize/enums/snapshots/borsh_skip_struct_variant_field.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/serialize/enums/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::ser::BorshSerialize for AB { fn serialize<__W: borsh::io::Write>( @@ -14,12 +14,12 @@ impl borsh::ser::BorshSerialize for AB { writer.write_all(&variant_idx.to_le_bytes())?; match self { AB::B { d, .. } => { - borsh::BorshSerialize::serialize(d, writer)?; + ::serialize(d, writer)?; } AB::NegatedVariant { beta, .. } => { - borsh::BorshSerialize::serialize(beta, writer)?; + ::serialize(beta, writer)?; } } - Ok(()) + ::core::result::Result::Ok(()) } } diff --git a/borsh-derive/src/internals/serialize/enums/snapshots/borsh_skip_tuple_variant_field-2.snap b/borsh-derive/src/internals/serialize/enums/snapshots/borsh_skip_tuple_variant_field-2.snap new file mode 100644 index 000000000..cef5665fe --- /dev/null +++ b/borsh-derive/src/internals/serialize/enums/snapshots/borsh_skip_tuple_variant_field-2.snap @@ -0,0 +1,23 @@ +--- +source: borsh-derive/src/internals/serialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::ser::BorshSerializeAsync for AATTB { + async fn serialize<'async_variant, __W: borsh::async_io::AsyncWrite>( + &'async_variant self, + writer: &'async_variant mut __W, + ) -> ::core::result::Result<(), borsh::io::Error> { + let variant_idx: u8 = match self { + AATTB::B(..) => 0u8, + AATTB::NegatedVariant { .. } => 1u8, + }; + writer.write_u8(variant_idx).await?; + match self { + AATTB::B(_id0, _id1) => {} + AATTB::NegatedVariant { beta, .. } => { + ::serialize(beta, writer).await?; + } + } + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/enums/snapshots/borsh_skip_tuple_variant_field.snap b/borsh-derive/src/internals/serialize/enums/snapshots/borsh_skip_tuple_variant_field.snap index fc3be0087..82b5f7b48 100644 --- a/borsh-derive/src/internals/serialize/enums/snapshots/borsh_skip_tuple_variant_field.snap +++ b/borsh-derive/src/internals/serialize/enums/snapshots/borsh_skip_tuple_variant_field.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/serialize/enums/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::ser::BorshSerialize for AATTB { fn serialize<__W: borsh::io::Write>( @@ -15,9 +15,9 @@ impl borsh::ser::BorshSerialize for AATTB { match self { AATTB::B(_id0, _id1) => {} AATTB::NegatedVariant { beta, .. } => { - borsh::BorshSerialize::serialize(beta, writer)?; + ::serialize(beta, writer)?; } } - Ok(()) + ::core::result::Result::Ok(()) } } diff --git a/borsh-derive/src/internals/serialize/enums/snapshots/bound_generics-2.snap b/borsh-derive/src/internals/serialize/enums/snapshots/bound_generics-2.snap new file mode 100644 index 000000000..86c05d8ca --- /dev/null +++ b/borsh-derive/src/internals/serialize/enums/snapshots/bound_generics-2.snap @@ -0,0 +1,34 @@ +--- +source: borsh-derive/src/internals/serialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::ser::BorshSerializeAsync for A +where + V: Value, + K: borsh::ser::BorshSerializeAsync, + V: borsh::ser::BorshSerializeAsync, + U: borsh::ser::BorshSerializeAsync, +{ + async fn serialize<'async_variant, __W: borsh::async_io::AsyncWrite>( + &'async_variant self, + writer: &'async_variant mut __W, + ) -> ::core::result::Result<(), borsh::io::Error> { + let variant_idx: u8 = match self { + A::B { .. } => 0u8, + A::C(..) => 1u8, + }; + writer.write_u8(variant_idx).await?; + match self { + A::B { x, y, .. } => { + as borsh::BorshSerializeAsync>::serialize(x, writer) + .await?; + ::serialize(y, writer).await?; + } + A::C(id0, id1) => { + ::serialize(id0, writer).await?; + as borsh::BorshSerializeAsync>::serialize(id1, writer).await?; + } + } + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/enums/snapshots/bound_generics.snap b/borsh-derive/src/internals/serialize/enums/snapshots/bound_generics.snap index 9c1630967..10e186ddc 100644 --- a/borsh-derive/src/internals/serialize/enums/snapshots/bound_generics.snap +++ b/borsh-derive/src/internals/serialize/enums/snapshots/bound_generics.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/serialize/enums/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::ser::BorshSerialize for A where @@ -20,14 +20,14 @@ where writer.write_all(&variant_idx.to_le_bytes())?; match self { A::B { x, y, .. } => { - borsh::BorshSerialize::serialize(x, writer)?; - borsh::BorshSerialize::serialize(y, writer)?; + as borsh::BorshSerialize>::serialize(x, writer)?; + ::serialize(y, writer)?; } A::C(id0, id1) => { - borsh::BorshSerialize::serialize(id0, writer)?; - borsh::BorshSerialize::serialize(id1, writer)?; + ::serialize(id0, writer)?; + as borsh::BorshSerialize>::serialize(id1, writer)?; } } - Ok(()) + ::core::result::Result::Ok(()) } } diff --git a/borsh-derive/src/internals/serialize/enums/snapshots/check_serialize_with_async_attr-2.snap b/borsh-derive/src/internals/serialize/enums/snapshots/check_serialize_with_async_attr-2.snap new file mode 100644 index 000000000..e7cb8b20d --- /dev/null +++ b/borsh-derive/src/internals/serialize/enums/snapshots/check_serialize_with_async_attr-2.snap @@ -0,0 +1,31 @@ +--- +source: borsh-derive/src/internals/serialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::ser::BorshSerializeAsync for C +where + K: borsh::ser::BorshSerializeAsync, + V: borsh::ser::BorshSerializeAsync, +{ + async fn serialize<'async_variant, __W: borsh::async_io::AsyncWrite>( + &'async_variant self, + writer: &'async_variant mut __W, + ) -> ::core::result::Result<(), borsh::io::Error> { + let variant_idx: u8 = match self { + C::C3(..) => 0u8, + C::C4 { .. } => 1u8, + }; + writer.write_u8(variant_idx).await?; + match self { + C::C3(id0, id1) => { + ::serialize(id0, writer).await?; + ::serialize(id1, writer).await?; + } + C::C4 { x, y, .. } => { + ::serialize(x, writer).await?; + third_party_impl::serialize_third_party(y, writer).await?; + } + } + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/enums/snapshots/check_serialize_with_async_attr.snap b/borsh-derive/src/internals/serialize/enums/snapshots/check_serialize_with_async_attr.snap new file mode 100644 index 000000000..9206b7b6d --- /dev/null +++ b/borsh-derive/src/internals/serialize/enums/snapshots/check_serialize_with_async_attr.snap @@ -0,0 +1,31 @@ +--- +source: borsh-derive/src/internals/serialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::ser::BorshSerialize for C +where + K: borsh::ser::BorshSerialize, + V: borsh::ser::BorshSerialize, +{ + fn serialize<__W: borsh::io::Write>( + &self, + writer: &mut __W, + ) -> ::core::result::Result<(), borsh::io::Error> { + let variant_idx: u8 = match self { + C::C3(..) => 0u8, + C::C4 { .. } => 1u8, + }; + writer.write_all(&variant_idx.to_le_bytes())?; + match self { + C::C3(id0, id1) => { + ::serialize(id0, writer)?; + ::serialize(id1, writer)?; + } + C::C4 { x, y, .. } => { + ::serialize(x, writer)?; + as borsh::BorshSerialize>::serialize(y, writer)?; + } + } + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/enums/snapshots/check_serialize_with_attr-2.snap b/borsh-derive/src/internals/serialize/enums/snapshots/check_serialize_with_attr-2.snap new file mode 100644 index 000000000..9bd53ef66 --- /dev/null +++ b/borsh-derive/src/internals/serialize/enums/snapshots/check_serialize_with_attr-2.snap @@ -0,0 +1,32 @@ +--- +source: borsh-derive/src/internals/serialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::ser::BorshSerializeAsync for C +where + K: borsh::ser::BorshSerializeAsync, + V: borsh::ser::BorshSerializeAsync, +{ + async fn serialize<'async_variant, __W: borsh::async_io::AsyncWrite>( + &'async_variant self, + writer: &'async_variant mut __W, + ) -> ::core::result::Result<(), borsh::io::Error> { + let variant_idx: u8 = match self { + C::C3(..) => 0u8, + C::C4 { .. } => 1u8, + }; + writer.write_u8(variant_idx).await?; + match self { + C::C3(id0, id1) => { + ::serialize(id0, writer).await?; + ::serialize(id1, writer).await?; + } + C::C4 { x, y, .. } => { + ::serialize(x, writer).await?; + as borsh::BorshSerializeAsync>::serialize(y, writer) + .await?; + } + } + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/enums/snapshots/check_serialize_with_attr.snap b/borsh-derive/src/internals/serialize/enums/snapshots/check_serialize_with_attr.snap index 29f1619c1..84fc5e517 100644 --- a/borsh-derive/src/internals/serialize/enums/snapshots/check_serialize_with_attr.snap +++ b/borsh-derive/src/internals/serialize/enums/snapshots/check_serialize_with_attr.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/serialize/enums/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::ser::BorshSerialize for C where @@ -18,14 +18,14 @@ where writer.write_all(&variant_idx.to_le_bytes())?; match self { C::C3(id0, id1) => { - borsh::BorshSerialize::serialize(id0, writer)?; - borsh::BorshSerialize::serialize(id1, writer)?; + ::serialize(id0, writer)?; + ::serialize(id1, writer)?; } C::C4 { x, y, .. } => { - borsh::BorshSerialize::serialize(x, writer)?; + ::serialize(x, writer)?; third_party_impl::serialize_third_party(y, writer)?; } } - Ok(()) + ::core::result::Result::Ok(()) } } diff --git a/borsh-derive/src/internals/serialize/enums/snapshots/generic_borsh_skip_struct_field-2.snap b/borsh-derive/src/internals/serialize/enums/snapshots/generic_borsh_skip_struct_field-2.snap new file mode 100644 index 000000000..8d186deb4 --- /dev/null +++ b/borsh-derive/src/internals/serialize/enums/snapshots/generic_borsh_skip_struct_field-2.snap @@ -0,0 +1,31 @@ +--- +source: borsh-derive/src/internals/serialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::ser::BorshSerializeAsync for A +where + V: Value, + K: borsh::ser::BorshSerializeAsync, + U: borsh::ser::BorshSerializeAsync, +{ + async fn serialize<'async_variant, __W: borsh::async_io::AsyncWrite>( + &'async_variant self, + writer: &'async_variant mut __W, + ) -> ::core::result::Result<(), borsh::io::Error> { + let variant_idx: u8 = match self { + A::B { .. } => 0u8, + A::C(..) => 1u8, + }; + writer.write_u8(variant_idx).await?; + match self { + A::B { y, .. } => { + ::serialize(y, writer).await?; + } + A::C(id0, id1) => { + ::serialize(id0, writer).await?; + as borsh::BorshSerializeAsync>::serialize(id1, writer).await?; + } + } + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/enums/snapshots/generic_borsh_skip_struct_field.snap b/borsh-derive/src/internals/serialize/enums/snapshots/generic_borsh_skip_struct_field.snap index 051033a64..0fc2c601a 100644 --- a/borsh-derive/src/internals/serialize/enums/snapshots/generic_borsh_skip_struct_field.snap +++ b/borsh-derive/src/internals/serialize/enums/snapshots/generic_borsh_skip_struct_field.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/serialize/enums/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::ser::BorshSerialize for A where @@ -19,13 +19,13 @@ where writer.write_all(&variant_idx.to_le_bytes())?; match self { A::B { y, .. } => { - borsh::BorshSerialize::serialize(y, writer)?; + ::serialize(y, writer)?; } A::C(id0, id1) => { - borsh::BorshSerialize::serialize(id0, writer)?; - borsh::BorshSerialize::serialize(id1, writer)?; + ::serialize(id0, writer)?; + as borsh::BorshSerialize>::serialize(id1, writer)?; } } - Ok(()) + ::core::result::Result::Ok(()) } } diff --git a/borsh-derive/src/internals/serialize/enums/snapshots/generic_borsh_skip_tuple_field-2.snap b/borsh-derive/src/internals/serialize/enums/snapshots/generic_borsh_skip_tuple_field-2.snap new file mode 100644 index 000000000..b260874c3 --- /dev/null +++ b/borsh-derive/src/internals/serialize/enums/snapshots/generic_borsh_skip_tuple_field-2.snap @@ -0,0 +1,32 @@ +--- +source: borsh-derive/src/internals/serialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::ser::BorshSerializeAsync for A +where + V: Value, + K: borsh::ser::BorshSerializeAsync, + V: borsh::ser::BorshSerializeAsync, +{ + async fn serialize<'async_variant, __W: borsh::async_io::AsyncWrite>( + &'async_variant self, + writer: &'async_variant mut __W, + ) -> ::core::result::Result<(), borsh::io::Error> { + let variant_idx: u8 = match self { + A::B { .. } => 0u8, + A::C(..) => 1u8, + }; + writer.write_u8(variant_idx).await?; + match self { + A::B { x, y, .. } => { + as borsh::BorshSerializeAsync>::serialize(x, writer) + .await?; + ::serialize(y, writer).await?; + } + A::C(id0, _id1) => { + ::serialize(id0, writer).await?; + } + } + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/enums/snapshots/generic_borsh_skip_tuple_field.snap b/borsh-derive/src/internals/serialize/enums/snapshots/generic_borsh_skip_tuple_field.snap index 4f0ae41b7..ca61b5fb9 100644 --- a/borsh-derive/src/internals/serialize/enums/snapshots/generic_borsh_skip_tuple_field.snap +++ b/borsh-derive/src/internals/serialize/enums/snapshots/generic_borsh_skip_tuple_field.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/serialize/enums/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::ser::BorshSerialize for A where @@ -19,13 +19,13 @@ where writer.write_all(&variant_idx.to_le_bytes())?; match self { A::B { x, y, .. } => { - borsh::BorshSerialize::serialize(x, writer)?; - borsh::BorshSerialize::serialize(y, writer)?; + as borsh::BorshSerialize>::serialize(x, writer)?; + ::serialize(y, writer)?; } A::C(id0, _id1) => { - borsh::BorshSerialize::serialize(id0, writer)?; + ::serialize(id0, writer)?; } } - Ok(()) + ::core::result::Result::Ok(()) } } diff --git a/borsh-derive/src/internals/serialize/enums/snapshots/generic_serialize_async_bound-2.snap b/borsh-derive/src/internals/serialize/enums/snapshots/generic_serialize_async_bound-2.snap new file mode 100644 index 000000000..9d4f4b821 --- /dev/null +++ b/borsh-derive/src/internals/serialize/enums/snapshots/generic_serialize_async_bound-2.snap @@ -0,0 +1,32 @@ +--- +source: borsh-derive/src/internals/serialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::ser::BorshSerializeAsync for A +where + T: borsh::ser::BorshSerializeAsync + PartialOrd, + U: borsh::ser::BorshSerializeAsync, +{ + async fn serialize<'async_variant, __W: borsh::async_io::AsyncWrite>( + &'async_variant self, + writer: &'async_variant mut __W, + ) -> ::core::result::Result<(), borsh::io::Error> { + let variant_idx: u8 = match self { + A::C { .. } => 0u8, + A::D(..) => 1u8, + }; + writer.write_u8(variant_idx).await?; + match self { + A::C { a, b, .. } => { + ::serialize(a, writer).await?; + as borsh::BorshSerializeAsync>::serialize(b, writer) + .await?; + } + A::D(id0, id1) => { + ::serialize(id0, writer).await?; + ::serialize(id1, writer).await?; + } + } + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/enums/snapshots/generic_serialize_async_bound.snap b/borsh-derive/src/internals/serialize/enums/snapshots/generic_serialize_async_bound.snap new file mode 100644 index 000000000..23806f9c5 --- /dev/null +++ b/borsh-derive/src/internals/serialize/enums/snapshots/generic_serialize_async_bound.snap @@ -0,0 +1,31 @@ +--- +source: borsh-derive/src/internals/serialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::ser::BorshSerialize for A +where + T: borsh::ser::BorshSerialize, + U: borsh::ser::BorshSerialize, +{ + fn serialize<__W: borsh::io::Write>( + &self, + writer: &mut __W, + ) -> ::core::result::Result<(), borsh::io::Error> { + let variant_idx: u8 = match self { + A::C { .. } => 0u8, + A::D(..) => 1u8, + }; + writer.write_all(&variant_idx.to_le_bytes())?; + match self { + A::C { a, b, .. } => { + ::serialize(a, writer)?; + as borsh::BorshSerialize>::serialize(b, writer)?; + } + A::D(id0, id1) => { + ::serialize(id0, writer)?; + ::serialize(id1, writer)?; + } + } + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/enums/snapshots/generic_serialize_bound-2.snap b/borsh-derive/src/internals/serialize/enums/snapshots/generic_serialize_bound-2.snap new file mode 100644 index 000000000..e3374b186 --- /dev/null +++ b/borsh-derive/src/internals/serialize/enums/snapshots/generic_serialize_bound-2.snap @@ -0,0 +1,32 @@ +--- +source: borsh-derive/src/internals/serialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::ser::BorshSerializeAsync for A +where + T: borsh::ser::BorshSerializeAsync, + U: borsh::ser::BorshSerializeAsync, +{ + async fn serialize<'async_variant, __W: borsh::async_io::AsyncWrite>( + &'async_variant self, + writer: &'async_variant mut __W, + ) -> ::core::result::Result<(), borsh::io::Error> { + let variant_idx: u8 = match self { + A::C { .. } => 0u8, + A::D(..) => 1u8, + }; + writer.write_u8(variant_idx).await?; + match self { + A::C { a, b, .. } => { + ::serialize(a, writer).await?; + as borsh::BorshSerializeAsync>::serialize(b, writer) + .await?; + } + A::D(id0, id1) => { + ::serialize(id0, writer).await?; + ::serialize(id1, writer).await?; + } + } + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/enums/snapshots/generic_serialize_bound.snap b/borsh-derive/src/internals/serialize/enums/snapshots/generic_serialize_bound.snap index 1e53690ec..91fd4f8fe 100644 --- a/borsh-derive/src/internals/serialize/enums/snapshots/generic_serialize_bound.snap +++ b/borsh-derive/src/internals/serialize/enums/snapshots/generic_serialize_bound.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/serialize/enums/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::ser::BorshSerialize for A where @@ -18,14 +18,14 @@ where writer.write_all(&variant_idx.to_le_bytes())?; match self { A::C { a, b, .. } => { - borsh::BorshSerialize::serialize(a, writer)?; - borsh::BorshSerialize::serialize(b, writer)?; + ::serialize(a, writer)?; + as borsh::BorshSerialize>::serialize(b, writer)?; } A::D(id0, id1) => { - borsh::BorshSerialize::serialize(id0, writer)?; - borsh::BorshSerialize::serialize(id1, writer)?; + ::serialize(id0, writer)?; + ::serialize(id1, writer)?; } } - Ok(()) + ::core::result::Result::Ok(()) } } diff --git a/borsh-derive/src/internals/serialize/enums/snapshots/mixed_with_unit_variants-2.snap b/borsh-derive/src/internals/serialize/enums/snapshots/mixed_with_unit_variants-2.snap new file mode 100644 index 000000000..c1155e80c --- /dev/null +++ b/borsh-derive/src/internals/serialize/enums/snapshots/mixed_with_unit_variants-2.snap @@ -0,0 +1,29 @@ +--- +source: borsh-derive/src/internals/serialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::ser::BorshSerializeAsync for X { + async fn serialize<'async_variant, __W: borsh::async_io::AsyncWrite>( + &'async_variant self, + writer: &'async_variant mut __W, + ) -> ::core::result::Result<(), borsh::io::Error> { + let variant_idx: u8 = match self { + X::A(..) => 0u8, + X::B => 1u8, + X::C { .. } => 2u8, + X::D => 3u8, + }; + writer.write_u8(variant_idx).await?; + match self { + X::A(id0) => { + ::serialize(id0, writer).await?; + } + X::C { x, y, .. } => { + ::serialize(x, writer).await?; + ::serialize(y, writer).await?; + } + _ => {} + } + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/enums/snapshots/mixed_with_unit_variants.snap b/borsh-derive/src/internals/serialize/enums/snapshots/mixed_with_unit_variants.snap index 69a56d5b9..687e4d815 100644 --- a/borsh-derive/src/internals/serialize/enums/snapshots/mixed_with_unit_variants.snap +++ b/borsh-derive/src/internals/serialize/enums/snapshots/mixed_with_unit_variants.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/serialize/enums/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::ser::BorshSerialize for X { fn serialize<__W: borsh::io::Write>( @@ -16,14 +16,14 @@ impl borsh::ser::BorshSerialize for X { writer.write_all(&variant_idx.to_le_bytes())?; match self { X::A(id0) => { - borsh::BorshSerialize::serialize(id0, writer)?; + ::serialize(id0, writer)?; } X::C { x, y, .. } => { - borsh::BorshSerialize::serialize(x, writer)?; - borsh::BorshSerialize::serialize(y, writer)?; + ::serialize(x, writer)?; + ::serialize(y, writer)?; } _ => {} } - Ok(()) + ::core::result::Result::Ok(()) } } diff --git a/borsh-derive/src/internals/serialize/enums/snapshots/recursive_enum-2.snap b/borsh-derive/src/internals/serialize/enums/snapshots/recursive_enum-2.snap new file mode 100644 index 000000000..124234ea6 --- /dev/null +++ b/borsh-derive/src/internals/serialize/enums/snapshots/recursive_enum-2.snap @@ -0,0 +1,33 @@ +--- +source: borsh-derive/src/internals/serialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::ser::BorshSerializeAsync for A +where + V: Value, + K: borsh::ser::BorshSerializeAsync, + V: borsh::ser::BorshSerializeAsync, +{ + async fn serialize<'async_variant, __W: borsh::async_io::AsyncWrite>( + &'async_variant self, + writer: &'async_variant mut __W, + ) -> ::core::result::Result<(), borsh::io::Error> { + let variant_idx: u8 = match self { + A::B { .. } => 0u8, + A::C(..) => 1u8, + }; + writer.write_u8(variant_idx).await?; + match self { + A::B { x, y, .. } => { + as borsh::BorshSerializeAsync>::serialize(x, writer) + .await?; + ::serialize(y, writer).await?; + } + A::C(id0, id1) => { + ::serialize(id0, writer).await?; + as borsh::BorshSerializeAsync>::serialize(id1, writer).await?; + } + } + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/enums/snapshots/recursive_enum.snap b/borsh-derive/src/internals/serialize/enums/snapshots/recursive_enum.snap index d7aeab233..6724928e5 100644 --- a/borsh-derive/src/internals/serialize/enums/snapshots/recursive_enum.snap +++ b/borsh-derive/src/internals/serialize/enums/snapshots/recursive_enum.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/serialize/enums/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::ser::BorshSerialize for A where @@ -19,14 +19,14 @@ where writer.write_all(&variant_idx.to_le_bytes())?; match self { A::B { x, y, .. } => { - borsh::BorshSerialize::serialize(x, writer)?; - borsh::BorshSerialize::serialize(y, writer)?; + as borsh::BorshSerialize>::serialize(x, writer)?; + ::serialize(y, writer)?; } A::C(id0, id1) => { - borsh::BorshSerialize::serialize(id0, writer)?; - borsh::BorshSerialize::serialize(id1, writer)?; + ::serialize(id0, writer)?; + as borsh::BorshSerialize>::serialize(id1, writer)?; } } - Ok(()) + ::core::result::Result::Ok(()) } } diff --git a/borsh-derive/src/internals/serialize/enums/snapshots/simple_enum_with_custom_crate-2.snap b/borsh-derive/src/internals/serialize/enums/snapshots/simple_enum_with_custom_crate-2.snap new file mode 100644 index 000000000..4789105cf --- /dev/null +++ b/borsh-derive/src/internals/serialize/enums/snapshots/simple_enum_with_custom_crate-2.snap @@ -0,0 +1,32 @@ +--- +source: borsh-derive/src/internals/serialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl reexporter::borsh::ser::BorshSerializeAsync for AB { + async fn serialize<'async_variant, __W: reexporter::borsh::async_io::AsyncWrite>( + &'async_variant self, + writer: &'async_variant mut __W, + ) -> ::core::result::Result<(), reexporter::borsh::io::Error> { + let variant_idx: u8 = match self { + AB::B { .. } => 0u8, + AB::NegatedVariant { .. } => 1u8, + }; + writer.write_u8(variant_idx).await?; + match self { + AB::B { c, d, .. } => { + ::serialize(c, writer) + .await?; + ::serialize(d, writer) + .await?; + } + AB::NegatedVariant { beta, .. } => { + ::serialize( + beta, + writer, + ) + .await?; + } + } + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/enums/snapshots/simple_enum_with_custom_crate.snap b/borsh-derive/src/internals/serialize/enums/snapshots/simple_enum_with_custom_crate.snap index fcfc55df6..d16e4ea5e 100644 --- a/borsh-derive/src/internals/serialize/enums/snapshots/simple_enum_with_custom_crate.snap +++ b/borsh-derive/src/internals/serialize/enums/snapshots/simple_enum_with_custom_crate.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/serialize/enums/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl reexporter::borsh::ser::BorshSerialize for AB { fn serialize<__W: reexporter::borsh::io::Write>( @@ -14,13 +14,13 @@ impl reexporter::borsh::ser::BorshSerialize for AB { writer.write_all(&variant_idx.to_le_bytes())?; match self { AB::B { c, d, .. } => { - reexporter::borsh::BorshSerialize::serialize(c, writer)?; - reexporter::borsh::BorshSerialize::serialize(d, writer)?; + ::serialize(c, writer)?; + ::serialize(d, writer)?; } AB::NegatedVariant { beta, .. } => { - reexporter::borsh::BorshSerialize::serialize(beta, writer)?; + ::serialize(beta, writer)?; } } - Ok(()) + ::core::result::Result::Ok(()) } } diff --git a/borsh-derive/src/internals/serialize/enums/snapshots/simple_generics-2.snap b/borsh-derive/src/internals/serialize/enums/snapshots/simple_generics-2.snap new file mode 100644 index 000000000..3f495c06c --- /dev/null +++ b/borsh-derive/src/internals/serialize/enums/snapshots/simple_generics-2.snap @@ -0,0 +1,33 @@ +--- +source: borsh-derive/src/internals/serialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::ser::BorshSerializeAsync for A +where + K: borsh::ser::BorshSerializeAsync, + V: borsh::ser::BorshSerializeAsync, + U: borsh::ser::BorshSerializeAsync, +{ + async fn serialize<'async_variant, __W: borsh::async_io::AsyncWrite>( + &'async_variant self, + writer: &'async_variant mut __W, + ) -> ::core::result::Result<(), borsh::io::Error> { + let variant_idx: u8 = match self { + A::B { .. } => 0u8, + A::C(..) => 1u8, + }; + writer.write_u8(variant_idx).await?; + match self { + A::B { x, y, .. } => { + as borsh::BorshSerializeAsync>::serialize(x, writer) + .await?; + ::serialize(y, writer).await?; + } + A::C(id0, id1) => { + ::serialize(id0, writer).await?; + as borsh::BorshSerializeAsync>::serialize(id1, writer).await?; + } + } + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/enums/snapshots/simple_generics.snap b/borsh-derive/src/internals/serialize/enums/snapshots/simple_generics.snap index 70e2f6498..8d056af5e 100644 --- a/borsh-derive/src/internals/serialize/enums/snapshots/simple_generics.snap +++ b/borsh-derive/src/internals/serialize/enums/snapshots/simple_generics.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/serialize/enums/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::ser::BorshSerialize for A where @@ -19,14 +19,14 @@ where writer.write_all(&variant_idx.to_le_bytes())?; match self { A::B { x, y, .. } => { - borsh::BorshSerialize::serialize(x, writer)?; - borsh::BorshSerialize::serialize(y, writer)?; + as borsh::BorshSerialize>::serialize(x, writer)?; + ::serialize(y, writer)?; } A::C(id0, id1) => { - borsh::BorshSerialize::serialize(id0, writer)?; - borsh::BorshSerialize::serialize(id1, writer)?; + ::serialize(id0, writer)?; + as borsh::BorshSerialize>::serialize(id1, writer)?; } } - Ok(()) + ::core::result::Result::Ok(()) } } diff --git a/borsh-derive/src/internals/serialize/enums/snapshots/struct_variant_field-2.snap b/borsh-derive/src/internals/serialize/enums/snapshots/struct_variant_field-2.snap new file mode 100644 index 000000000..4c8428aaf --- /dev/null +++ b/borsh-derive/src/internals/serialize/enums/snapshots/struct_variant_field-2.snap @@ -0,0 +1,26 @@ +--- +source: borsh-derive/src/internals/serialize/enums/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::ser::BorshSerializeAsync for AB { + async fn serialize<'async_variant, __W: borsh::async_io::AsyncWrite>( + &'async_variant self, + writer: &'async_variant mut __W, + ) -> ::core::result::Result<(), borsh::io::Error> { + let variant_idx: u8 = match self { + AB::B { .. } => 0u8, + AB::NegatedVariant { .. } => 1u8, + }; + writer.write_u8(variant_idx).await?; + match self { + AB::B { c, d, .. } => { + ::serialize(c, writer).await?; + ::serialize(d, writer).await?; + } + AB::NegatedVariant { beta, .. } => { + ::serialize(beta, writer).await?; + } + } + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/enums/snapshots/struct_variant_field.snap b/borsh-derive/src/internals/serialize/enums/snapshots/struct_variant_field.snap index 0ba345286..893d4794b 100644 --- a/borsh-derive/src/internals/serialize/enums/snapshots/struct_variant_field.snap +++ b/borsh-derive/src/internals/serialize/enums/snapshots/struct_variant_field.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/serialize/enums/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::ser::BorshSerialize for AB { fn serialize<__W: borsh::io::Write>( @@ -14,13 +14,13 @@ impl borsh::ser::BorshSerialize for AB { writer.write_all(&variant_idx.to_le_bytes())?; match self { AB::B { c, d, .. } => { - borsh::BorshSerialize::serialize(c, writer)?; - borsh::BorshSerialize::serialize(d, writer)?; + ::serialize(c, writer)?; + ::serialize(d, writer)?; } AB::NegatedVariant { beta, .. } => { - borsh::BorshSerialize::serialize(beta, writer)?; + ::serialize(beta, writer)?; } } - Ok(()) + ::core::result::Result::Ok(()) } } diff --git a/borsh-derive/src/internals/serialize/mod.rs b/borsh-derive/src/internals/serialize/mod.rs index b4b7a20dc..1ae0d4172 100644 --- a/borsh-derive/src/internals/serialize/mod.rs +++ b/borsh-derive/src/internals/serialize/mod.rs @@ -1,7 +1,8 @@ +use std::convert::TryFrom; + use proc_macro2::{Span, TokenStream as TokenStream2}; use quote::quote; -use std::convert::TryFrom; -use syn::{Expr, ExprPath, Generics, Ident, Index, Path}; +use syn::{parse_quote, Expr, ExprPath, Generics, Ident, Index, Path, Type}; use super::generics; @@ -21,8 +22,12 @@ impl GenericsOutput { serialize_visitor: generics::FindTyParams::new(generics), } } - fn extend(self, where_clause: &mut syn::WhereClause, cratename: &Path) { - let trait_path: Path = syn::parse2(quote! { #cratename::ser::BorshSerialize }).unwrap(); + fn extend(self, where_clause: &mut syn::WhereClause, cratename: &Path) { + let trait_path: Path = if IS_ASYNC { + parse_quote! { #cratename::ser::BorshSerializeAsync } + } else { + parse_quote! { #cratename::ser::BorshSerialize } + }; let predicates = generics::compute_predicates(self.serialize_visitor.process_for_bounds(), &trait_path); where_clause.predicates.extend(predicates); @@ -65,39 +70,54 @@ impl FieldId { impl FieldId { fn serialize_arg(&self) -> Expr { match self { - Self::Struct(name) => syn::parse2(quote! { &self.#name }).unwrap(), - Self::StructUnnamed(index) => syn::parse2(quote! { &self.#index }).unwrap(), - Self::Enum(name) => syn::parse2(quote! { #name }).unwrap(), + Self::Struct(name) => parse_quote! { &self.#name }, + Self::StructUnnamed(index) => parse_quote! { &self.#index }, + Self::Enum(name) => parse_quote! { #name }, Self::EnumUnnamed(ind) => { let field = Ident::new(&format!("id{}", ind.index), Span::mixed_site()); - syn::parse2(quote! { #field }).unwrap() + parse_quote! { #field } } } } + /// function which computes derive output [proc_macro2::TokenStream] /// of code, which serializes single field - pub fn serialize_output( + pub fn serialize_output( &self, + field_type: &Type, cratename: &Path, serialize_with: Option, ) -> TokenStream2 { let arg: Expr = self.serialize_arg(); + let dot_await = IS_ASYNC.then(|| quote! { .await }); if let Some(func) = serialize_with { - quote! { #func(#arg, writer)?; } + quote! { #func(#arg, writer)#dot_await?; } } else { - quote! { #cratename::BorshSerialize::serialize(#arg, writer)?; } + let serialize_trait = Ident::new( + if IS_ASYNC { + "BorshSerializeAsync" + } else { + "BorshSerialize" + }, + Span::call_site(), + ); + quote! { <#field_type as #cratename::#serialize_trait>::serialize(#arg, writer)#dot_await?; } } } + pub fn enum_variant_header(&self, skipped: bool) -> Option { match self { Self::Struct(..) | Self::StructUnnamed(..) => unreachable!("no variant header"), Self::Enum(name) => (!skipped).then_some(quote! { #name, }), Self::EnumUnnamed(index) => { - let field_ident = if skipped { - Ident::new(&format!("_id{}", index.index), Span::mixed_site()) - } else { - Ident::new(&format!("id{}", index.index), Span::mixed_site()) - }; + let field_ident = Ident::new( + &if skipped { + format!("_id{}", index.index) + } else { + format!("id{}", index.index) + }, + Span::mixed_site(), + ); Some(quote! { #field_ident, }) } } diff --git a/borsh-derive/src/internals/serialize/structs/mod.rs b/borsh-derive/src/internals/serialize/structs/mod.rs index 2864c78e9..75dc88893 100644 --- a/borsh-derive/src/internals/serialize/structs/mod.rs +++ b/borsh-derive/src/internals/serialize/structs/mod.rs @@ -1,15 +1,18 @@ -use proc_macro2::TokenStream as TokenStream2; +use proc_macro2::{Ident, Span, TokenStream as TokenStream2}; use quote::quote; -use syn::{Fields, ItemStruct, Path}; +use syn::{Fields, ItemStruct, Lifetime, Path, Token}; use crate::internals::{ attributes::{field, BoundType}, generics, serialize, }; -pub fn process(input: &ItemStruct, cratename: Path) -> syn::Result { +pub fn process( + input: ItemStruct, + cratename: Path, +) -> syn::Result { let name = &input.ident; - let generics = generics::without_defaults(&input.generics); + let generics = generics::without_defaults(input.generics); let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); let mut where_clause = generics::default_where(where_clause); let mut body = TokenStream2::new(); @@ -19,31 +22,63 @@ pub fn process(input: &ItemStruct, cratename: Path) -> syn::Result for field in &fields.named { let field_id = serialize::FieldId::Struct(field.ident.clone().unwrap()); - process_field(field, field_id, &cratename, &mut generics_output, &mut body)?; + process_field::( + field, + field_id, + &cratename, + &mut generics_output, + &mut body, + )?; } } Fields::Unnamed(fields) => { for (field_idx, field) in fields.unnamed.iter().enumerate() { let field_id = serialize::FieldId::new_struct_unnamed(field_idx)?; - process_field(field, field_id, &cratename, &mut generics_output, &mut body)?; + process_field::( + field, + field_id, + &cratename, + &mut generics_output, + &mut body, + )?; } } Fields::Unit => {} } - generics_output.extend(&mut where_clause, &cratename); + generics_output.extend::(&mut where_clause, &cratename); + + let serialize_trait = Ident::new( + if IS_ASYNC { + "BorshSerializeAsync" + } else { + "BorshSerialize" + }, + Span::call_site(), + ); + let writer_trait_path = if IS_ASYNC { + quote! { async_io::AsyncWrite } + } else { + quote! { io::Write } + }; + let r#async = IS_ASYNC.then(|| Token![async](Span::call_site())); + let lifetime = IS_ASYNC.then(|| Lifetime::new("'async_variant", Span::call_site())); + let lt_comma = IS_ASYNC.then(|| Token![,](Span::call_site())); Ok(quote! { - impl #impl_generics #cratename::ser::BorshSerialize for #name #ty_generics #where_clause { - fn serialize<__W: #cratename::io::Write>(&self, writer: &mut __W) -> ::core::result::Result<(), #cratename::io::Error> { + impl #impl_generics #cratename::ser::#serialize_trait for #name #ty_generics #where_clause { + #r#async fn serialize<#lifetime #lt_comma __W: #cratename::#writer_trait_path>( + &#lifetime self, + writer: &#lifetime mut __W, + ) -> ::core::result::Result<(), #cratename::io::Error> { #body - Ok(()) + ::core::result::Result::Ok(()) } } }) } -fn process_field( +fn process_field( field: &syn::Field, field_id: serialize::FieldId, cratename: &Path, @@ -51,13 +86,28 @@ fn process_field( body: &mut TokenStream2, ) -> syn::Result<()> { let parsed = field::Attributes::parse(&field.attrs)?; - let needs_bounds_derive = parsed.needs_bounds_derive(BoundType::Serialize); - generics - .overrides - .extend(parsed.collect_bounds(BoundType::Serialize)); + let needs_bounds_derive = if IS_ASYNC { + parsed.needs_async_bounds_derive(BoundType::Serialize) + } else { + parsed.needs_bounds_derive(BoundType::Serialize) + }; + generics.overrides.extend(if IS_ASYNC { + parsed.collect_async_bounds(BoundType::Serialize) + } else { + parsed.collect_bounds(BoundType::Serialize) + }); + if !parsed.skip { - let delta = field_id.serialize_output(cratename, parsed.serialize_with); + let delta = field_id.serialize_output::( + &field.ty, + cratename, + if IS_ASYNC { + parsed.serialize_with_async + } else { + parsed.serialize_with + }, + ); body.extend(delta); if needs_bounds_derive { @@ -69,149 +119,163 @@ fn process_field( #[cfg(test)] mod tests { + use syn::parse_quote; + + use super::*; use crate::internals::test_helpers::{ default_cratename, local_insta_assert_debug_snapshot, local_insta_assert_snapshot, pretty_print_syn_str, }; - use super::*; - #[test] fn simple_struct() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A { x: u64, y: String, } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process::(item_struct.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn simple_struct_with_custom_crate() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A { x: u64, y: String, } - }) - .unwrap(); + }; - let crate_: Path = syn::parse2(quote! { reexporter::borsh }).unwrap(); - let actual = process(&item_struct, crate_).unwrap(); + let crate_: Path = parse_quote! { reexporter::borsh }; - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_struct.clone(), crate_.clone()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); + + let actual = process::(item_struct, crate_).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn simple_generics() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A { x: HashMap, y: String, } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_struct.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); + + let actual = process::(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn simple_generic_tuple_struct() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct TupleA(T, u32); - }) - .unwrap(); + }; + + let actual = process::(item_struct.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - let actual = process(&item_struct, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn bound_generics() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A where V: Value { x: HashMap, y: String, } - }) - .unwrap(); + }; + + let actual = process::(item_struct.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - let actual = process(&item_struct, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn recursive_struct() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct CRecC { a: String, b: HashMap, } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process::(item_struct.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn generic_tuple_struct_borsh_skip1() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct G ( #[borsh(skip)] HashMap, U, ); - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process::(item_struct.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn generic_tuple_struct_borsh_skip2() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct G ( HashMap, #[borsh(skip)] U, ); - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process::(item_struct.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn generic_named_fields_struct_borsh_skip() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct G { #[borsh(skip)] x: HashMap, y: U, } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process::(item_struct.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn generic_associated_type() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct Parametrized where T: TraitName, @@ -219,17 +283,16 @@ mod tests { field: T::Associated, another: V, } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process::(item_struct, default_cratename()).unwrap(); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn generic_serialize_bound() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct C { a: String, #[borsh(bound(serialize = @@ -238,17 +301,38 @@ mod tests { ))] b: HashMap, } - }) - .unwrap(); + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process::(item_struct.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); + } + + #[test] + fn generic_serialize_async_bound() { + let item_struct: ItemStruct = parse_quote! { + struct C { + a: String, + #[borsh(async_bound(serialize = + "T: borsh::ser::BorshSerializeAsync + PartialOrd, + U: borsh::ser::BorshSerializeAsync" + ))] + b: HashMap, + } + }; + + let actual = process::(item_struct.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); + + let actual = process::(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn override_generic_associated_type_wrong_derive() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct Parametrized where T: TraitName { #[borsh(bound(serialize = "::Associated: borsh::ser::BorshSerialize" @@ -256,42 +340,114 @@ mod tests { field: ::Associated, another: V, } - }) - .unwrap(); + }; + + let actual = process::(item_struct.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); + + let actual = process::(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); + } + + #[test] + fn async_override_generic_associated_type_wrong_derive() { + let item_struct: ItemStruct = parse_quote! { + struct Parametrized where T: TraitName { + #[borsh(async_bound(serialize = + "::Associated: borsh::ser::BorshSerializeAsync" + ))] + field: ::Associated, + another: V, + } + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process::(item_struct.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn check_serialize_with_attr() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A { #[borsh(serialize_with = "third_party_impl::serialize_third_party")] x: ThirdParty, y: u64, } - }) - .unwrap(); + }; + + let actual = process::(item_struct.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); + + let actual = process::(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); + } + + #[test] + fn check_serialize_with_async_attr() { + let item_struct: ItemStruct = parse_quote! { + struct A { + #[borsh(serialize_with_async = "third_party_impl::serialize_third_party")] + x: ThirdParty, + y: u64, + } + }; - let actual = process(&item_struct, default_cratename()).unwrap(); + let actual = process::(item_struct.clone(), default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); - local_insta_assert_snapshot!(pretty_print_syn_str(&actual).unwrap()); + let actual = process::(item_struct, default_cratename()).unwrap(); + local_insta_assert_snapshot!(pretty_print_syn_str(actual).unwrap()); } #[test] fn check_serialize_with_skip_conflict() { - let item_struct: ItemStruct = syn::parse2(quote! { + let item_struct: ItemStruct = parse_quote! { struct A { - #[borsh(skip,serialize_with = "third_party_impl::serialize_third_party")] + #[borsh(skip, serialize_with = "third_party_impl::serialize_third_party")] x: ThirdParty, y: u64, } - }) - .unwrap(); + }; + + let actual = process::(item_struct.clone(), default_cratename()); + + let err = match actual { + Ok(..) => unreachable!("expecting error here"), + Err(err) => err, + }; + local_insta_assert_debug_snapshot!(err); + + let actual = process::(item_struct, default_cratename()); + + let err = match actual { + Ok(..) => unreachable!("expecting error here"), + Err(err) => err, + }; + local_insta_assert_debug_snapshot!(err); + } + + #[test] + fn check_serialize_with_async_skip_conflict() { + let item_struct: ItemStruct = parse_quote! { + struct A { + #[borsh(skip, serialize_with_async = "third_party_impl::serialize_third_party")] + x: ThirdParty, + y: u64, + } + }; + + let actual = process::(item_struct.clone(), default_cratename()); + + let err = match actual { + Ok(..) => unreachable!("expecting error here"), + Err(err) => err, + }; + local_insta_assert_debug_snapshot!(err); - let actual = process(&item_struct, default_cratename()); + let actual = process::(item_struct, default_cratename()); let err = match actual { Ok(..) => unreachable!("expecting error here"), diff --git a/borsh-derive/src/internals/serialize/structs/snapshots/async_override_generic_associated_type_wrong_derive-2.snap b/borsh-derive/src/internals/serialize/structs/snapshots/async_override_generic_associated_type_wrong_derive-2.snap new file mode 100644 index 000000000..9958fedc1 --- /dev/null +++ b/borsh-derive/src/internals/serialize/structs/snapshots/async_override_generic_associated_type_wrong_derive-2.snap @@ -0,0 +1,23 @@ +--- +source: borsh-derive/src/internals/serialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::ser::BorshSerializeAsync for Parametrized +where + T: TraitName, + V: borsh::ser::BorshSerializeAsync, + ::Associated: borsh::ser::BorshSerializeAsync, +{ + async fn serialize<'async_variant, __W: borsh::async_io::AsyncWrite>( + &'async_variant self, + writer: &'async_variant mut __W, + ) -> ::core::result::Result<(), borsh::io::Error> { + <::Associated as borsh::BorshSerializeAsync>::serialize( + &self.field, + writer, + ) + .await?; + ::serialize(&self.another, writer).await?; + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/structs/snapshots/async_override_generic_associated_type_wrong_derive.snap b/borsh-derive/src/internals/serialize/structs/snapshots/async_override_generic_associated_type_wrong_derive.snap new file mode 100644 index 000000000..c6ad3da20 --- /dev/null +++ b/borsh-derive/src/internals/serialize/structs/snapshots/async_override_generic_associated_type_wrong_derive.snap @@ -0,0 +1,22 @@ +--- +source: borsh-derive/src/internals/serialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::ser::BorshSerialize for Parametrized +where + T: TraitName, + T: borsh::ser::BorshSerialize, + V: borsh::ser::BorshSerialize, +{ + fn serialize<__W: borsh::io::Write>( + &self, + writer: &mut __W, + ) -> ::core::result::Result<(), borsh::io::Error> { + <::Associated as borsh::BorshSerialize>::serialize( + &self.field, + writer, + )?; + ::serialize(&self.another, writer)?; + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/structs/snapshots/bound_generics-2.snap b/borsh-derive/src/internals/serialize/structs/snapshots/bound_generics-2.snap new file mode 100644 index 000000000..1b4293232 --- /dev/null +++ b/borsh-derive/src/internals/serialize/structs/snapshots/bound_generics-2.snap @@ -0,0 +1,19 @@ +--- +source: borsh-derive/src/internals/serialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::ser::BorshSerializeAsync for A +where + V: Value, + K: borsh::ser::BorshSerializeAsync, + V: borsh::ser::BorshSerializeAsync, +{ + async fn serialize<'async_variant, __W: borsh::async_io::AsyncWrite>( + &'async_variant self, + writer: &'async_variant mut __W, + ) -> ::core::result::Result<(), borsh::io::Error> { + as borsh::BorshSerializeAsync>::serialize(&self.x, writer).await?; + ::serialize(&self.y, writer).await?; + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/structs/snapshots/bound_generics.snap b/borsh-derive/src/internals/serialize/structs/snapshots/bound_generics.snap index 5c7c6926b..15a8d413d 100644 --- a/borsh-derive/src/internals/serialize/structs/snapshots/bound_generics.snap +++ b/borsh-derive/src/internals/serialize/structs/snapshots/bound_generics.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/serialize/structs/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::ser::BorshSerialize for A where @@ -12,8 +12,8 @@ where &self, writer: &mut __W, ) -> ::core::result::Result<(), borsh::io::Error> { - borsh::BorshSerialize::serialize(&self.x, writer)?; - borsh::BorshSerialize::serialize(&self.y, writer)?; - Ok(()) + as borsh::BorshSerialize>::serialize(&self.x, writer)?; + ::serialize(&self.y, writer)?; + ::core::result::Result::Ok(()) } } diff --git a/borsh-derive/src/internals/serialize/structs/snapshots/check_serialize_with_async_attr-2.snap b/borsh-derive/src/internals/serialize/structs/snapshots/check_serialize_with_async_attr-2.snap new file mode 100644 index 000000000..bbf2faf4c --- /dev/null +++ b/borsh-derive/src/internals/serialize/structs/snapshots/check_serialize_with_async_attr-2.snap @@ -0,0 +1,18 @@ +--- +source: borsh-derive/src/internals/serialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::ser::BorshSerializeAsync for A +where + K: borsh::ser::BorshSerializeAsync, + V: borsh::ser::BorshSerializeAsync, +{ + async fn serialize<'async_variant, __W: borsh::async_io::AsyncWrite>( + &'async_variant self, + writer: &'async_variant mut __W, + ) -> ::core::result::Result<(), borsh::io::Error> { + third_party_impl::serialize_third_party(&self.x, writer).await?; + ::serialize(&self.y, writer).await?; + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/structs/snapshots/check_serialize_with_async_attr.snap b/borsh-derive/src/internals/serialize/structs/snapshots/check_serialize_with_async_attr.snap new file mode 100644 index 000000000..7816a3a1a --- /dev/null +++ b/borsh-derive/src/internals/serialize/structs/snapshots/check_serialize_with_async_attr.snap @@ -0,0 +1,18 @@ +--- +source: borsh-derive/src/internals/serialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::ser::BorshSerialize for A +where + K: borsh::ser::BorshSerialize, + V: borsh::ser::BorshSerialize, +{ + fn serialize<__W: borsh::io::Write>( + &self, + writer: &mut __W, + ) -> ::core::result::Result<(), borsh::io::Error> { + as borsh::BorshSerialize>::serialize(&self.x, writer)?; + ::serialize(&self.y, writer)?; + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/structs/snapshots/check_serialize_with_async_skip_conflict-2.snap b/borsh-derive/src/internals/serialize/structs/snapshots/check_serialize_with_async_skip_conflict-2.snap new file mode 100644 index 000000000..3b40ba358 --- /dev/null +++ b/borsh-derive/src/internals/serialize/structs/snapshots/check_serialize_with_async_skip_conflict-2.snap @@ -0,0 +1,7 @@ +--- +source: borsh-derive/src/internals/serialize/structs/mod.rs +expression: err +--- +Error( + "`skip` cannot be used at the same time as `serialize_with`, `deserialize_with`, `serialize_with_async` or `deserialize_with_async`", +) diff --git a/borsh-derive/src/internals/serialize/structs/snapshots/check_serialize_with_async_skip_conflict.snap b/borsh-derive/src/internals/serialize/structs/snapshots/check_serialize_with_async_skip_conflict.snap new file mode 100644 index 000000000..3b40ba358 --- /dev/null +++ b/borsh-derive/src/internals/serialize/structs/snapshots/check_serialize_with_async_skip_conflict.snap @@ -0,0 +1,7 @@ +--- +source: borsh-derive/src/internals/serialize/structs/mod.rs +expression: err +--- +Error( + "`skip` cannot be used at the same time as `serialize_with`, `deserialize_with`, `serialize_with_async` or `deserialize_with_async`", +) diff --git a/borsh-derive/src/internals/serialize/structs/snapshots/check_serialize_with_attr-2.snap b/borsh-derive/src/internals/serialize/structs/snapshots/check_serialize_with_attr-2.snap new file mode 100644 index 000000000..5e5d2dac9 --- /dev/null +++ b/borsh-derive/src/internals/serialize/structs/snapshots/check_serialize_with_attr-2.snap @@ -0,0 +1,19 @@ +--- +source: borsh-derive/src/internals/serialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::ser::BorshSerializeAsync for A +where + K: borsh::ser::BorshSerializeAsync, + V: borsh::ser::BorshSerializeAsync, +{ + async fn serialize<'async_variant, __W: borsh::async_io::AsyncWrite>( + &'async_variant self, + writer: &'async_variant mut __W, + ) -> ::core::result::Result<(), borsh::io::Error> { + as borsh::BorshSerializeAsync>::serialize(&self.x, writer) + .await?; + ::serialize(&self.y, writer).await?; + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/structs/snapshots/check_serialize_with_attr.snap b/borsh-derive/src/internals/serialize/structs/snapshots/check_serialize_with_attr.snap index 6d977d521..2370ac97c 100644 --- a/borsh-derive/src/internals/serialize/structs/snapshots/check_serialize_with_attr.snap +++ b/borsh-derive/src/internals/serialize/structs/snapshots/check_serialize_with_attr.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/serialize/structs/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::ser::BorshSerialize for A where @@ -12,7 +12,7 @@ where writer: &mut __W, ) -> ::core::result::Result<(), borsh::io::Error> { third_party_impl::serialize_third_party(&self.x, writer)?; - borsh::BorshSerialize::serialize(&self.y, writer)?; - Ok(()) + ::serialize(&self.y, writer)?; + ::core::result::Result::Ok(()) } } diff --git a/borsh-derive/src/internals/serialize/structs/snapshots/check_serialize_with_skip_conflict-2.snap b/borsh-derive/src/internals/serialize/structs/snapshots/check_serialize_with_skip_conflict-2.snap new file mode 100644 index 000000000..3b40ba358 --- /dev/null +++ b/borsh-derive/src/internals/serialize/structs/snapshots/check_serialize_with_skip_conflict-2.snap @@ -0,0 +1,7 @@ +--- +source: borsh-derive/src/internals/serialize/structs/mod.rs +expression: err +--- +Error( + "`skip` cannot be used at the same time as `serialize_with`, `deserialize_with`, `serialize_with_async` or `deserialize_with_async`", +) diff --git a/borsh-derive/src/internals/serialize/structs/snapshots/check_serialize_with_skip_conflict.snap b/borsh-derive/src/internals/serialize/structs/snapshots/check_serialize_with_skip_conflict.snap index 0334d44bb..3b40ba358 100644 --- a/borsh-derive/src/internals/serialize/structs/snapshots/check_serialize_with_skip_conflict.snap +++ b/borsh-derive/src/internals/serialize/structs/snapshots/check_serialize_with_skip_conflict.snap @@ -3,5 +3,5 @@ source: borsh-derive/src/internals/serialize/structs/mod.rs expression: err --- Error( - "`skip` cannot be used at the same time as `serialize_with` or `deserialize_with`", + "`skip` cannot be used at the same time as `serialize_with`, `deserialize_with`, `serialize_with_async` or `deserialize_with_async`", ) diff --git a/borsh-derive/src/internals/serialize/structs/snapshots/generic_associated_type.snap b/borsh-derive/src/internals/serialize/structs/snapshots/generic_associated_type.snap index 33b203f80..322493711 100644 --- a/borsh-derive/src/internals/serialize/structs/snapshots/generic_associated_type.snap +++ b/borsh-derive/src/internals/serialize/structs/snapshots/generic_associated_type.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/serialize/structs/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::ser::BorshSerialize for Parametrized where @@ -12,8 +12,8 @@ where &self, writer: &mut __W, ) -> ::core::result::Result<(), borsh::io::Error> { - borsh::BorshSerialize::serialize(&self.field, writer)?; - borsh::BorshSerialize::serialize(&self.another, writer)?; - Ok(()) + ::serialize(&self.field, writer)?; + ::serialize(&self.another, writer)?; + ::core::result::Result::Ok(()) } } diff --git a/borsh-derive/src/internals/serialize/structs/snapshots/generic_named_fields_struct_borsh_skip-2.snap b/borsh-derive/src/internals/serialize/structs/snapshots/generic_named_fields_struct_borsh_skip-2.snap new file mode 100644 index 000000000..225be6bc6 --- /dev/null +++ b/borsh-derive/src/internals/serialize/structs/snapshots/generic_named_fields_struct_borsh_skip-2.snap @@ -0,0 +1,16 @@ +--- +source: borsh-derive/src/internals/serialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::ser::BorshSerializeAsync for G +where + U: borsh::ser::BorshSerializeAsync, +{ + async fn serialize<'async_variant, __W: borsh::async_io::AsyncWrite>( + &'async_variant self, + writer: &'async_variant mut __W, + ) -> ::core::result::Result<(), borsh::io::Error> { + ::serialize(&self.y, writer).await?; + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/structs/snapshots/generic_named_fields_struct_borsh_skip.snap b/borsh-derive/src/internals/serialize/structs/snapshots/generic_named_fields_struct_borsh_skip.snap index 5351f166f..0526e2c5b 100644 --- a/borsh-derive/src/internals/serialize/structs/snapshots/generic_named_fields_struct_borsh_skip.snap +++ b/borsh-derive/src/internals/serialize/structs/snapshots/generic_named_fields_struct_borsh_skip.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/serialize/structs/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::ser::BorshSerialize for G where @@ -10,7 +10,7 @@ where &self, writer: &mut __W, ) -> ::core::result::Result<(), borsh::io::Error> { - borsh::BorshSerialize::serialize(&self.y, writer)?; - Ok(()) + ::serialize(&self.y, writer)?; + ::core::result::Result::Ok(()) } } diff --git a/borsh-derive/src/internals/serialize/structs/snapshots/generic_serialize_async_bound-2.snap b/borsh-derive/src/internals/serialize/structs/snapshots/generic_serialize_async_bound-2.snap new file mode 100644 index 000000000..dea73c518 --- /dev/null +++ b/borsh-derive/src/internals/serialize/structs/snapshots/generic_serialize_async_bound-2.snap @@ -0,0 +1,18 @@ +--- +source: borsh-derive/src/internals/serialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::ser::BorshSerializeAsync for C +where + T: borsh::ser::BorshSerializeAsync + PartialOrd, + U: borsh::ser::BorshSerializeAsync, +{ + async fn serialize<'async_variant, __W: borsh::async_io::AsyncWrite>( + &'async_variant self, + writer: &'async_variant mut __W, + ) -> ::core::result::Result<(), borsh::io::Error> { + ::serialize(&self.a, writer).await?; + as borsh::BorshSerializeAsync>::serialize(&self.b, writer).await?; + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/structs/snapshots/generic_serialize_async_bound.snap b/borsh-derive/src/internals/serialize/structs/snapshots/generic_serialize_async_bound.snap new file mode 100644 index 000000000..b960585ae --- /dev/null +++ b/borsh-derive/src/internals/serialize/structs/snapshots/generic_serialize_async_bound.snap @@ -0,0 +1,18 @@ +--- +source: borsh-derive/src/internals/serialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::ser::BorshSerialize for C +where + T: borsh::ser::BorshSerialize, + U: borsh::ser::BorshSerialize, +{ + fn serialize<__W: borsh::io::Write>( + &self, + writer: &mut __W, + ) -> ::core::result::Result<(), borsh::io::Error> { + ::serialize(&self.a, writer)?; + as borsh::BorshSerialize>::serialize(&self.b, writer)?; + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/structs/snapshots/generic_serialize_bound-2.snap b/borsh-derive/src/internals/serialize/structs/snapshots/generic_serialize_bound-2.snap new file mode 100644 index 000000000..62754e200 --- /dev/null +++ b/borsh-derive/src/internals/serialize/structs/snapshots/generic_serialize_bound-2.snap @@ -0,0 +1,18 @@ +--- +source: borsh-derive/src/internals/serialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::ser::BorshSerializeAsync for C +where + T: borsh::ser::BorshSerializeAsync, + U: borsh::ser::BorshSerializeAsync, +{ + async fn serialize<'async_variant, __W: borsh::async_io::AsyncWrite>( + &'async_variant self, + writer: &'async_variant mut __W, + ) -> ::core::result::Result<(), borsh::io::Error> { + ::serialize(&self.a, writer).await?; + as borsh::BorshSerializeAsync>::serialize(&self.b, writer).await?; + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/structs/snapshots/generic_serialize_bound.snap b/borsh-derive/src/internals/serialize/structs/snapshots/generic_serialize_bound.snap index c0309d69a..ad8e7908a 100644 --- a/borsh-derive/src/internals/serialize/structs/snapshots/generic_serialize_bound.snap +++ b/borsh-derive/src/internals/serialize/structs/snapshots/generic_serialize_bound.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/serialize/structs/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::ser::BorshSerialize for C where @@ -11,8 +11,8 @@ where &self, writer: &mut __W, ) -> ::core::result::Result<(), borsh::io::Error> { - borsh::BorshSerialize::serialize(&self.a, writer)?; - borsh::BorshSerialize::serialize(&self.b, writer)?; - Ok(()) + ::serialize(&self.a, writer)?; + as borsh::BorshSerialize>::serialize(&self.b, writer)?; + ::core::result::Result::Ok(()) } } diff --git a/borsh-derive/src/internals/serialize/structs/snapshots/generic_tuple_struct_borsh_skip1-2.snap b/borsh-derive/src/internals/serialize/structs/snapshots/generic_tuple_struct_borsh_skip1-2.snap new file mode 100644 index 000000000..56479f61c --- /dev/null +++ b/borsh-derive/src/internals/serialize/structs/snapshots/generic_tuple_struct_borsh_skip1-2.snap @@ -0,0 +1,16 @@ +--- +source: borsh-derive/src/internals/serialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::ser::BorshSerializeAsync for G +where + U: borsh::ser::BorshSerializeAsync, +{ + async fn serialize<'async_variant, __W: borsh::async_io::AsyncWrite>( + &'async_variant self, + writer: &'async_variant mut __W, + ) -> ::core::result::Result<(), borsh::io::Error> { + ::serialize(&self.1, writer).await?; + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/structs/snapshots/generic_tuple_struct_borsh_skip1.snap b/borsh-derive/src/internals/serialize/structs/snapshots/generic_tuple_struct_borsh_skip1.snap index 447fcb32e..2ba771ccb 100644 --- a/borsh-derive/src/internals/serialize/structs/snapshots/generic_tuple_struct_borsh_skip1.snap +++ b/borsh-derive/src/internals/serialize/structs/snapshots/generic_tuple_struct_borsh_skip1.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/serialize/structs/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::ser::BorshSerialize for G where @@ -10,7 +10,7 @@ where &self, writer: &mut __W, ) -> ::core::result::Result<(), borsh::io::Error> { - borsh::BorshSerialize::serialize(&self.1, writer)?; - Ok(()) + ::serialize(&self.1, writer)?; + ::core::result::Result::Ok(()) } } diff --git a/borsh-derive/src/internals/serialize/structs/snapshots/generic_tuple_struct_borsh_skip2-2.snap b/borsh-derive/src/internals/serialize/structs/snapshots/generic_tuple_struct_borsh_skip2-2.snap new file mode 100644 index 000000000..1ff89c2d7 --- /dev/null +++ b/borsh-derive/src/internals/serialize/structs/snapshots/generic_tuple_struct_borsh_skip2-2.snap @@ -0,0 +1,17 @@ +--- +source: borsh-derive/src/internals/serialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::ser::BorshSerializeAsync for G +where + K: borsh::ser::BorshSerializeAsync, + V: borsh::ser::BorshSerializeAsync, +{ + async fn serialize<'async_variant, __W: borsh::async_io::AsyncWrite>( + &'async_variant self, + writer: &'async_variant mut __W, + ) -> ::core::result::Result<(), borsh::io::Error> { + as borsh::BorshSerializeAsync>::serialize(&self.0, writer).await?; + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/structs/snapshots/generic_tuple_struct_borsh_skip2.snap b/borsh-derive/src/internals/serialize/structs/snapshots/generic_tuple_struct_borsh_skip2.snap index 8c5800a25..59b43cd7f 100644 --- a/borsh-derive/src/internals/serialize/structs/snapshots/generic_tuple_struct_borsh_skip2.snap +++ b/borsh-derive/src/internals/serialize/structs/snapshots/generic_tuple_struct_borsh_skip2.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/serialize/structs/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::ser::BorshSerialize for G where @@ -11,7 +11,7 @@ where &self, writer: &mut __W, ) -> ::core::result::Result<(), borsh::io::Error> { - borsh::BorshSerialize::serialize(&self.0, writer)?; - Ok(()) + as borsh::BorshSerialize>::serialize(&self.0, writer)?; + ::core::result::Result::Ok(()) } } diff --git a/borsh-derive/src/internals/serialize/structs/snapshots/override_generic_associated_type_wrong_derive-2.snap b/borsh-derive/src/internals/serialize/structs/snapshots/override_generic_associated_type_wrong_derive-2.snap new file mode 100644 index 000000000..568115c56 --- /dev/null +++ b/borsh-derive/src/internals/serialize/structs/snapshots/override_generic_associated_type_wrong_derive-2.snap @@ -0,0 +1,23 @@ +--- +source: borsh-derive/src/internals/serialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::ser::BorshSerializeAsync for Parametrized +where + T: TraitName, + T: borsh::ser::BorshSerializeAsync, + V: borsh::ser::BorshSerializeAsync, +{ + async fn serialize<'async_variant, __W: borsh::async_io::AsyncWrite>( + &'async_variant self, + writer: &'async_variant mut __W, + ) -> ::core::result::Result<(), borsh::io::Error> { + <::Associated as borsh::BorshSerializeAsync>::serialize( + &self.field, + writer, + ) + .await?; + ::serialize(&self.another, writer).await?; + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/structs/snapshots/override_generic_associated_type_wrong_derive.snap b/borsh-derive/src/internals/serialize/structs/snapshots/override_generic_associated_type_wrong_derive.snap index 9b2bf20b3..c7bd3fd42 100644 --- a/borsh-derive/src/internals/serialize/structs/snapshots/override_generic_associated_type_wrong_derive.snap +++ b/borsh-derive/src/internals/serialize/structs/snapshots/override_generic_associated_type_wrong_derive.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/serialize/structs/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::ser::BorshSerialize for Parametrized where @@ -12,8 +12,11 @@ where &self, writer: &mut __W, ) -> ::core::result::Result<(), borsh::io::Error> { - borsh::BorshSerialize::serialize(&self.field, writer)?; - borsh::BorshSerialize::serialize(&self.another, writer)?; - Ok(()) + <::Associated as borsh::BorshSerialize>::serialize( + &self.field, + writer, + )?; + ::serialize(&self.another, writer)?; + ::core::result::Result::Ok(()) } } diff --git a/borsh-derive/src/internals/serialize/structs/snapshots/recursive_struct-2.snap b/borsh-derive/src/internals/serialize/structs/snapshots/recursive_struct-2.snap new file mode 100644 index 000000000..6f25d5914 --- /dev/null +++ b/borsh-derive/src/internals/serialize/structs/snapshots/recursive_struct-2.snap @@ -0,0 +1,18 @@ +--- +source: borsh-derive/src/internals/serialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::ser::BorshSerializeAsync for CRecC { + async fn serialize<'async_variant, __W: borsh::async_io::AsyncWrite>( + &'async_variant self, + writer: &'async_variant mut __W, + ) -> ::core::result::Result<(), borsh::io::Error> { + ::serialize(&self.a, writer).await?; + as borsh::BorshSerializeAsync>::serialize(&self.b, writer) + .await?; + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/structs/snapshots/recursive_struct.snap b/borsh-derive/src/internals/serialize/structs/snapshots/recursive_struct.snap index 510b71b77..33be64902 100644 --- a/borsh-derive/src/internals/serialize/structs/snapshots/recursive_struct.snap +++ b/borsh-derive/src/internals/serialize/structs/snapshots/recursive_struct.snap @@ -1,14 +1,14 @@ --- source: borsh-derive/src/internals/serialize/structs/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::ser::BorshSerialize for CRecC { fn serialize<__W: borsh::io::Write>( &self, writer: &mut __W, ) -> ::core::result::Result<(), borsh::io::Error> { - borsh::BorshSerialize::serialize(&self.a, writer)?; - borsh::BorshSerialize::serialize(&self.b, writer)?; - Ok(()) + ::serialize(&self.a, writer)?; + as borsh::BorshSerialize>::serialize(&self.b, writer)?; + ::core::result::Result::Ok(()) } } diff --git a/borsh-derive/src/internals/serialize/structs/snapshots/simple_generic_tuple_struct-2.snap b/borsh-derive/src/internals/serialize/structs/snapshots/simple_generic_tuple_struct-2.snap new file mode 100644 index 000000000..a94669553 --- /dev/null +++ b/borsh-derive/src/internals/serialize/structs/snapshots/simple_generic_tuple_struct-2.snap @@ -0,0 +1,17 @@ +--- +source: borsh-derive/src/internals/serialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::ser::BorshSerializeAsync for TupleA +where + T: borsh::ser::BorshSerializeAsync, +{ + async fn serialize<'async_variant, __W: borsh::async_io::AsyncWrite>( + &'async_variant self, + writer: &'async_variant mut __W, + ) -> ::core::result::Result<(), borsh::io::Error> { + ::serialize(&self.0, writer).await?; + ::serialize(&self.1, writer).await?; + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/structs/snapshots/simple_generic_tuple_struct.snap b/borsh-derive/src/internals/serialize/structs/snapshots/simple_generic_tuple_struct.snap index 984defae9..7486c2358 100644 --- a/borsh-derive/src/internals/serialize/structs/snapshots/simple_generic_tuple_struct.snap +++ b/borsh-derive/src/internals/serialize/structs/snapshots/simple_generic_tuple_struct.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/serialize/structs/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::ser::BorshSerialize for TupleA where @@ -10,8 +10,8 @@ where &self, writer: &mut __W, ) -> ::core::result::Result<(), borsh::io::Error> { - borsh::BorshSerialize::serialize(&self.0, writer)?; - borsh::BorshSerialize::serialize(&self.1, writer)?; - Ok(()) + ::serialize(&self.0, writer)?; + ::serialize(&self.1, writer)?; + ::core::result::Result::Ok(()) } } diff --git a/borsh-derive/src/internals/serialize/structs/snapshots/simple_generics-2.snap b/borsh-derive/src/internals/serialize/structs/snapshots/simple_generics-2.snap new file mode 100644 index 000000000..299dcfd67 --- /dev/null +++ b/borsh-derive/src/internals/serialize/structs/snapshots/simple_generics-2.snap @@ -0,0 +1,18 @@ +--- +source: borsh-derive/src/internals/serialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::ser::BorshSerializeAsync for A +where + K: borsh::ser::BorshSerializeAsync, + V: borsh::ser::BorshSerializeAsync, +{ + async fn serialize<'async_variant, __W: borsh::async_io::AsyncWrite>( + &'async_variant self, + writer: &'async_variant mut __W, + ) -> ::core::result::Result<(), borsh::io::Error> { + as borsh::BorshSerializeAsync>::serialize(&self.x, writer).await?; + ::serialize(&self.y, writer).await?; + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/structs/snapshots/simple_generics.snap b/borsh-derive/src/internals/serialize/structs/snapshots/simple_generics.snap index 3518ba3a4..47667b80d 100644 --- a/borsh-derive/src/internals/serialize/structs/snapshots/simple_generics.snap +++ b/borsh-derive/src/internals/serialize/structs/snapshots/simple_generics.snap @@ -1,6 +1,6 @@ --- source: borsh-derive/src/internals/serialize/structs/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::ser::BorshSerialize for A where @@ -11,8 +11,8 @@ where &self, writer: &mut __W, ) -> ::core::result::Result<(), borsh::io::Error> { - borsh::BorshSerialize::serialize(&self.x, writer)?; - borsh::BorshSerialize::serialize(&self.y, writer)?; - Ok(()) + as borsh::BorshSerialize>::serialize(&self.x, writer)?; + ::serialize(&self.y, writer)?; + ::core::result::Result::Ok(()) } } diff --git a/borsh-derive/src/internals/serialize/structs/snapshots/simple_struct-2.snap b/borsh-derive/src/internals/serialize/structs/snapshots/simple_struct-2.snap new file mode 100644 index 000000000..5e9b3b15e --- /dev/null +++ b/borsh-derive/src/internals/serialize/structs/snapshots/simple_struct-2.snap @@ -0,0 +1,14 @@ +--- +source: borsh-derive/src/internals/serialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl borsh::ser::BorshSerializeAsync for A { + async fn serialize<'async_variant, __W: borsh::async_io::AsyncWrite>( + &'async_variant self, + writer: &'async_variant mut __W, + ) -> ::core::result::Result<(), borsh::io::Error> { + ::serialize(&self.x, writer).await?; + ::serialize(&self.y, writer).await?; + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/structs/snapshots/simple_struct.snap b/borsh-derive/src/internals/serialize/structs/snapshots/simple_struct.snap index 8904dca85..eac613281 100644 --- a/borsh-derive/src/internals/serialize/structs/snapshots/simple_struct.snap +++ b/borsh-derive/src/internals/serialize/structs/snapshots/simple_struct.snap @@ -1,14 +1,14 @@ --- source: borsh-derive/src/internals/serialize/structs/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl borsh::ser::BorshSerialize for A { fn serialize<__W: borsh::io::Write>( &self, writer: &mut __W, ) -> ::core::result::Result<(), borsh::io::Error> { - borsh::BorshSerialize::serialize(&self.x, writer)?; - borsh::BorshSerialize::serialize(&self.y, writer)?; - Ok(()) + ::serialize(&self.x, writer)?; + ::serialize(&self.y, writer)?; + ::core::result::Result::Ok(()) } } diff --git a/borsh-derive/src/internals/serialize/structs/snapshots/simple_struct_with_custom_crate-2.snap b/borsh-derive/src/internals/serialize/structs/snapshots/simple_struct_with_custom_crate-2.snap new file mode 100644 index 000000000..8361c83c3 --- /dev/null +++ b/borsh-derive/src/internals/serialize/structs/snapshots/simple_struct_with_custom_crate-2.snap @@ -0,0 +1,16 @@ +--- +source: borsh-derive/src/internals/serialize/structs/mod.rs +expression: pretty_print_syn_str(actual).unwrap() +--- +impl reexporter::borsh::ser::BorshSerializeAsync for A { + async fn serialize<'async_variant, __W: reexporter::borsh::async_io::AsyncWrite>( + &'async_variant self, + writer: &'async_variant mut __W, + ) -> ::core::result::Result<(), reexporter::borsh::io::Error> { + ::serialize(&self.x, writer) + .await?; + ::serialize(&self.y, writer) + .await?; + ::core::result::Result::Ok(()) + } +} diff --git a/borsh-derive/src/internals/serialize/structs/snapshots/simple_struct_with_custom_crate.snap b/borsh-derive/src/internals/serialize/structs/snapshots/simple_struct_with_custom_crate.snap index bd331f30d..462572e22 100644 --- a/borsh-derive/src/internals/serialize/structs/snapshots/simple_struct_with_custom_crate.snap +++ b/borsh-derive/src/internals/serialize/structs/snapshots/simple_struct_with_custom_crate.snap @@ -1,14 +1,14 @@ --- source: borsh-derive/src/internals/serialize/structs/mod.rs -expression: pretty_print_syn_str(&actual).unwrap() +expression: pretty_print_syn_str(actual).unwrap() --- impl reexporter::borsh::ser::BorshSerialize for A { fn serialize<__W: reexporter::borsh::io::Write>( &self, writer: &mut __W, ) -> ::core::result::Result<(), reexporter::borsh::io::Error> { - reexporter::borsh::BorshSerialize::serialize(&self.x, writer)?; - reexporter::borsh::BorshSerialize::serialize(&self.y, writer)?; - Ok(()) + ::serialize(&self.x, writer)?; + ::serialize(&self.y, writer)?; + ::core::result::Result::Ok(()) } } diff --git a/borsh-derive/src/internals/serialize/unions/mod.rs b/borsh-derive/src/internals/serialize/unions/mod.rs index 3806821bd..89200b4ea 100644 --- a/borsh-derive/src/internals/serialize/unions/mod.rs +++ b/borsh-derive/src/internals/serialize/unions/mod.rs @@ -1,6 +1,9 @@ use proc_macro2::TokenStream as TokenStream2; use syn::{ItemUnion, Path}; -pub fn process(_input: &ItemUnion, _cratename: Path) -> syn::Result { +pub fn process( + _input: ItemUnion, + _cratename: Path, +) -> syn::Result { unimplemented!() } diff --git a/borsh-derive/src/internals/test_helpers.rs b/borsh-derive/src/internals/test_helpers.rs index 806b7c826..a4ce8ae4a 100644 --- a/borsh-derive/src/internals/test_helpers.rs +++ b/borsh-derive/src/internals/test_helpers.rs @@ -1,37 +1,36 @@ -use super::cratename::BORSH; -use proc_macro2::Span; -use proc_macro2::TokenStream; -use quote::{quote, ToTokens}; -use std::fmt::Write; +use proc_macro2::{Span, TokenStream}; +use quote::ToTokens; use syn::{Ident, Path}; -pub fn pretty_print_syn_str(input: &TokenStream) -> syn::Result { - let input = format!("{}", quote!(#input)); - let syn_file = syn::parse_str::(&input)?; +use super::cratename::BORSH; + +pub fn pretty_print_syn_str(input: TokenStream) -> syn::Result { + let syn_file = syn::parse2::(input)?; Ok(prettyplease::unparse(&syn_file)) } pub fn debug_print_vec_of_tokenizable(optional: Option>) -> String { - let mut s = String::new(); if let Some(vec) = optional { + let mut s = String::new(); for element in vec { - writeln!(&mut s, "{}", element.to_token_stream()).unwrap(); + s.push_str(&element.to_token_stream().to_string()); + s.push('\n'); } + s } else { - write!(&mut s, "None").unwrap(); + "None".to_owned() } - s } pub fn debug_print_tokenizable(optional: Option) -> String { - let mut s = String::new(); if let Some(type_) = optional { - writeln!(&mut s, "{}", type_.to_token_stream()).unwrap(); + let mut s = type_.to_token_stream().to_string(); + s.push('\n'); + s } else { - write!(&mut s, "None").unwrap(); + "None".to_owned() } - s } macro_rules! local_insta_assert_debug_snapshot { @@ -57,4 +56,5 @@ pub(crate) fn default_cratename() -> Path { cratename.into() } -pub(crate) use {local_insta_assert_debug_snapshot, local_insta_assert_snapshot}; +pub(crate) use local_insta_assert_debug_snapshot; +pub(crate) use local_insta_assert_snapshot; diff --git a/borsh-derive/src/lib.rs b/borsh-derive/src/lib.rs index f12dd3992..6f6ae501c 100644 --- a/borsh-derive/src/lib.rs +++ b/borsh-derive/src/lib.rs @@ -14,12 +14,12 @@ use syn::{DeriveInput, Error, ItemEnum, ItemStruct, ItemUnion, Path}; /// by convention, local to borsh-derive crate, imports from proc_macro (1) are not allowed in `internals` module or in any of its submodules. mod internals; -use crate::internals::attributes::item; - #[cfg(feature = "schema")] use internals::schema; use internals::{cratename, deserialize, serialize}; +use crate::internals::attributes::item; + fn check_attrs_get_cratename(input: &TokenStream) -> Result { let input = input.clone(); @@ -35,6 +35,18 @@ fn check_attrs_get_cratename(input: &TokenStream) -> Result { /// moved to docs of **Derive Macro** `BorshSerialize` in `borsh` crate #[proc_macro_derive(BorshSerialize, attributes(borsh))] pub fn borsh_serialize(input: TokenStream) -> TokenStream { + borsh_serialize_generic::(input) +} + +/// --- +/// +/// moved to docs of **Derive Macro** `BorshSerializeAsync` in `borsh` crate +#[proc_macro_derive(BorshSerializeAsync, attributes(borsh))] +pub fn borsh_serialize_async(input: TokenStream) -> TokenStream { + borsh_serialize_generic::(input) +} + +fn borsh_serialize_generic(input: TokenStream) -> TokenStream { let cratename = match check_attrs_get_cratename(&input) { Ok(cratename) => cratename, Err(err) => { @@ -43,19 +55,16 @@ pub fn borsh_serialize(input: TokenStream) -> TokenStream { }; let res = if let Ok(input) = syn::parse::(input.clone()) { - serialize::structs::process(&input, cratename) + serialize::structs::process::(input, cratename) } else if let Ok(input) = syn::parse::(input.clone()) { - serialize::enums::process(&input, cratename) + serialize::enums::process::(input, cratename) } else if let Ok(input) = syn::parse::(input) { - serialize::unions::process(&input, cratename) + serialize::unions::process::(input, cratename) } else { // Derive macros can only be defined on structs, enums, and unions. unreachable!() }; - TokenStream::from(match res { - Ok(res) => res, - Err(err) => err.to_compile_error(), - }) + TokenStream::from(res.unwrap_or_else(|err| err.to_compile_error())) } /// --- @@ -63,6 +72,18 @@ pub fn borsh_serialize(input: TokenStream) -> TokenStream { /// moved to docs of **Derive Macro** `BorshDeserialize` in `borsh` crate #[proc_macro_derive(BorshDeserialize, attributes(borsh))] pub fn borsh_deserialize(input: TokenStream) -> TokenStream { + borsh_deserialize_generic::(input) +} + +/// --- +/// +/// moved to docs of **Derive Macro** `BorshDeserializeAsync` in `borsh` crate +#[proc_macro_derive(BorshDeserializeAsync, attributes(borsh))] +pub fn borsh_deserialize_async(input: TokenStream) -> TokenStream { + borsh_deserialize_generic::(input) +} + +fn borsh_deserialize_generic(input: TokenStream) -> TokenStream { let cratename = match check_attrs_get_cratename(&input) { Ok(cratename) => cratename, Err(err) => { @@ -71,19 +92,16 @@ pub fn borsh_deserialize(input: TokenStream) -> TokenStream { }; let res = if let Ok(input) = syn::parse::(input.clone()) { - deserialize::structs::process(&input, cratename) + deserialize::structs::process::(input, cratename) } else if let Ok(input) = syn::parse::(input.clone()) { - deserialize::enums::process(&input, cratename) + deserialize::enums::process::(input, cratename) } else if let Ok(input) = syn::parse::(input) { - deserialize::unions::process(&input, cratename) + deserialize::unions::process::(input, cratename) } else { // Derive macros can only be defined on structs, enums, and unions. unreachable!() }; - TokenStream::from(match res { - Ok(res) => res, - Err(err) => err.to_compile_error(), - }) + TokenStream::from(res.unwrap_or_else(|err| err.to_compile_error())) } /// --- @@ -100,11 +118,11 @@ pub fn borsh_schema(input: TokenStream) -> TokenStream { }; let res = if let Ok(input) = syn::parse::(input.clone()) { - schema::structs::process(&input, cratename) + schema::structs::process(input, cratename) } else if let Ok(input) = syn::parse::(input.clone()) { - schema::enums::process(&input, cratename) + schema::enums::process(input, cratename) } else if syn::parse::(input).is_ok() { - Err(syn::Error::new( + Err(Error::new( Span::call_site(), "Borsh schema does not support unions yet.", )) @@ -112,8 +130,5 @@ pub fn borsh_schema(input: TokenStream) -> TokenStream { // Derive macros can only be defined on structs, enums, and unions. unreachable!() }; - TokenStream::from(match res { - Ok(res) => res, - Err(err) => err.to_compile_error(), - }) + TokenStream::from(res.unwrap_or_else(|err| err.to_compile_error())) } diff --git a/borsh/Cargo.toml b/borsh/Cargo.toml index 4a7cd7bcc..4e9353746 100644 --- a/borsh/Cargo.toml +++ b/borsh/Cargo.toml @@ -3,7 +3,7 @@ name = "borsh" version.workspace = true rust-version.workspace = true authors = ["Near Inc "] -edition = "2018" +edition.workspace = true license = "MIT OR Apache-2.0" readme = "README.md" categories = ["encoding", "network-programming"] @@ -41,7 +41,12 @@ hashbrown = { version = ">=0.11,<0.16.0", optional = true } bytes = { version = "1", optional = true } bson = { version = "2", optional = true } +async-generic = { git = "https://github.com/DanikVitek/async-generic.git", rev = "392e8ef432c9bf4ca381262f56e192a27136e04f" } +tokio = { version = "1", default-features = false, features = ["io-util"], optional = true } +async-std = { version = "1", default-features = false, features = ["std"], optional = true } + [dev-dependencies] +tokio-test = "0.4.4" insta = "1.29.0" serde_json = { version = "1" } @@ -52,6 +57,9 @@ targets = ["x86_64-unknown-linux-gnu"] [features] default = ["std"] derive = ["borsh-derive"] +unstable__async = [] +unstable__tokio = ["unstable__async", "dep:tokio", "std"] +unstable__async-std = ["unstable__async", "dep:async-std", "std"] unstable__schema = ["derive", "borsh-derive/schema"] std = [] # Opt into impls for Rc and Arc. Serializing and deserializing these types diff --git a/borsh/examples/serde_json_value.rs b/borsh/examples/serde_json_value.rs index 21cadf758..dbbd599d8 100644 --- a/borsh/examples/serde_json_value.rs +++ b/borsh/examples/serde_json_value.rs @@ -3,14 +3,18 @@ use std::collections::HashMap; use borsh::{BorshDeserialize, BorshSerialize}; mod serde_json_value { + #[allow(unused_imports)] // used in attribute pub use de::deserialize_value; + #[allow(unused_imports)] // used in attribute pub use ser::serialize_value; + mod ser { + use core::convert::TryFrom; + use borsh::{ io::{ErrorKind, Result, Write}, BorshSerialize, }; - use core::convert::TryFrom; /// this is mutually recursive with `serialize_array` and `serialize_map` pub fn serialize_value(value: &serde_json::Value, writer: &mut W) -> Result<()> { diff --git a/borsh/src/async_io.rs b/borsh/src/async_io.rs new file mode 100644 index 000000000..66e2d3a78 --- /dev/null +++ b/borsh/src/async_io.rs @@ -0,0 +1,397 @@ +use core::future::Future; + +use crate::io::Result; + +pub trait AsyncRead: Unpin + Send { + fn read<'a>(&'a mut self, buf: &'a mut [u8]) + -> impl Future> + Send + 'a; + + fn read_exact<'a>( + &'a mut self, + buf: &'a mut [u8], + ) -> impl Future> + Send + 'a { + async { + let mut offset = 0; + while offset < buf.len() { + let read = self.read(&mut buf[offset..]).await?; + if read == 0 { + return Err(crate::io::Error::new( + crate::io::ErrorKind::UnexpectedEof, + "failed to fill the whole buffer", + )); + } + offset += read; + } + Ok(()) + } + } + + fn read_u8(&mut self) -> impl Future> + Send { + async { + let mut buf = [0u8; 1]; + self.read_exact(&mut buf).await?; + Ok(buf[0]) + } + } + + fn read_u16(&mut self) -> impl Future> + Send { + async { + let mut buf = [0u8; 2]; + self.read_exact(&mut buf).await?; + Ok(u16::from_le_bytes(buf)) + } + } + + fn read_u32(&mut self) -> impl Future> + Send { + async { + let mut buf = [0u8; 4]; + self.read_exact(&mut buf).await?; + Ok(u32::from_le_bytes(buf)) + } + } + + fn read_u64(&mut self) -> impl Future> + Send { + async { + let mut buf = [0u8; 8]; + self.read_exact(&mut buf).await?; + Ok(u64::from_le_bytes(buf)) + } + } + + fn read_u128(&mut self) -> impl Future> + Send { + async { + let mut buf = [0u8; 16]; + self.read_exact(&mut buf).await?; + Ok(u128::from_le_bytes(buf)) + } + } + + fn read_i8(&mut self) -> impl Future> + Send { + async { + let mut buf = [0u8; 1]; + self.read_exact(&mut buf).await?; + Ok(buf[0] as i8) + } + } + + fn read_i16(&mut self) -> impl Future> + Send { + async { + let mut buf = [0u8; 2]; + self.read_exact(&mut buf).await?; + Ok(i16::from_le_bytes(buf)) + } + } + + fn read_i32(&mut self) -> impl Future> + Send { + async { + let mut buf = [0u8; 4]; + self.read_exact(&mut buf).await?; + Ok(i32::from_le_bytes(buf)) + } + } + + fn read_i64(&mut self) -> impl Future> + Send { + async { + let mut buf = [0u8; 8]; + self.read_exact(&mut buf).await?; + Ok(i64::from_le_bytes(buf)) + } + } + + fn read_i128(&mut self) -> impl Future> + Send { + async { + let mut buf = [0u8; 16]; + self.read_exact(&mut buf).await?; + Ok(i128::from_le_bytes(buf)) + } + } + + fn read_f32(&mut self) -> impl Future> + Send { + async { + let mut buf = [0u8; 4]; + self.read_exact(&mut buf).await?; + Ok(f32::from_le_bytes(buf)) + } + } + + fn read_f64(&mut self) -> impl Future> + Send { + async { + let mut buf = [0u8; 8]; + self.read_exact(&mut buf).await?; + Ok(f64::from_le_bytes(buf)) + } + } +} + +#[cfg(feature = "unstable__tokio")] +impl AsyncRead for R { + #[inline] + fn read<'a>( + &'a mut self, + buf: &'a mut [u8], + ) -> impl Future> + Send + 'a { + tokio::io::AsyncReadExt::read(self, buf) + } + + #[inline] + async fn read_exact<'a>(&'a mut self, buf: &'a mut [u8]) -> Result<()> { + tokio::io::AsyncReadExt::read_exact(self, buf) + .await + .map(|_| ()) + } + + #[inline] + fn read_u8(&mut self) -> impl Future> + Send { + tokio::io::AsyncReadExt::read_u8(self) + } + + #[inline] + fn read_u16(&mut self) -> impl Future> + Send { + tokio::io::AsyncReadExt::read_u16_le(self) + } + + #[inline] + fn read_u32(&mut self) -> impl Future> + Send { + tokio::io::AsyncReadExt::read_u32_le(self) + } + + #[inline] + fn read_u64(&mut self) -> impl Future> + Send { + tokio::io::AsyncReadExt::read_u64_le(self) + } + + #[inline] + fn read_u128(&mut self) -> impl Future> + Send { + tokio::io::AsyncReadExt::read_u128_le(self) + } + + #[inline] + fn read_i8(&mut self) -> impl Future> + Send { + tokio::io::AsyncReadExt::read_i8(self) + } + + #[inline] + fn read_i16(&mut self) -> impl Future> + Send { + tokio::io::AsyncReadExt::read_i16_le(self) + } + + #[inline] + fn read_i32(&mut self) -> impl Future> + Send { + tokio::io::AsyncReadExt::read_i32_le(self) + } + + #[inline] + fn read_i64(&mut self) -> impl Future> + Send { + tokio::io::AsyncReadExt::read_i64_le(self) + } + + #[inline] + fn read_i128(&mut self) -> impl Future> + Send { + tokio::io::AsyncReadExt::read_i128_le(self) + } + + #[inline] + fn read_f32(&mut self) -> impl Future> + Send { + tokio::io::AsyncReadExt::read_f32_le(self) + } + + #[inline] + fn read_f64(&mut self) -> impl Future> + Send { + tokio::io::AsyncReadExt::read_f64_le(self) + } +} + +#[cfg(feature = "unstable__async-std")] +impl AsyncRead for R { + #[inline] + fn read<'a>( + &'a mut self, + buf: &'a mut [u8], + ) -> impl Future> + Send + 'a { + async_std::io::ReadExt::read(self, buf) + } + + #[inline] + fn read_exact<'a>( + &'a mut self, + buf: &'a mut [u8], + ) -> impl Future> + Send + 'a { + async_std::io::ReadExt::read_exact(self, buf) + } +} + +pub trait AsyncWrite: Unpin + Send { + fn write_all<'a>(&'a mut self, buf: &'a [u8]) -> impl Future> + Send + 'a; + + fn write_u8(&mut self, n: u8) -> impl Future> + Send { + async move { + let bytes = n.to_le_bytes(); + self.write_all(&bytes).await?; + Ok(()) + } + } + + fn write_u16(&mut self, n: u16) -> impl Future> + Send { + async move { + let bytes = n.to_le_bytes(); + self.write_all(&bytes).await?; + Ok(()) + } + } + + fn write_u32(&mut self, n: u32) -> impl Future> + Send { + async move { + let bytes = n.to_le_bytes(); + self.write_all(&bytes).await?; + Ok(()) + } + } + + fn write_u64(&mut self, n: u64) -> impl Future> + Send { + async move { + let bytes = n.to_le_bytes(); + self.write_all(&bytes).await?; + Ok(()) + } + } + + fn write_u128(&mut self, n: u128) -> impl Future> + Send { + async move { + let bytes = n.to_le_bytes(); + self.write_all(&bytes).await?; + Ok(()) + } + } + + fn write_i8(&mut self, n: i8) -> impl Future> + Send { + async move { + let bytes = n.to_le_bytes(); + self.write_all(&bytes).await?; + Ok(()) + } + } + + fn write_i16(&mut self, n: i16) -> impl Future> + Send { + async move { + let bytes = n.to_le_bytes(); + self.write_all(&bytes).await?; + Ok(()) + } + } + + fn write_i32(&mut self, n: i32) -> impl Future> + Send { + async move { + let bytes = n.to_le_bytes(); + self.write_all(&bytes).await?; + Ok(()) + } + } + + fn write_i64(&mut self, n: i64) -> impl Future> + Send { + async move { + let bytes = n.to_le_bytes(); + self.write_all(&bytes).await?; + Ok(()) + } + } + + fn write_i128(&mut self, n: i128) -> impl Future> + Send { + async move { + let bytes = n.to_le_bytes(); + self.write_all(&bytes).await?; + Ok(()) + } + } + + fn write_f32(&mut self, n: f32) -> impl Future> + Send { + async move { + let bytes = n.to_le_bytes(); + self.write_all(&bytes).await?; + Ok(()) + } + } + + fn write_f64(&mut self, n: f64) -> impl Future> + Send { + async move { + let bytes = n.to_le_bytes(); + self.write_all(&bytes).await?; + Ok(()) + } + } +} + +#[cfg(feature = "unstable__tokio")] +impl AsyncWrite for R { + #[inline] + fn write_all<'a>(&'a mut self, buf: &'a [u8]) -> impl Future> + Send + 'a { + tokio::io::AsyncWriteExt::write_all(self, buf) + } + + #[inline] + fn write_u8(&mut self, n: u8) -> impl Future> + Send { + tokio::io::AsyncWriteExt::write_u8(self, n) + } + + #[inline] + fn write_u16(&mut self, n: u16) -> impl Future> + Send { + tokio::io::AsyncWriteExt::write_u16_le(self, n) + } + + #[inline] + fn write_u32(&mut self, n: u32) -> impl Future> + Send { + tokio::io::AsyncWriteExt::write_u32_le(self, n) + } + + #[inline] + fn write_u64(&mut self, n: u64) -> impl Future> + Send { + tokio::io::AsyncWriteExt::write_u64_le(self, n) + } + + #[inline] + fn write_u128(&mut self, n: u128) -> impl Future> + Send { + tokio::io::AsyncWriteExt::write_u128_le(self, n) + } + + #[inline] + fn write_i8(&mut self, n: i8) -> impl Future> + Send { + tokio::io::AsyncWriteExt::write_i8(self, n) + } + + #[inline] + fn write_i16(&mut self, n: i16) -> impl Future> + Send { + tokio::io::AsyncWriteExt::write_i16_le(self, n) + } + + #[inline] + fn write_i32(&mut self, n: i32) -> impl Future> + Send { + tokio::io::AsyncWriteExt::write_i32_le(self, n) + } + + #[inline] + fn write_i64(&mut self, n: i64) -> impl Future> + Send { + tokio::io::AsyncWriteExt::write_i64_le(self, n) + } + + #[inline] + fn write_i128(&mut self, n: i128) -> impl Future> + Send { + tokio::io::AsyncWriteExt::write_i128_le(self, n) + } + + #[inline] + fn write_f32(&mut self, n: f32) -> impl Future> + Send { + tokio::io::AsyncWriteExt::write_f32_le(self, n) + } + + #[inline] + fn write_f64(&mut self, n: f64) -> impl Future> + Send { + tokio::io::AsyncWriteExt::write_f64_le(self, n) + } +} + +#[cfg(feature = "unstable__async-std")] +impl AsyncWrite for R { + #[inline] + fn write_all<'a>(&'a mut self, buf: &'a [u8]) -> impl Future> + Send + 'a { + async_std::io::WriteExt::write_all(self, buf) + } +} diff --git a/borsh/src/de/mod.rs b/borsh/src/de/mod.rs index 0abb36e3e..2d702fa96 100644 --- a/borsh/src/de/mod.rs +++ b/borsh/src/de/mod.rs @@ -1,25 +1,30 @@ -use core::marker::PhantomData; -use core::mem::MaybeUninit; +#[cfg(feature = "unstable__async")] +use core::future::Future; use core::{ convert::{TryFrom, TryInto}, - mem::size_of, + marker::PhantomData, + mem::{size_of, MaybeUninit}, }; +use async_generic::async_generic; #[cfg(feature = "bytes")] use bytes::{BufMut, BytesMut}; -use crate::__private::maybestd::{ - borrow::{Borrow, Cow, ToOwned}, - boxed::Box, - collections::{BTreeMap, BTreeSet, LinkedList, VecDeque}, - format, - string::{String, ToString}, - vec, - vec::Vec, +#[cfg(feature = "unstable__async")] +use crate::async_io::AsyncRead; +use crate::{ + __private::maybestd::{ + borrow::{Borrow, Cow, ToOwned}, + boxed::Box, + collections::{BTreeMap, BTreeSet, LinkedList, VecDeque}, + format, + string::String, + vec, + vec::Vec, + }, + error::check_zst, + io::{Error, ErrorKind, Read, Result}, }; -use crate::io::{Error, ErrorKind, Read, Result}; - -use crate::error::check_zst; mod hint; @@ -54,6 +59,7 @@ pub trait BorshDeserialize: Sized { fn try_from_reader(reader: &mut R) -> Result { let result = Self::deserialize_reader(reader)?; + let mut buf = [0u8; 1]; match reader.read_exact(&mut buf) { Err(f) if f.kind() == ErrorKind::UnexpectedEof => Ok(result), @@ -77,12 +83,54 @@ pub trait BorshDeserialize: Sized { } } +/// A data-structure that can be asynchronously de-serialized from binary format by NBOR. +#[cfg(feature = "unstable__async")] +pub trait BorshDeserializeAsync: Sized + Send { + fn deserialize_reader( + reader: &mut R, + ) -> impl Future> + Send; + + fn try_from_reader(reader: &mut R) -> impl Future> + Send { + async move { + let result = { Self::deserialize_reader(reader).await }?; + + let mut buf = [0u8; 1]; + let res = reader.read_exact(&mut buf); + let res = { res.await }; + match res { + Err(f) if f.kind() == ErrorKind::UnexpectedEof => Ok(result), + _ => Err(Error::new(ErrorKind::InvalidData, ERROR_NOT_ALL_BYTES_READ)), + } + } + } + + #[inline] + #[doc(hidden)] + fn vec_from_reader( + len: u32, + reader: &mut R, + ) -> impl Future>>> + Send { + let _ = len; + let _ = reader; + core::future::ready(Ok(None)) + } + + #[inline] + #[doc(hidden)] + fn array_from_reader( + reader: &mut R, + ) -> impl Future>> + Send { + let _ = reader; + core::future::ready(Ok(None)) + } +} + /// Additional methods offered on enums which is used by `[derive(BorshDeserialize)]`. pub trait EnumExt: BorshDeserialize { /// Deserialises given variant of an enum from the reader. /// /// This may be used to perform validation or filtering based on what - /// variant is being deserialised. + /// variant is being deserialized. /// /// ``` /// use borsh::BorshDeserialize; @@ -135,6 +183,70 @@ pub trait EnumExt: BorshDeserialize { fn deserialize_variant(reader: &mut R, tag: u8) -> Result; } +/// Additional methods offered on enums which is used by `[derive(BorshDeserializeAsync)]`. +#[cfg(feature = "unstable__async")] +pub trait EnumExtAsync: BorshDeserializeAsync { + /// Deserialises given variant of an enum from the async reader. + /// + /// This may be used to perform validation or filtering based on what + /// variant is being deserialized. + /// + /// ``` + /// # tokio_test::block_on(async { + /// use borsh::BorshDeserializeAsync; + /// use borsh::de::EnumExtAsync as _; + /// + /// /// derive is only available if borsh is built with `features = ["derive"]` + /// # #[cfg(feature = "derive")] + /// #[derive(Debug, PartialEq, Eq, BorshDeserializeAsync)] + /// enum MyEnum { + /// Zero, + /// One(u8), + /// Many(Vec) + /// } + /// + /// # #[cfg(feature = "derive")] + /// #[derive(Debug, PartialEq, Eq)] + /// struct OneOrZero(MyEnum); + /// + /// # #[cfg(feature = "derive")] + /// impl borsh::de::BorshDeserializeAsync for OneOrZero { + /// async fn deserialize_reader( + /// reader: &mut R, + /// ) -> borsh::io::Result { + /// use borsh::de::EnumExtAsync; + /// let tag = u8::deserialize_reader(reader).await?; + /// if tag == 2 { + /// Err(borsh::io::Error::new( + /// borsh::io::ErrorKind::InvalidData, + /// "MyEnum::Many not allowed here", + /// )) + /// } else { + /// MyEnum::deserialize_variant(reader, tag).await.map(Self) + /// } + /// } + /// } + /// + /// use borsh::from_reader_async; + /// let data = b"\0"; + /// # #[cfg(all(feature = "derive", any(feature = "unstable__tokio", feature = "unstable__async-std")))] + /// assert_eq!(MyEnum::Zero, from_reader_async::<_, MyEnum>(&mut &data[..]).await.unwrap()); + /// # #[cfg(all(feature = "derive", any(feature = "unstable__tokio", feature = "unstable__async-std")))] + /// assert_eq!(MyEnum::Zero, from_reader_async::<_, OneOrZero>(&mut &data[..]).await.unwrap().0); + /// + /// let data = b"\x02\0\0\0\0"; + /// # #[cfg(all(feature = "derive", any(feature = "unstable__tokio", feature = "unstable__async-std")))] + /// assert_eq!(MyEnum::Many(Vec::new()), from_reader_async::<_, MyEnum>(&mut &data[..]).await.unwrap()); + /// # #[cfg(all(feature = "derive", any(feature = "unstable__tokio", feature = "unstable__async-std")))] + /// assert!(from_reader_async::<_, OneOrZero>(&mut &data[..]).await.is_err()); + /// # }); + /// ``` + fn deserialize_variant( + reader: &mut R, + tag: u8, + ) -> impl Future> + Send; +} + fn unexpected_eof_to_unexpected_length_of_input(e: Error) -> Error { if e.kind() == ErrorKind::UnexpectedEof { Error::new(ErrorKind::InvalidData, ERROR_UNEXPECTED_LENGTH_OF_INPUT) @@ -143,18 +255,32 @@ fn unexpected_eof_to_unexpected_length_of_input(e: Error) -> Error { } } +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant +)] impl BorshDeserialize for u8 { #[inline] + #[async_generic( + async_signature[impl_fut](reader: &mut R) -> impl Future> + Send + )] fn deserialize_reader(reader: &mut R) -> Result { - let mut buf = [0u8; 1]; - reader - .read_exact(&mut buf) - .map_err(unexpected_eof_to_unexpected_length_of_input)?; - Ok(buf[0]) + if _sync { + let mut buf = [0u8; 1]; + reader + .read_exact(&mut buf) + .map_err(unexpected_eof_to_unexpected_length_of_input)?; + Ok(buf[0]) + } else { + reader.read_u8() + } } #[inline] #[doc(hidden)] + #[async_generic( + async_signature(len: u32, reader: &mut R) -> Result>> + )] fn vec_from_reader(len: u32, reader: &mut R) -> Result>> { let len: usize = len.try_into().map_err(|_| ErrorKind::InvalidData)?; // Avoid OOM by limiting the size of allocation. This makes the read @@ -168,7 +294,11 @@ impl BorshDeserialize for u8 { vec.resize(vec.len().saturating_mul(2).min(len), 0) } // TODO(mina86): Convert this to read_buf once that stabilises. - match reader.read(&mut vec.as_mut_slice()[pos..])? { + let res = { + let res = reader.read(&mut vec.as_mut_slice()[pos..]); + if _sync { res } else { res.await }? + }; + match res { 0 => { return Err(Error::new( ErrorKind::InvalidData, @@ -185,103 +315,138 @@ impl BorshDeserialize for u8 { #[inline] #[doc(hidden)] + #[async_generic( + async_signature(reader: &mut R) -> Result> + )] fn array_from_reader(reader: &mut R) -> Result> { let mut arr = [0u8; N]; - reader - .read_exact(&mut arr) + let res = reader.read_exact(&mut arr); + if _sync { res } else { res.await } .map_err(unexpected_eof_to_unexpected_length_of_input)?; Ok(Some(arr)) } } macro_rules! impl_for_integer { - ($type: ident) => { + ($type: ident, $method: ident) => { + #[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + )] impl BorshDeserialize for $type { #[inline] + #[async_generic( + async_signature[impl_fut](reader: &mut R) -> impl Future> + Send + )] fn deserialize_reader(reader: &mut R) -> Result { - let mut buf = [0u8; size_of::<$type>()]; - reader - .read_exact(&mut buf) - .map_err(unexpected_eof_to_unexpected_length_of_input)?; - let res = $type::from_le_bytes(buf.try_into().unwrap()); - Ok(res) + if _sync { + let mut buf = [0u8; size_of::<$type>()]; + reader + .read_exact(&mut buf) + .map_err(unexpected_eof_to_unexpected_length_of_input)?; + let res = $type::from_le_bytes(buf.try_into().unwrap()); + Ok(res) + } else { + reader.$method() + } } } }; } -impl_for_integer!(i8); -impl_for_integer!(i16); -impl_for_integer!(i32); -impl_for_integer!(i64); -impl_for_integer!(i128); -impl_for_integer!(u16); -impl_for_integer!(u32); -impl_for_integer!(u64); -impl_for_integer!(u128); - +impl_for_integer!(i8, read_i8); +impl_for_integer!(i16, read_i16); +impl_for_integer!(i32, read_i32); +impl_for_integer!(i64, read_i64); +impl_for_integer!(i128, read_i128); +impl_for_integer!(u16, read_u16); +impl_for_integer!(u32, read_u32); +impl_for_integer!(u64, read_u64); +impl_for_integer!(u128, read_u128); + +#[rustfmt::skip] macro_rules! impl_for_nonzero_integer { - ($type: ty) => { + ($type: ty, $repr: ty) => { + #[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + )] impl BorshDeserialize for $type { #[inline] + #[async_generic(async_signature(reader: &mut R) -> Result)] fn deserialize_reader(reader: &mut R) -> Result { - <$type>::new(BorshDeserialize::deserialize_reader(reader)?) - .ok_or_else(|| Error::new(ErrorKind::InvalidData, ERROR_INVALID_ZERO_VALUE)) + <$type>::new(if _sync { + <$repr as BorshDeserialize>::deserialize_reader(reader) + } else { + <$repr as BorshDeserializeAsync>::deserialize_reader(reader).await + }?) + .ok_or_else(|| Error::new(ErrorKind::InvalidData, ERROR_INVALID_ZERO_VALUE)) } } }; } -impl_for_nonzero_integer!(core::num::NonZeroI8); -impl_for_nonzero_integer!(core::num::NonZeroI16); -impl_for_nonzero_integer!(core::num::NonZeroI32); -impl_for_nonzero_integer!(core::num::NonZeroI64); -impl_for_nonzero_integer!(core::num::NonZeroI128); -impl_for_nonzero_integer!(core::num::NonZeroU8); -impl_for_nonzero_integer!(core::num::NonZeroU16); -impl_for_nonzero_integer!(core::num::NonZeroU32); -impl_for_nonzero_integer!(core::num::NonZeroU64); -impl_for_nonzero_integer!(core::num::NonZeroU128); -impl_for_nonzero_integer!(core::num::NonZeroUsize); - -impl BorshDeserialize for isize { - fn deserialize_reader(reader: &mut R) -> Result { - let i: i64 = BorshDeserialize::deserialize_reader(reader)?; - let i = isize::try_from(i).map_err(|_| { - Error::new( - ErrorKind::InvalidData, - ERROR_OVERFLOW_ON_MACHINE_WITH_32_BIT_ISIZE, - ) - })?; - Ok(i) - } +impl_for_nonzero_integer!(core::num::NonZeroI8, i8); +impl_for_nonzero_integer!(core::num::NonZeroI16, i16); +impl_for_nonzero_integer!(core::num::NonZeroI32, i32); +impl_for_nonzero_integer!(core::num::NonZeroI64, i64); +impl_for_nonzero_integer!(core::num::NonZeroI128, i128); +impl_for_nonzero_integer!(core::num::NonZeroIsize, isize); +impl_for_nonzero_integer!(core::num::NonZeroU8, u8); +impl_for_nonzero_integer!(core::num::NonZeroU16, u16); +impl_for_nonzero_integer!(core::num::NonZeroU32, u32); +impl_for_nonzero_integer!(core::num::NonZeroU64, u64); +impl_for_nonzero_integer!(core::num::NonZeroU128, u128); +impl_for_nonzero_integer!(core::num::NonZeroUsize, usize); + +#[rustfmt::skip] +macro_rules! impl_for_size_integer { + ($type: ty: $temp_type: ty, $msg: expr) => { + #[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + )] + impl BorshDeserialize for $type { + #[async_generic(async_signature(reader: &mut R) -> Result)] + fn deserialize_reader(reader: &mut R) -> Result { + let i = if _sync { + <$temp_type as BorshDeserialize>::deserialize_reader(reader) + } else { + <$temp_type as BorshDeserializeAsync>::deserialize_reader(reader).await + }?; + let i = + <$type>::try_from(i).map_err(|_| Error::new(ErrorKind::InvalidData, $msg))?; + Ok(i) + } + } + }; } -impl BorshDeserialize for usize { - fn deserialize_reader(reader: &mut R) -> Result { - let u: u64 = BorshDeserialize::deserialize_reader(reader)?; - let u = usize::try_from(u).map_err(|_| { - Error::new( - ErrorKind::InvalidData, - ERROR_OVERFLOW_ON_MACHINE_WITH_32_BIT_USIZE, - ) - })?; - Ok(u) - } -} +impl_for_size_integer!(isize: i64, ERROR_OVERFLOW_ON_MACHINE_WITH_32_BIT_ISIZE); +impl_for_size_integer!(usize: u64, ERROR_OVERFLOW_ON_MACHINE_WITH_32_BIT_USIZE); // Note NaNs have a portability issue. Specifically, signalling NaNs on MIPS are quiet NaNs on x86, -// and vice-versa. We disallow NaNs to avoid this issue. +// and vice versa. We disallow NaNs to avoid this issue. +#[rustfmt::skip] macro_rules! impl_for_float { - ($type: ident, $int_type: ident) => { + ($type: ident, $int_type: ident, $method: ident) => { + #[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + )] impl BorshDeserialize for $type { #[inline] + #[async_generic(async_signature(reader: &mut R) -> Result)] fn deserialize_reader(reader: &mut R) -> Result { - let mut buf = [0u8; size_of::<$type>()]; - reader - .read_exact(&mut buf) - .map_err(unexpected_eof_to_unexpected_length_of_input)?; - let res = $type::from_bits($int_type::from_le_bytes(buf.try_into().unwrap())); + let res = if _sync { + let mut buf = [0u8; size_of::<$type>()]; + reader + .read_exact(&mut buf) + .map_err(unexpected_eof_to_unexpected_length_of_input)?; + $type::from_bits($int_type::from_le_bytes(buf.try_into().unwrap())) + } else { + reader.$method().await? + }; if res.is_nan() { return Err(Error::new( ErrorKind::InvalidData, @@ -294,76 +459,131 @@ macro_rules! impl_for_float { }; } -impl_for_float!(f32, u32); -impl_for_float!(f64, u64); +impl_for_float!(f32, u32, read_f32); +impl_for_float!(f64, u64, read_f64); +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant +)] impl BorshDeserialize for bool { #[inline] + #[async_generic(async_signature(reader: &mut R) -> Result)] fn deserialize_reader(reader: &mut R) -> Result { - let b: u8 = BorshDeserialize::deserialize_reader(reader)?; - if b == 0 { - Ok(false) - } else if b == 1 { - Ok(true) + let b = if _sync { + ::deserialize_reader(reader) } else { - let msg = format!("Invalid bool representation: {}", b); - - Err(Error::new(ErrorKind::InvalidData, msg)) + ::deserialize_reader(reader).await + }?; + match b { + 0 => Ok(false), + 1 => Ok(true), + _ => Err(Error::new( + ErrorKind::InvalidData, + format!("Invalid bool representation: {}", b), + )), } } } +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + where + T: BorshDeserializeAsync, +)] impl BorshDeserialize for Option where T: BorshDeserialize, { #[inline] + #[async_generic(async_signature(reader: &mut R) -> Result)] fn deserialize_reader(reader: &mut R) -> Result { - let flag: u8 = BorshDeserialize::deserialize_reader(reader)?; - if flag == 0 { - Ok(None) - } else if flag == 1 { - Ok(Some(T::deserialize_reader(reader)?)) + let flag = if _sync { + ::deserialize_reader(reader) } else { - let msg = format!( - "Invalid Option representation: {}. The first byte must be 0 or 1", - flag - ); - - Err(Error::new(ErrorKind::InvalidData, msg)) + ::deserialize_reader(reader).await + }?; + match flag { + 0 => Ok(None), + 1 => Ok(Some({ + let res = T::deserialize_reader(reader); + if _sync { res } else { res.await }? + })), + _ => Err(Error::new( + ErrorKind::InvalidData, + format!( + "Invalid Option representation: {}. The first byte must be 0 or 1", + flag + ), + )), } } } +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + where + T: BorshDeserializeAsync, + E: BorshDeserializeAsync, +)] impl BorshDeserialize for core::result::Result where T: BorshDeserialize, E: BorshDeserialize, { #[inline] + #[async_generic(async_signature(reader: &mut R) -> Result)] fn deserialize_reader(reader: &mut R) -> Result { - let flag: u8 = BorshDeserialize::deserialize_reader(reader)?; - if flag == 0 { - Ok(Err(E::deserialize_reader(reader)?)) - } else if flag == 1 { - Ok(Ok(T::deserialize_reader(reader)?)) + let flag = if _sync { + ::deserialize_reader(reader) } else { - let msg = format!( - "Invalid Result representation: {}. The first byte must be 0 or 1", - flag - ); - - Err(Error::new(ErrorKind::InvalidData, msg)) + ::deserialize_reader(reader).await + }?; + match flag { + 0 => Ok(Err({ + let res = E::deserialize_reader(reader); + if _sync { res } else { res.await }? + })), + 1 => Ok(Ok({ + let res = T::deserialize_reader(reader); + if _sync { res } else { res.await }? + })), + _ => Err(Error::new( + ErrorKind::InvalidData, + format!( + "Invalid Result representation: {}. The first byte must be 0 or 1", + flag + ), + )), } } } +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant +)] impl BorshDeserialize for String { #[inline] + #[async_generic(async_signature(reader: &mut R) -> Result)] fn deserialize_reader(reader: &mut R) -> Result { - String::from_utf8(Vec::::deserialize_reader(reader)?).map_err(|err| { - let msg = err.to_string(); - Error::new(ErrorKind::InvalidData, msg) + String::from_utf8(if _sync { + as BorshDeserialize>::deserialize_reader(reader) + } else { + as BorshDeserializeAsync>::deserialize_reader(reader).await + }?) + .map_err(|err| { + #[cfg(feature = "std")] + { + Error::new(ErrorKind::InvalidData, err) + } + #[cfg(not(feature = "std"))] + { + use crate::__private::maybestd::string::ToString; + Error::new(ErrorKind::InvalidData, err.to_string()) + } }) } } @@ -372,49 +592,110 @@ impl BorshDeserialize for String { #[cfg(feature = "ascii")] pub mod ascii { //! - //! Module defines [BorshDeserialize] implementation for - //! some types from [ascii](::ascii) crate. - use crate::BorshDeserialize; - use crate::__private::maybestd::{string::ToString, vec::Vec}; - use crate::io::{Error, ErrorKind, Read, Result}; + //! Module defines [`BorshDeserialize`] + #![cfg_attr(feature = "unstable__async", doc = " & [`BorshDeserializeAsync`]")] + //! implementation for some types from [`ascii`] crate. + + use async_generic::async_generic; + + use super::BorshDeserialize; + #[cfg(feature = "unstable__async")] + use super::{AsyncRead, BorshDeserializeAsync}; + use crate::{ + __private::maybestd::vec::Vec, + io::{Error, ErrorKind, Read, Result}, + }; + #[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + )] impl BorshDeserialize for ascii::AsciiString { #[inline] + #[async_generic(async_signature(reader: &mut R) -> Result)] fn deserialize_reader(reader: &mut R) -> Result { - let bytes = Vec::::deserialize_reader(reader)?; - ascii::AsciiString::from_ascii(bytes) - .map_err(|err| Error::new(ErrorKind::InvalidData, err.to_string())) + let bytes = if _sync { + as BorshDeserialize>::deserialize_reader(reader) + } else { + as BorshDeserializeAsync>::deserialize_reader(reader).await + }?; + ascii::AsciiString::from_ascii(bytes).map_err(|err| { + #[cfg(feature = "std")] + { + Error::new(ErrorKind::InvalidData, err) + } + #[cfg(not(feature = "std"))] + { + use crate::__private::maybestd::string::ToString; + Error::new(ErrorKind::InvalidData, err.to_string()) + } + }) } } + #[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + )] impl BorshDeserialize for ascii::AsciiChar { #[inline] + #[async_generic(async_signature(reader: &mut R) -> Result)] fn deserialize_reader(reader: &mut R) -> Result { - let byte = u8::deserialize_reader(reader)?; - ascii::AsciiChar::from_ascii(byte) - .map_err(|err| Error::new(ErrorKind::InvalidData, err.to_string())) + let byte = if _sync { + ::deserialize_reader(reader) + } else { + ::deserialize_reader(reader).await + }?; + ascii::AsciiChar::from_ascii(byte).map_err(|err| { + #[cfg(feature = "std")] + { + Error::new(ErrorKind::InvalidData, err) + } + #[cfg(not(feature = "std"))] + { + use crate::__private::maybestd::string::ToString; + Error::new(ErrorKind::InvalidData, err.to_string()) + } + }) } } } +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + where + T: BorshDeserializeAsync, +)] impl BorshDeserialize for Vec where T: BorshDeserialize, { #[inline] + #[async_generic(async_signature(reader: &mut R) -> Result)] fn deserialize_reader(reader: &mut R) -> Result { check_zst::()?; - let len = u32::deserialize_reader(reader)?; + let len = if _sync { + ::deserialize_reader(reader) + } else { + ::deserialize_reader(reader).await + }?; if len == 0 { Ok(Vec::new()) - } else if let Some(vec_bytes) = T::vec_from_reader(len, reader)? { + } else if let Some(vec_bytes) = { + let res = T::vec_from_reader(len, reader); + if _sync { res } else { res.await }? + } { Ok(vec_bytes) } else { // TODO(16): return capacity allocation when we can safely do that. let mut result = Vec::with_capacity(hint::cautious::(len)); for _ in 0..len { - result.push(T::deserialize_reader(reader)?); + result.push({ + let res = T::deserialize_reader(reader); + if _sync { res } else { res.await }? + }); } Ok(result) } @@ -422,101 +703,183 @@ where } #[cfg(feature = "bytes")] +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant +)] impl BorshDeserialize for bytes::Bytes { #[inline] + #[async_generic(async_signature(reader: &mut R) -> Result)] fn deserialize_reader(reader: &mut R) -> Result { - let vec = >::deserialize_reader(reader)?; + let vec = if _sync { + as BorshDeserialize>::deserialize_reader(reader) + } else { + as BorshDeserializeAsync>::deserialize_reader(reader).await + }?; Ok(vec.into()) } } #[cfg(feature = "bytes")] -impl BorshDeserialize for bytes::BytesMut { +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant +)] +impl BorshDeserialize for BytesMut { #[inline] + #[async_generic(async_signature(reader: &mut R) -> Result)] fn deserialize_reader(reader: &mut R) -> Result { - let len = u32::deserialize_reader(reader)?; + let len = if _sync { + ::deserialize_reader(reader) + } else { + ::deserialize_reader(reader).await + }?; let mut out = BytesMut::with_capacity(hint::cautious::(len)); for _ in 0..len { - out.put_u8(u8::deserialize_reader(reader)?); + out.put_u8(if _sync { + ::deserialize_reader(reader) + } else { + ::deserialize_reader(reader).await + }?); } Ok(out) } } #[cfg(feature = "bson")] +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant +)] impl BorshDeserialize for bson::oid::ObjectId { #[inline] + #[async_generic(async_signature(reader: &mut R) -> Result)] fn deserialize_reader(reader: &mut R) -> Result { let mut buf = [0u8; 12]; - reader.read_exact(&mut buf)?; + { + let res = reader.read_exact(&mut buf); + if _sync { res } else { res.await }?; + } Ok(bson::oid::ObjectId::from_bytes(buf)) } } +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + where + T: ToOwned + ?Sized, + T::Owned: BorshDeserializeAsync, + for<'a> &'a T: Send, +)] impl BorshDeserialize for Cow<'_, T> where T: ToOwned + ?Sized, T::Owned: BorshDeserialize, { #[inline] + #[async_generic(async_signature(reader: &mut R) -> Result)] fn deserialize_reader(reader: &mut R) -> Result { - Ok(Cow::Owned(BorshDeserialize::deserialize_reader(reader)?)) + Ok(Cow::Owned({ + let res = T::Owned::deserialize_reader(reader); + if _sync { res } else { res.await }? + })) } } +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + where + T: BorshDeserializeAsync, +)] impl BorshDeserialize for VecDeque where T: BorshDeserialize, { #[inline] + #[async_generic(async_signature(reader: &mut R) -> Result)] fn deserialize_reader(reader: &mut R) -> Result { - let vec = >::deserialize_reader(reader)?; + let vec = { + let res = >::deserialize_reader(reader); + if _sync { res } else { res.await }? + }; Ok(vec.into()) } } +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + where + T: BorshDeserializeAsync, +)] impl BorshDeserialize for LinkedList where T: BorshDeserialize, { #[inline] + #[async_generic(async_signature(reader: &mut R) -> Result)] fn deserialize_reader(reader: &mut R) -> Result { - let vec = >::deserialize_reader(reader)?; + let vec = { + let res = >::deserialize_reader(reader); + if _sync { res } else { res.await }? + }; Ok(vec.into_iter().collect::>()) } } /// Module is available if borsh is built with `features = ["std"]` or `features = ["hashbrown"]`. /// -/// Module defines [BorshDeserialize] implementation for -/// [HashMap](std::collections::HashMap)/[HashSet](std::collections::HashSet). +/// Module defines [`BorshDeserialize`] +#[cfg_attr(feature = "unstable__async", doc = " & [`BorshDeserializeAsync`]")] +/// implementation for [`HashMap`](std::collections::HashMap)/[`HashSet`](std::collections::HashSet). #[cfg(hash_collections)] pub mod hashes { use core::hash::{BuildHasher, Hash}; - use crate::BorshDeserialize; - use crate::__private::maybestd::collections::{HashMap, HashSet}; - use crate::__private::maybestd::vec::Vec; - use crate::io::{Read, Result}; + use async_generic::async_generic; - #[cfg(feature = "de_strict_order")] - const ERROR_WRONG_ORDER_OF_KEYS: &str = "keys were not serialized in ascending order"; - use crate::error::check_zst; + use super::BorshDeserialize; + #[cfg(feature = "unstable__async")] + use super::{AsyncRead, BorshDeserializeAsync}; #[cfg(feature = "de_strict_order")] use crate::io::{Error, ErrorKind}; + use crate::{ + __private::maybestd::{ + collections::{HashMap, HashSet}, + vec::Vec, + }, + error::check_zst, + io::{Read, Result}, + }; + + #[cfg(feature = "de_strict_order")] + const ERROR_WRONG_ORDER_OF_KEYS: &str = "keys were not serialized in ascending order"; + #[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + where + T: BorshDeserializeAsync + Eq + Hash + Ord, + H: BuildHasher + Default + Send, + )] impl BorshDeserialize for HashSet where T: BorshDeserialize + Eq + Hash + Ord, H: BuildHasher + Default, { #[inline] + #[async_generic(async_signature(reader: &mut R) -> Result)] fn deserialize_reader(reader: &mut R) -> Result { // NOTE: deserialize-as-you-go approach as once was in HashSet is better in the sense // that it allows to fail early, and not allocate memory for all the elements // which may fail `cmp()` checks // NOTE: deserialize first to `Vec` is faster - let vec = >::deserialize_reader(reader)?; + let vec = { + let res = >::deserialize_reader(reader); + if _sync { res } else { res.await }? + }; #[cfg(feature = "de_strict_order")] // TODO: replace with `is_sorted` api when stabilizes https://github.com/rust-lang/rust/issues/53485 @@ -538,6 +901,14 @@ pub mod hashes { } } + #[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + where + K: BorshDeserializeAsync + Eq + Hash + Ord, + V: BorshDeserializeAsync, + H: BuildHasher + Default + Send, + )] impl BorshDeserialize for HashMap where K: BorshDeserialize + Eq + Hash + Ord, @@ -545,13 +916,17 @@ pub mod hashes { H: BuildHasher + Default, { #[inline] + #[async_generic(async_signature(reader: &mut R) -> Result)] fn deserialize_reader(reader: &mut R) -> Result { check_zst::()?; // NOTE: deserialize-as-you-go approach as once was in HashSet is better in the sense // that it allows to fail early, and not allocate memory for all the entries // which may fail `cmp()` checks // NOTE: deserialize first to `Vec<(K, V)>` is faster - let vec = >::deserialize_reader(reader)?; + let vec = { + let res = >::deserialize_reader(reader); + if _sync { res } else { res.await }? + }; #[cfg(feature = "de_strict_order")] // TODO: replace with `is_sorted` api when stabilizes https://github.com/rust-lang/rust/issues/53485 @@ -574,17 +949,27 @@ pub mod hashes { } } +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + where + T: BorshDeserializeAsync + Ord, +)] impl BorshDeserialize for BTreeSet where T: BorshDeserialize + Ord, { #[inline] + #[async_generic(async_signature(reader: &mut R) -> Result)] fn deserialize_reader(reader: &mut R) -> Result { // NOTE: deserialize-as-you-go approach as once was in HashSet is better in the sense // that it allows to fail early, and not allocate memory for all the elements // which may fail `cmp()` checks // NOTE: deserialize first to `Vec` is faster - let vec = >::deserialize_reader(reader)?; + let vec = { + let res = >::deserialize_reader(reader); + if _sync { res } else { res.await }? + }; #[cfg(feature = "de_strict_order")] // TODO: replace with `is_sorted` api when stabilizes https://github.com/rust-lang/rust/issues/53485 @@ -607,19 +992,30 @@ where } } +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + where + K: BorshDeserializeAsync + Ord, + V: BorshDeserializeAsync, +)] impl BorshDeserialize for BTreeMap where K: BorshDeserialize + Ord, V: BorshDeserialize, { #[inline] + #[async_generic(async_signature(reader: &mut R) -> Result)] fn deserialize_reader(reader: &mut R) -> Result { check_zst::()?; // NOTE: deserialize-as-you-go approach as once was in HashSet is better in the sense // that it allows to fail early, and not allocate memory for all the entries // which may fail `cmp()` checks // NOTE: deserialize first to `Vec<(K, V)>` is faster - let vec = >::deserialize_reader(reader)?; + let vec = { + let res = >::deserialize_reader(reader); + if _sync { res } else { res.await }? + }; #[cfg(feature = "de_strict_order")] // TODO: replace with `is_sorted` api when stabilizes https://github.com/rust-lang/rust/issues/53485 @@ -644,13 +1040,32 @@ where } #[cfg(feature = "std")] +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant +)] impl BorshDeserialize for std::net::SocketAddr { #[inline] + #[async_generic(async_signature(reader: &mut R) -> Result)] fn deserialize_reader(reader: &mut R) -> Result { - let kind = u8::deserialize_reader(reader)?; + let kind = if _sync { + ::deserialize_reader(reader) + } else { + ::deserialize_reader(reader).await + }?; match kind { - 0 => std::net::SocketAddrV4::deserialize_reader(reader).map(std::net::SocketAddr::V4), - 1 => std::net::SocketAddrV6::deserialize_reader(reader).map(std::net::SocketAddr::V6), + 0 => if _sync { + ::deserialize_reader(reader) + } else { + ::deserialize_reader(reader).await + } + .map(std::net::SocketAddr::V4), + 1 => if _sync { + ::deserialize_reader(reader) + } else { + ::deserialize_reader(reader).await + } + .map(std::net::SocketAddr::V6), value => Err(Error::new( ErrorKind::InvalidData, format!("Invalid SocketAddr variant: {}", value), @@ -660,21 +1075,32 @@ impl BorshDeserialize for std::net::SocketAddr { } #[cfg(feature = "std")] +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant +)] impl BorshDeserialize for std::net::IpAddr { #[inline] + #[async_generic(async_signature(reader: &mut R) -> Result)] fn deserialize_reader(reader: &mut R) -> Result { - let kind = u8::deserialize_reader(reader)?; + let kind = if _sync { + ::deserialize_reader(reader) + } else { + ::deserialize_reader(reader).await + }?; match kind { - 0u8 => { - // Deserialize an Ipv4Addr and convert it to IpAddr::V4 - let ipv4_addr = std::net::Ipv4Addr::deserialize_reader(reader)?; - Ok(std::net::IpAddr::V4(ipv4_addr)) + 0 => if _sync { + ::deserialize_reader(reader) + } else { + ::deserialize_reader(reader).await } - 1u8 => { - // Deserialize an Ipv6Addr and convert it to IpAddr::V6 - let ipv6_addr = std::net::Ipv6Addr::deserialize_reader(reader)?; - Ok(std::net::IpAddr::V6(ipv6_addr)) + .map(std::net::IpAddr::V4), + 1 => if _sync { + ::deserialize_reader(reader) + } else { + ::deserialize_reader(reader).await } + .map(std::net::IpAddr::V6), value => Err(Error::new( ErrorKind::InvalidData, format!("Invalid IpAddr variant: {}", value), @@ -684,57 +1110,106 @@ impl BorshDeserialize for std::net::IpAddr { } #[cfg(feature = "std")] +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant +)] impl BorshDeserialize for std::net::SocketAddrV4 { #[inline] + #[async_generic(async_signature(reader: &mut R) -> Result)] fn deserialize_reader(reader: &mut R) -> Result { - let ip = std::net::Ipv4Addr::deserialize_reader(reader)?; - let port = u16::deserialize_reader(reader)?; + let ip = if _sync { + ::deserialize_reader(reader) + } else { + ::deserialize_reader(reader).await + }?; + let port = if _sync { + ::deserialize_reader(reader) + } else { + ::deserialize_reader(reader).await + }?; Ok(std::net::SocketAddrV4::new(ip, port)) } } #[cfg(feature = "std")] +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant +)] impl BorshDeserialize for std::net::SocketAddrV6 { #[inline] + #[async_generic(async_signature(reader: &mut R) -> Result)] fn deserialize_reader(reader: &mut R) -> Result { - let ip = std::net::Ipv6Addr::deserialize_reader(reader)?; - let port = u16::deserialize_reader(reader)?; + let ip = if _sync { + ::deserialize_reader(reader) + } else { + ::deserialize_reader(reader).await + }?; + let port = if _sync { + ::deserialize_reader(reader) + } else { + ::deserialize_reader(reader).await + }?; Ok(std::net::SocketAddrV6::new(ip, port, 0, 0)) } } #[cfg(feature = "std")] +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant +)] impl BorshDeserialize for std::net::Ipv4Addr { #[inline] + #[async_generic(async_signature(reader: &mut R) -> Result)] fn deserialize_reader(reader: &mut R) -> Result { let mut buf = [0u8; 4]; - reader - .read_exact(&mut buf) + let res = reader.read_exact(&mut buf); + if _sync { res } else { res.await } .map_err(unexpected_eof_to_unexpected_length_of_input)?; Ok(std::net::Ipv4Addr::from(buf)) } } #[cfg(feature = "std")] +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant +)] impl BorshDeserialize for std::net::Ipv6Addr { #[inline] + #[async_generic(async_signature(reader: &mut R) -> Result)] fn deserialize_reader(reader: &mut R) -> Result { let mut buf = [0u8; 16]; - reader - .read_exact(&mut buf) + let res = reader.read_exact(&mut buf); + if _sync { res } else { res.await } .map_err(unexpected_eof_to_unexpected_length_of_input)?; Ok(std::net::Ipv6Addr::from(buf)) } } +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + where + U: Into> + Borrow, + T: ToOwned + ?Sized + Send, + T::Owned: BorshDeserializeAsync, +)] impl BorshDeserialize for Box where U: Into> + Borrow, T: ToOwned + ?Sized, T::Owned: BorshDeserialize, { + #[inline] + #[async_generic(async_signature(reader: &mut R) -> Result)] fn deserialize_reader(reader: &mut R) -> Result { - Ok(T::Owned::deserialize_reader(reader)?.into()) + Ok({ + let res = T::Owned::deserialize_reader(reader); + if _sync { res } else { res.await }?.into() + }) } } @@ -796,6 +1271,70 @@ where } } +#[cfg(feature = "unstable__async")] +impl BorshDeserializeAsync for [T; N] +where + T: BorshDeserializeAsync, +{ + #[inline] + async fn deserialize_reader(reader: &mut R) -> Result { + struct ArrayDropGuard<'r, T: BorshDeserializeAsync, const N: usize, R: AsyncRead> { + buffer: [MaybeUninit; N], + init_count: usize, + reader: &'r mut R, + } + impl<'r, T: BorshDeserializeAsync, const N: usize, R: AsyncRead> Drop + for ArrayDropGuard<'r, T, N, R> + { + fn drop(&mut self) { + let init_range = &mut self.buffer[..self.init_count]; + // SAFETY: Elements up to self.init_count have been initialized. Assumes this value + // is only incremented in `fill_buffer`, which writes the element before + // increasing the init_count. + unsafe { + core::ptr::drop_in_place(init_range as *mut _ as *mut [T]); + }; + } + } + + impl<'r, T: BorshDeserializeAsync, const N: usize, R: AsyncRead> ArrayDropGuard<'r, T, N, R> { + unsafe fn transmute_to_array(mut self) -> [T; N] { + debug_assert_eq!(self.init_count, N); + // Set init_count to 0 so that the values do not get dropped twice. + self.init_count = 0; + // SAFETY: This cast is required because `mem::transmute` does not work with + // const generics https://github.com/rust-lang/rust/issues/61956. This + // array is guaranteed to be initialized by this point. + core::ptr::read(&self.buffer as *const _ as *const [T; N]) + } + async fn fill_buffer(&mut self) -> Result<()> { + // TODO: replace with `core::array::try_from_fn` when stabilized to avoid manually + // dropping uninitialized values through the guard drop. + for elem in self.buffer.iter_mut() { + elem.write(T::deserialize_reader(self.reader).await?); + self.init_count += 1; + } + Ok(()) + } + } + + if let Some(arr) = T::array_from_reader(reader).await? { + Ok(arr) + } else { + let mut result = ArrayDropGuard { + buffer: unsafe { MaybeUninit::uninit().assume_init() }, + init_count: 0, + reader, + }; + + result.fill_buffer().await?; + + // SAFETY: The elements up to `i` have been initialized in `fill_buffer`. + Ok(unsafe { result.transmute_to_array() }) + } + } +} + #[test] fn array_deserialization_doesnt_leak() { use core::sync::atomic::{AtomicUsize, Ordering}; @@ -805,9 +1344,19 @@ fn array_deserialization_doesnt_leak() { #[allow(unused)] struct MyType(u8); + + #[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + )] impl BorshDeserialize for MyType { + #[async_generic(async_signature(reader: &mut R) -> Result)] fn deserialize_reader(reader: &mut R) -> Result { - let val = u8::deserialize_reader(reader)?; + let val = if _sync { + ::deserialize_reader(reader) + } else { + ::deserialize_reader(reader).await + }?; let v = DESERIALIZE_COUNT.fetch_add(1, Ordering::SeqCst); if v >= 7 { panic!("panic in deserialize"); @@ -843,24 +1392,42 @@ fn array_deserialization_doesnt_leak() { macro_rules! impl_tuple { (@unit $name:ty) => { + #[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + )] impl BorshDeserialize for $name { #[inline] - fn deserialize_reader(_reader: &mut R) -> Result { + #[async_generic( + async_signature[ready](_: &mut R) -> impl Future> + Send + )] + fn deserialize_reader(_: &mut R) -> Result { Ok(<$name>::default()) } } }; ($($name:ident)+) => { - impl<$($name),+> BorshDeserialize for ($($name,)+) - where $($name: BorshDeserialize,)+ - { - #[inline] - fn deserialize_reader(reader: &mut R) -> Result { - - Ok(($($name::deserialize_reader(reader)?,)+)) + #[async_generic( + #[cfg(feature = "unstable__async")] + async_variant<$($name),+> + where + $($name: BorshDeserializeAsync,)+ + )] + impl<$($name),+> BorshDeserialize for ($($name,)+) + where + $($name: BorshDeserialize,)+ + { + #[inline] + #[async_generic(async_signature(reader: &mut R) -> Result)] + fn deserialize_reader(reader: &mut R) -> Result { + Ok(if _sync { + ($(<$name as BorshDeserialize>::deserialize_reader(reader)?,)+) + } else { + ($(<$name as BorshDeserializeAsync>::deserialize_reader(reader).await?,)+) + }) + } } - } }; } @@ -889,32 +1456,50 @@ 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); macro_rules! impl_range { - ($type:ident, $make:expr, $($side:ident),*) => { + ($type:ident, $make:expr, $n: literal, $($side:ident),*) => { + #[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + where + T: BorshDeserializeAsync, + )] impl BorshDeserialize for core::ops::$type { #[inline] + #[async_generic(async_signature(reader: &mut R) -> Result)] fn deserialize_reader(reader: &mut R) -> Result { - let ($($side,)*) = <_>::deserialize_reader(reader)?; + let [$($side,)*] = { + let res = <[T; $n]>::deserialize_reader(reader); + if _sync { res } else { res.await }? + }; Ok($make) } } }; } -impl_range!(Range, start..end, start, end); -impl_range!(RangeInclusive, start..=end, start, end); -impl_range!(RangeFrom, start.., start); -impl_range!(RangeTo, ..end, end); -impl_range!(RangeToInclusive, ..=end, end); +impl_range!(Range, start..end, 2, start, end); +impl_range!(RangeInclusive, start..=end, 2, start, end); +impl_range!(RangeFrom, start.., 1, start); +impl_range!(RangeTo, ..end, 1, end); +impl_range!(RangeToInclusive, ..=end, 1, end); /// Module is available if borsh is built with `features = ["rc"]`. #[cfg(feature = "rc")] pub mod rc { //! - //! Module defines [BorshDeserialize] implementation for - //! [alloc::rc::Rc](std::rc::Rc) and [alloc::sync::Arc](std::sync::Arc). - use crate::__private::maybestd::{boxed::Box, rc::Rc, sync::Arc}; - use crate::io::{Read, Result}; - use crate::BorshDeserialize; + //! Module defines [`BorshDeserialize`] + #![cfg_attr(feature = "unstable__async", doc = " & [`BorshDeserializeAsync`]")] + //! implementation for [`alloc::rc::Rc`](Rc) and [`alloc::sync::Arc`](Arc). + + use async_generic::async_generic; + + use super::BorshDeserialize; + #[cfg(feature = "unstable__async")] + use super::{AsyncRead, BorshDeserializeAsync}; + use crate::{ + __private::maybestd::{boxed::Box, rc::Rc, sync::Arc}, + io::{Read, Result}, + }; /// This impl requires the [`"rc"`] Cargo feature of borsh. /// @@ -925,8 +1510,9 @@ pub mod rc { where Box: BorshDeserialize, { + #[inline] fn deserialize_reader(reader: &mut R) -> Result { - Ok(Box::::deserialize_reader(reader)?.into()) + Ok(>::deserialize_reader(reader)?.into()) } } @@ -935,37 +1521,75 @@ pub mod rc { /// Deserializing a data structure containing `Arc` will not attempt to /// deduplicate `Arc` references to the same data. Every deserialized `Arc` /// will end up with a strong count of 1. + #[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + where + Box: BorshDeserializeAsync, + Self: Send, + )] impl BorshDeserialize for Arc where Box: BorshDeserialize, { + #[inline] + #[async_generic(async_signature(reader: &mut R) -> Result)] fn deserialize_reader(reader: &mut R) -> Result { - Ok(Box::::deserialize_reader(reader)?.into()) + Ok({ + let res = >::deserialize_reader(reader); + if _sync { res } else { res.await }?.into() + }) } } } +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant +)] impl BorshDeserialize for PhantomData { + #[inline] + #[async_generic( + async_signature[ready](_: &mut R) -> impl Future> + Send + )] fn deserialize_reader(_: &mut R) -> Result { Ok(PhantomData) } } +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + where + T: BorshDeserializeAsync, +)] impl BorshDeserialize for core::cell::Cell where - T: BorshDeserialize + Copy, + T: BorshDeserialize, { + #[inline] + #[async_generic(async_signature(reader: &mut R) -> Result)] fn deserialize_reader(reader: &mut R) -> Result { - ::deserialize_reader(reader).map(core::cell::Cell::new) + let res = T::deserialize_reader(reader); + if _sync { res } else { res.await }.map(core::cell::Cell::new) } } +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + where + T: BorshDeserializeAsync, +)] impl BorshDeserialize for core::cell::RefCell where T: BorshDeserialize, { + #[inline] + #[async_generic(async_signature(reader: &mut R) -> Result)] fn deserialize_reader(reader: &mut R) -> Result { - ::deserialize_reader(reader).map(core::cell::RefCell::new) + let res = T::deserialize_reader(reader); + if _sync { res } else { res.await }.map(core::cell::RefCell::new) } } @@ -1001,10 +1625,7 @@ pub fn from_slice(v: &[u8]) -> Result { let mut v_mut = v; let object = T::deserialize(&mut v_mut)?; if !v_mut.is_empty() { - return Err(Error::new( - ErrorKind::InvalidData, - crate::de::ERROR_NOT_ALL_BYTES_READ, - )); + return Err(Error::new(ErrorKind::InvalidData, ERROR_NOT_ALL_BYTES_READ)); } Ok(object) } @@ -1031,11 +1652,10 @@ pub fn from_slice(v: &[u8]) -> Result { /// # #[cfg(feature = "derive")] /// assert_eq!(original, decoded); /// ``` +#[async_generic( + #[cfg(feature = "unstable__async")] + async_signature[impl_fut]<'a, R: AsyncRead, T: BorshDeserializeAsync + 'a>(reader: &'a mut R) -> impl Future> + Send + 'a +)] pub fn from_reader(reader: &mut R) -> Result { - let result = T::deserialize_reader(reader)?; - let mut buf = [0u8; 1]; - match reader.read_exact(&mut buf) { - Err(f) if f.kind() == ErrorKind::UnexpectedEof => Ok(result), - _ => Err(Error::new(ErrorKind::InvalidData, ERROR_NOT_ALL_BYTES_READ)), - } + T::try_from_reader(reader) } diff --git a/borsh/src/error.rs b/borsh/src/error.rs index 9afc88c09..615ff6edc 100644 --- a/borsh/src/error.rs +++ b/borsh/src/error.rs @@ -1,5 +1,7 @@ -use crate::io::{Error, ErrorKind, Result}; use core::mem::size_of; + +use crate::io::{Error, ErrorKind, Result}; + pub const ERROR_ZST_FORBIDDEN: &str = "Collections of zero-sized types are not allowed due to deny-of-service concerns on deserialization."; pub(crate) fn check_zst() -> Result<()> { diff --git a/borsh/src/generate_schema_schema.rs b/borsh/src/generate_schema_schema.rs index 647816318..f2baaa98c 100644 --- a/borsh/src/generate_schema_schema.rs +++ b/borsh/src/generate_schema_schema.rs @@ -1,9 +1,9 @@ //! Generate `BorshSchemaCointainer` for `BorshSchemaContainer` and save it into a file. #![cfg_attr(not(feature = "std"), no_std)] +use std::{fs::File, io::Write}; + use borsh::schema_container_of; -use std::fs::File; -use std::io::Write; fn main() { let container = schema_container_of::(); diff --git a/borsh/src/lib.rs b/borsh/src/lib.rs index ba4ce6501..18a4250a1 100644 --- a/borsh/src/lib.rs +++ b/borsh/src/lib.rs @@ -4,17 +4,21 @@ #[cfg(not(feature = "std"))] extern crate alloc; -#[doc = include_str!("../docs/rustdoc_include/borsh_schema.md")] -#[cfg(feature = "unstable__schema")] -pub use borsh_derive::BorshSchema; - #[doc = include_str!("../docs/rustdoc_include/borsh_deserialize.md")] #[cfg(feature = "derive")] pub use borsh_derive::BorshDeserialize; - +// TODO: add docs +#[cfg(all(feature = "derive", feature = "unstable__async"))] +pub use borsh_derive::BorshDeserializeAsync; +#[doc = include_str!("../docs/rustdoc_include/borsh_schema.md")] +#[cfg(feature = "unstable__schema")] +pub use borsh_derive::BorshSchema; #[doc = include_str!("../docs/rustdoc_include/borsh_serialize.md")] #[cfg(feature = "derive")] pub use borsh_derive::BorshSerialize; +// TODO: add docs +#[cfg(all(feature = "derive", feature = "unstable__async"))] +pub use borsh_derive::BorshSerializeAsync; pub mod de; @@ -26,25 +30,38 @@ pub mod schema; pub(crate) mod schema_helpers; pub mod ser; -pub use de::BorshDeserialize; -pub use de::{from_reader, from_slice}; +pub use de::{from_reader, from_slice, BorshDeserialize}; +#[cfg(feature = "unstable__async")] +pub use de::{from_reader_async, BorshDeserializeAsync}; #[cfg(feature = "unstable__schema")] pub use schema::BorshSchema; #[cfg(feature = "unstable__schema")] pub use schema_helpers::{ max_serialized_size, schema_container_of, try_from_slice_with_schema, try_to_vec_with_schema, }; -pub use ser::helpers::{object_length, to_vec, to_writer}; -pub use ser::BorshSerialize; +#[cfg(feature = "unstable__async")] +pub use ser::{helpers::to_writer_async, BorshSerializeAsync}; +pub use ser::{ + helpers::{object_length, to_vec, to_writer}, + BorshSerialize, +}; pub mod error; #[cfg(all(feature = "std", feature = "hashbrown"))] compile_error!("feature \"std\" and feature \"hashbrown\" don't make sense at the same time"); +#[cfg(all(feature = "unstable__tokio", feature = "unstable__async-std"))] +compile_error!( + "Cannot enable both `unstable__tokio` and `unstable__async-std` features at the same time" +); + #[cfg(feature = "std")] use std::io as io_impl; +#[cfg(feature = "unstable__async")] +pub mod async_io; #[cfg(not(feature = "std"))] mod nostd_io; + #[cfg(not(feature = "std"))] use nostd_io as io_impl; @@ -66,19 +83,18 @@ pub mod __private { #[cfg(feature = "std")] pub mod maybestd { pub use std::{borrow, boxed, collections, format, string, vec}; - #[cfg(feature = "rc")] pub use std::{rc, sync}; } #[cfg(not(feature = "std"))] pub mod maybestd { pub use alloc::{borrow, boxed, format, string, vec}; - #[cfg(feature = "rc")] pub use alloc::{rc, sync}; pub mod collections { pub use alloc::collections::{btree_map, BTreeMap, BTreeSet, LinkedList, VecDeque}; + #[cfg(feature = "hashbrown")] pub use hashbrown::*; } diff --git a/borsh/src/nostd_io.rs b/borsh/src/nostd_io.rs index 52061b817..ae87cd536 100644 --- a/borsh/src/nostd_io.rs +++ b/borsh/src/nostd_io.rs @@ -1,8 +1,9 @@ //! Taken from https://github.com/bbqsrc/bare-io (with adjustments) -use crate::__private::maybestd::string::String; use core::{convert::From, fmt, result}; +use crate::__private::maybestd::borrow::Cow; + /// A specialized [`Result`] type for I/O operations. /// /// This type is broadly used across [`std::io`] for any operation which may @@ -67,7 +68,7 @@ enum Repr { #[derive(Debug)] struct Custom { kind: ErrorKind, - error: String, + error: Cow<'static, str>, } /// A list specifying general categories of I/O error. @@ -226,14 +227,15 @@ impl Error { /// // errors can also be created from other errors /// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error); /// ``` - pub fn new>(kind: ErrorKind, error: T) -> Error { - Self::_new(kind, error.into()) - } - - fn _new(kind: ErrorKind, error: String) -> Error { - Error { - repr: Repr::Custom(Custom { kind, error }), + #[inline] + pub fn new>>(kind: ErrorKind, error: T) -> Error { + fn new(kind: ErrorKind, error: Cow<'static, str>) -> Error { + Error { + repr: Repr::Custom(Custom { kind, error }), + } } + + new(kind, error.into()) } /// Returns a reference to the inner error wrapped by this error (if any). @@ -297,7 +299,7 @@ impl Error { /// print_error(Error::new(ErrorKind::Other, "oh no!")); /// } /// ``` - pub fn into_inner(self) -> Option { + pub fn into_inner(self) -> Option> { match self.repr { Repr::Simple(..) => None, Repr::Custom(c) => Some(c.error), @@ -649,7 +651,7 @@ impl Write for &mut [u8] { #[inline] fn write(&mut self, data: &[u8]) -> Result { let amt = core::cmp::min(data.len(), self.len()); - let (a, b) = core::mem::replace(self, &mut []).split_at_mut(amt); + let (a, b) = core::mem::take(self).split_at_mut(amt); a.copy_from_slice(&data[..amt]); *self = b; Ok(amt) diff --git a/borsh/src/schema.rs b/borsh/src/schema.rs index 49bee3824..7d07546b5 100644 --- a/borsh/src/schema.rs +++ b/borsh/src/schema.rs @@ -6,27 +6,30 @@ //! on Rust side. //! //! The important components are: `BorshSchema` trait, `Definition` and `Declaration` types, and `BorshSchemaContainer` struct. -//! * `BorshSchema` trait allows any type that implements it to be self-descriptive, i.e. generate it's own schema; +//! * `BorshSchema` trait allows any type that implements it to be self-descriptive, i.e. generate its own schema; //! * `Declaration` is used to describe the type identifier, e.g. `HashMap`; //! * `Definition` is used to describe the structure of the type; //! * `BorshSchemaContainer` is used to store all declarations and definitions that are needed to work with a single type. #![allow(dead_code)] // Unclear why rust check complains on fields of `Definition` variants. -use crate as borsh; // For `#[derive(BorshSerialize, BorshDeserialize)]`. -use crate::__private::maybestd::{ - borrow, - boxed::Box, - collections::{btree_map::Entry, BTreeMap, BTreeSet, LinkedList, VecDeque}, - format, - string::{String, ToString}, - vec, - vec::Vec, + +use core::{borrow::Borrow, cmp::Ord, marker::PhantomData}; + +use crate as borsh; +// For `#[derive(BorshSerialize, BorshDeserialize, BorshSchema)]`. +use crate::{ + __private::maybestd::{ + borrow, + boxed::Box, + collections::{btree_map::Entry, BTreeMap, BTreeSet, LinkedList, VecDeque}, + format, + string::{String, ToString}, + vec, + vec::Vec, + }, + io::{Read, Result as IOResult, Write}, + BorshDeserialize, BorshSchema as BorshSchemaMacro, BorshSerialize, }; -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; @@ -350,11 +353,11 @@ pub mod rc { //! //! Module defines [BorshSchema] implementation for //! [alloc::rc::Rc](std::rc::Rc) and [alloc::sync::Arc](std::sync::Arc). - use crate::BorshSchema; - use super::{Declaration, Definition}; - use crate::__private::maybestd::collections::BTreeMap; - use crate::__private::maybestd::{rc::Rc, sync::Arc}; + use crate::{ + BorshSchema, + __private::maybestd::{collections::BTreeMap, rc::Rc, sync::Arc}, + }; impl BorshSchema for Rc where @@ -487,10 +490,8 @@ pub mod ascii { //! //! Module defines [BorshSchema] implementation for //! some types from [ascii](::ascii) crate. - use crate::BorshSchema; - use super::{add_definition, Declaration, Definition}; - use crate::__private::maybestd::collections::BTreeMap; + use crate::{BorshSchema, __private::maybestd::collections::BTreeMap}; impl BorshSchema for ascii::AsciiString { #[inline] @@ -575,7 +576,6 @@ where T: BorshSchema, { fn add_definitions_recursively(definitions: &mut BTreeMap) { - use core::convert::TryFrom; let length = u64::try_from(N).unwrap(); let definition = Definition::Sequence { length_width: Definition::ARRAY_LENGTH_WIDTH, @@ -687,15 +687,15 @@ where /// [HashMap](std::collections::HashMap)/[HashSet](std::collections::HashSet). #[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; + use super::{add_definition, Declaration, Definition}; + use crate::{ + BorshSchema, + __private::maybestd::collections::{BTreeMap, HashMap, HashSet}, + }; + // S is not serialized, so we ignore it in schema too // forcing S to be BorshSchema forces to define Definition // which must be empty, but if not - it will fail diff --git a/borsh/src/schema/container_ext.rs b/borsh/src/schema/container_ext.rs index ba1f95982..e348a9e09 100644 --- a/borsh/src/schema/container_ext.rs +++ b/borsh/src/schema/container_ext.rs @@ -1,8 +1,8 @@ -use super::{BorshSchemaContainer, Declaration, Definition, Fields}; - pub use max_size::Error as SchemaMaxSerializedSizeError; use max_size::{is_zero_size, ZeroSizeError}; pub use validate::Error as SchemaContainerValidateError; +use super::{BorshSchemaContainer, Declaration, Definition, Fields}; + mod max_size; mod validate; diff --git a/borsh/src/schema/container_ext/max_size.rs b/borsh/src/schema/container_ext/max_size.rs index 193f3be1e..3be5d3936 100644 --- a/borsh/src/schema/container_ext/max_size.rs +++ b/borsh/src/schema/container_ext/max_size.rs @@ -1,8 +1,8 @@ +use core::num::NonZeroUsize; + use super::{BorshSchemaContainer, Declaration, Definition, Fields}; use crate::__private::maybestd::{string::ToString, vec::Vec}; -use core::num::NonZeroUsize; - /// NonZeroUsize of value one. // TODO: Replace usage by NonZeroUsize::MIN once MSRV is 1.70+. const ONE: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(1) }; @@ -13,7 +13,7 @@ impl BorshSchemaContainer { /// Even when if returned upper bound is correct, the theoretical value may be /// *much* larger than any practical length. For example, maximum encoded /// length of `String` is 4 GiB while in practice one may encounter strings of - /// at most dozen of characters. + /// at most a dozen of characters. /// /// # Example /// @@ -66,8 +66,6 @@ fn max_serialized_size_impl<'a>( schema: &'a BorshSchemaContainer, stack: &mut Vec<&'a str>, ) -> Result { - use core::convert::TryFrom; - /// Maximum number of elements in a vector or length of a string which can /// be serialised. const MAX_LEN: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(u32::MAX as usize) }; @@ -263,7 +261,6 @@ fn is_zero_size_impl<'a>( #[cfg(test)] mod tests { use super::*; - // this is not integration test module, so can use __private for ease of imports; // it cannot be made integration, as it tests `is_zero_size` function, chosen to be non-pub use crate::__private::maybestd::{boxed::Box, string::ToString}; diff --git a/borsh/src/schema/container_ext/validate.rs b/borsh/src/schema/container_ext/validate.rs index 6bd2738fb..e9798e75c 100644 --- a/borsh/src/schema/container_ext/validate.rs +++ b/borsh/src/schema/container_ext/validate.rs @@ -1,5 +1,4 @@ -use super::{is_zero_size, ZeroSizeError}; -use super::{BorshSchemaContainer, Declaration, Definition, Fields}; +use super::{is_zero_size, BorshSchemaContainer, Declaration, Definition, Fields, ZeroSizeError}; use crate::__private::maybestd::{string::ToString, vec::Vec}; impl BorshSchemaContainer { diff --git a/borsh/src/schema_helpers.rs b/borsh/src/schema_helpers.rs index 422c36138..7cacabca4 100644 --- a/borsh/src/schema_helpers.rs +++ b/borsh/src/schema_helpers.rs @@ -1,8 +1,10 @@ -use crate::__private::maybestd::vec::Vec; -use crate::from_slice; -use crate::io::{Error, ErrorKind, Result}; -use crate::schema::{BorshSchemaContainer, SchemaMaxSerializedSizeError}; -use crate::{BorshDeserialize, BorshSchema, BorshSerialize}; +use crate::{ + __private::maybestd::vec::Vec, + from_slice, + io::{Error, ErrorKind, Result}, + schema::{BorshSchemaContainer, SchemaMaxSerializedSizeError}, + BorshDeserialize, BorshSchema, BorshSerialize, +}; /// Deserialize this instance from a slice of bytes, but assume that at the beginning we have /// bytes describing the schema of the type. We deserialize this schema and verify that it is diff --git a/borsh/src/ser/helpers.rs b/borsh/src/ser/helpers.rs index da4da27da..58ed90d32 100644 --- a/borsh/src/ser/helpers.rs +++ b/borsh/src/ser/helpers.rs @@ -1,6 +1,12 @@ -use crate::BorshSerialize; -use crate::__private::maybestd::vec::Vec; -use crate::io::{ErrorKind, Result, Write}; +use async_generic::async_generic; + +#[cfg(feature = "unstable__async")] +use crate::{async_io::AsyncWrite, BorshSerializeAsync}; +use crate::{ + BorshSerialize, + __private::maybestd::vec::Vec, + io::{ErrorKind, Result, Write}, +}; pub(super) const DEFAULT_SERIALIZER_CAPACITY: usize = 1024; @@ -22,17 +28,29 @@ where /// Serializes an object directly into a `Writer`. /// # Example /// -/// ``` -/// # #[cfg(feature = "std")] -/// let stderr = std::io::stderr(); -/// # #[cfg(feature = "std")] -/// assert_eq!((), borsh::to_writer(&stderr, "hello_0x0a").unwrap()); -/// ``` +#[async_generic( + /// ``` + /// # #[cfg(feature = "std")] + /// let stderr = std::io::stderr(); + /// # #[cfg(feature = "std")] + /// assert_eq!((), borsh::to_writer(&stderr, "hello_0x0a").unwrap()); + /// ``` + sync_signature; + #[cfg(feature = "unstable__async")] + async_signature(mut writer: W, value: &T) -> Result<()> + where + T: BorshSerializeAsync + ?Sized, +)] pub fn to_writer(mut writer: W, value: &T) -> Result<()> where T: BorshSerialize + ?Sized, { - value.serialize(&mut writer) + let res = value.serialize(&mut writer); + if _sync { + res + } else { + res.await + } } /// Serializes an object without allocation to compute and return its length @@ -47,7 +65,7 @@ where /// struct A { /// tag: String, /// value: u64, -/// }; +/// } /// /// # #[cfg(feature = "derive")] /// let a = A { tag: "hello".to_owned(), value: 42 }; diff --git a/borsh/src/ser/mod.rs b/borsh/src/ser/mod.rs index b7da5ebd7..72818a58f 100644 --- a/borsh/src/ser/mod.rs +++ b/borsh/src/ser/mod.rs @@ -1,15 +1,22 @@ -use core::convert::TryFrom; -use core::marker::PhantomData; - -use crate::__private::maybestd::{ - borrow::{Cow, ToOwned}, - boxed::Box, - collections::{BTreeMap, BTreeSet, LinkedList, VecDeque}, - string::String, - vec::Vec, +#[cfg(feature = "unstable__async")] +use core::future::Future; +use core::{convert::TryFrom, marker::PhantomData}; + +use async_generic::async_generic; + +#[cfg(feature = "unstable__async")] +use crate::async_io::AsyncWrite; +use crate::{ + __private::maybestd::{ + borrow::{Cow, ToOwned}, + boxed::Box, + collections::{BTreeMap, BTreeSet, LinkedList, VecDeque}, + string::String, + vec::Vec, + }, + error::check_zst, + io::{Error, ErrorKind, Result, Write}, }; -use crate::error::check_zst; -use crate::io::{Error, ErrorKind, Result, Write}; pub(crate) mod helpers; @@ -27,7 +34,6 @@ const FLOAT_NAN_ERR: &str = "For portability reasons we do not allow to serializ /// value: String, /// } /// -/// /// # #[cfg(feature = "derive")] /// let x = MyBorshSerializableStruct { value: "hello".to_owned() }; /// let mut buffer: Vec = Vec::new(); @@ -62,10 +68,79 @@ pub trait BorshSerialize { } } +/// A data-structure that can be serialized into binary format by NBOR. +/// +/// ``` +/// # tokio_test::block_on(async { +/// use borsh::BorshSerializeAsync; +/// # #[cfg(all(feature = "derive", feature = "unstable__tokio"))] +/// # use std::io; +/// # #[cfg(all(feature = "derive", feature = "unstable__async-std"))] +/// # use async_std::io; +/// # #[cfg(all(feature = "derive", any(feature = "unstable__tokio", feature = "unstable__async-std")))] +/// use io::Cursor; +/// +/// /// derive is only available if borsh is built with `features = ["derive"]` +/// # #[cfg(feature = "derive")] +/// #[derive(BorshSerializeAsync)] +/// struct MyBorshSerializableStruct { +/// value: String, +/// } +/// +/// # #[cfg(feature = "derive")] +/// let x = MyBorshSerializableStruct { value: "hello".to_owned() }; +/// let mut buffer: Vec = Vec::new(); +/// # #[cfg(all(feature = "derive", any(feature = "unstable__tokio", feature = "unstable__async-std")))] +/// x.serialize(&mut buffer).await.unwrap(); +/// # #[cfg(all(feature = "derive", any(feature = "unstable__tokio", feature = "unstable__async-std")))] +/// let single_serialized_buffer_len = buffer.len(); +/// +/// # #[cfg(all(feature = "derive", any(feature = "unstable__tokio", feature = "unstable__async-std")))] +/// x.serialize(&mut buffer).await.unwrap(); +/// # #[cfg(all(feature = "derive", any(feature = "unstable__tokio", feature = "unstable__async-std")))] +/// assert_eq!(buffer.len(), single_serialized_buffer_len * 2); +/// +/// # #[cfg(all(feature = "derive", any(feature = "unstable__tokio", feature = "unstable__async-std")))] +/// let mut buffer: Cursor> = Cursor::new(vec![0; 1024 + single_serialized_buffer_len]); +/// # #[cfg(all(feature = "derive", any(feature = "unstable__tokio", feature = "unstable__async-std")))] +/// buffer.set_position(1024); +/// # #[cfg(all(feature = "derive", any(feature = "unstable__tokio", feature = "unstable__async-std")))] +/// x.serialize(&mut buffer).await.unwrap(); +/// # }) +/// ``` +#[cfg(feature = "unstable__async")] +pub trait BorshSerializeAsync: Sync { + fn serialize<'a, W: AsyncWrite>( + &'a self, + writer: &'a mut W, + ) -> impl Future> + Send + 'a; + + #[inline] + #[doc(hidden)] + fn u8_slice(slice: &[Self]) -> Option<&[u8]> + where + Self: Sized, + { + let _ = slice; + None + } +} + +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant(copy_sync) +)] impl BorshSerialize for u8 { #[inline] + #[async_generic( + async_signature[impl_fut]<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> impl Future> + Send + 'a + )] fn serialize(&self, writer: &mut W) -> Result<()> { - writer.write_all(core::slice::from_ref(self)) + if _sync { + writer.write_all(core::slice::from_ref(self)) + } else { + writer.write_u8(*self) + } } #[inline] @@ -75,135 +150,254 @@ impl BorshSerialize for u8 { } macro_rules! impl_for_integer { - ($type: ident) => { + ($type: ident, $method: ident) => { + #[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + )] impl BorshSerialize for $type { #[inline] + #[async_generic( + async_signature[impl_fut]<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> impl Future> + Send + 'a + )] fn serialize(&self, writer: &mut W) -> Result<()> { - let bytes = self.to_le_bytes(); - writer.write_all(&bytes) + if _sync { + let bytes = self.to_le_bytes(); + writer.write_all(&bytes) + } else { + writer.$method(*self) + } } } }; } -impl_for_integer!(i8); -impl_for_integer!(i16); -impl_for_integer!(i32); -impl_for_integer!(i64); -impl_for_integer!(i128); -impl_for_integer!(u16); -impl_for_integer!(u32); -impl_for_integer!(u64); -impl_for_integer!(u128); +impl_for_integer!(i8, write_i8); +impl_for_integer!(i16, write_i16); +impl_for_integer!(i32, write_i32); +impl_for_integer!(i64, write_i64); +impl_for_integer!(i128, write_i128); +impl_for_integer!(u16, write_u16); +impl_for_integer!(u32, write_u32); +impl_for_integer!(u64, write_u64); +impl_for_integer!(u128, write_u128); macro_rules! impl_for_nonzero_integer { - ($type: ty) => { + ($type: ty, $method: ident $(, $repr: ty)?) => { + #[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + )] impl BorshSerialize for $type { #[inline] + #[async_generic( + async_signature[impl_fut]<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> impl Future> + Send + 'a + )] fn serialize(&self, writer: &mut W) -> Result<()> { - BorshSerialize::serialize(&self.get(), writer) + if _sync { + BorshSerialize::serialize(&self.get(), writer) + } else { + let value = self.get(); + writer.$method(value $(as $repr)?) + } } } }; } -impl_for_nonzero_integer!(core::num::NonZeroI8); -impl_for_nonzero_integer!(core::num::NonZeroI16); -impl_for_nonzero_integer!(core::num::NonZeroI32); -impl_for_nonzero_integer!(core::num::NonZeroI64); -impl_for_nonzero_integer!(core::num::NonZeroI128); -impl_for_nonzero_integer!(core::num::NonZeroU8); -impl_for_nonzero_integer!(core::num::NonZeroU16); -impl_for_nonzero_integer!(core::num::NonZeroU32); -impl_for_nonzero_integer!(core::num::NonZeroU64); -impl_for_nonzero_integer!(core::num::NonZeroU128); -impl_for_nonzero_integer!(core::num::NonZeroUsize); - -impl BorshSerialize for isize { - fn serialize(&self, writer: &mut W) -> Result<()> { - BorshSerialize::serialize(&(*self as i64), writer) - } +impl_for_nonzero_integer!(core::num::NonZeroI8, write_i8); +impl_for_nonzero_integer!(core::num::NonZeroI16, write_i16); +impl_for_nonzero_integer!(core::num::NonZeroI32, write_i32); +impl_for_nonzero_integer!(core::num::NonZeroI64, write_i64); +impl_for_nonzero_integer!(core::num::NonZeroI128, write_i128); +impl_for_nonzero_integer!(core::num::NonZeroIsize, write_i64, i64); +impl_for_nonzero_integer!(core::num::NonZeroU8, write_u8); +impl_for_nonzero_integer!(core::num::NonZeroU16, write_u16); +impl_for_nonzero_integer!(core::num::NonZeroU32, write_u32); +impl_for_nonzero_integer!(core::num::NonZeroU64, write_u64); +impl_for_nonzero_integer!(core::num::NonZeroU128, write_u128); +impl_for_nonzero_integer!(core::num::NonZeroUsize, write_u64, u64); + +macro_rules! impl_for_size_integer { + ($type:ty: $repr:ty, $method: ident) => { + #[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + )] + impl BorshSerialize for $type { + #[inline] + #[async_generic( + async_signature[impl_fut]<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> impl Future> + Send + 'a + )] + fn serialize(&self, writer: &mut W) -> Result<()> { + if _sync { + BorshSerialize::serialize(&(*self as $repr), writer) + } else { + let value = *self as $repr; + writer.$method(value) + } + } + } + }; } -impl BorshSerialize for usize { - fn serialize(&self, writer: &mut W) -> Result<()> { - BorshSerialize::serialize(&(*self as u64), writer) - } -} +impl_for_size_integer!(usize: u64, write_u64); +impl_for_size_integer!(isize: i64, write_i64); // Note NaNs have a portability issue. Specifically, signalling NaNs on MIPS are quiet NaNs on x86, -// and vice-versa. We disallow NaNs to avoid this issue. +// and vice versa. We disallow NaNs to avoid this issue. macro_rules! impl_for_float { - ($type: ident) => { + ($type: ident, $method: ident) => { + #[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + )] impl BorshSerialize for $type { #[inline] + #[async_generic(async_signature<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> Result<()>)] fn serialize(&self, writer: &mut W) -> Result<()> { if self.is_nan() { return Err(Error::new(ErrorKind::InvalidData, FLOAT_NAN_ERR)); } - writer.write_all(&self.to_bits().to_le_bytes()) + if _sync{ + let bytes = self.to_bits().to_le_bytes(); + writer.write_all(&bytes) + } else { + writer.$method(*self).await + } } } }; } -impl_for_float!(f32); -impl_for_float!(f64); +impl_for_float!(f32, write_f32); +impl_for_float!(f64, write_f64); +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant +)] impl BorshSerialize for bool { #[inline] + #[async_generic( + async_signature[impl_fut]<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> impl Future> + Send + 'a + )] fn serialize(&self, writer: &mut W) -> Result<()> { - (u8::from(*self)).serialize(writer) + let byte = u8::from(*self); + if _sync { + BorshSerialize::serialize(&byte, writer) + } else { + writer.write_u8(byte) + } } } +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + where + T: BorshSerializeAsync, +)] impl BorshSerialize for Option where T: BorshSerialize, { #[inline] + #[async_generic(async_signature<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> Result<()>)] fn serialize(&self, writer: &mut W) -> Result<()> { match self { - None => 0u8.serialize(writer), + None => { + if _sync { + BorshSerialize::serialize(&0u8, writer) + } else { + BorshSerializeAsync::serialize(&0u8, writer).await + } + } Some(value) => { - 1u8.serialize(writer)?; - value.serialize(writer) + if _sync { + BorshSerialize::serialize(&1u8, writer)?; + BorshSerialize::serialize(value, writer) + } else { + BorshSerializeAsync::serialize(&1u8, writer).await?; + BorshSerializeAsync::serialize(value, writer).await + } } } } } +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + where + T: BorshSerializeAsync, + E: BorshSerializeAsync, +)] impl BorshSerialize for core::result::Result where T: BorshSerialize, E: BorshSerialize, { #[inline] + #[async_generic(async_signature<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> Result<()>)] fn serialize(&self, writer: &mut W) -> Result<()> { match self { Err(e) => { - 0u8.serialize(writer)?; - e.serialize(writer) + if _sync { + BorshSerialize::serialize(&0u8, writer)?; + BorshSerialize::serialize(e, writer) + } else { + BorshSerializeAsync::serialize(&0u8, writer).await?; + BorshSerializeAsync::serialize(e, writer).await + } } Ok(v) => { - 1u8.serialize(writer)?; - v.serialize(writer) + if _sync { + BorshSerialize::serialize(&1u8, writer)?; + BorshSerialize::serialize(v, writer) + } else { + BorshSerializeAsync::serialize(&1u8, writer).await?; + BorshSerializeAsync::serialize(v, writer).await + } } } } } +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant +)] impl BorshSerialize for str { #[inline] + #[async_generic( + async_signature[impl_fut]<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> impl Future> + Send + 'a + )] fn serialize(&self, writer: &mut W) -> Result<()> { - self.as_bytes().serialize(writer) + let bytes = self.as_bytes(); + if _sync { + BorshSerialize::serialize(bytes, writer) + } else { + BorshSerializeAsync::serialize(bytes, writer) + } } } +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant +)] impl BorshSerialize for String { #[inline] + #[async_generic( + async_signature[impl_fut]<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> impl Future> + Send + 'a + )] fn serialize(&self, writer: &mut W) -> Result<()> { - self.as_bytes().serialize(writer) + if _sync { + BorshSerialize::serialize(&**self, writer) + } else { + BorshSerializeAsync::serialize(&**self, writer) + } } } @@ -211,142 +405,317 @@ impl BorshSerialize for String { #[cfg(feature = "ascii")] pub mod ascii { //! - //! Module defines [BorshSerialize] implementation for - //! some types from [ascii](::ascii) crate. + //! Module defines [`BorshSerialize`] + #![cfg_attr(feature = "unstable__async", doc = " & [`BorshSerializeAsync`]")] + //! implementation for some types from [`ascii`] crate. + + #[cfg(feature = "unstable__async")] + use core::future::Future; + + use async_generic::async_generic; + use super::BorshSerialize; + #[cfg(feature = "unstable__async")] + use super::{AsyncWrite, BorshSerializeAsync}; use crate::io::{Result, Write}; + #[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + )] impl BorshSerialize for ascii::AsciiChar { #[inline] + #[async_generic( + async_signature[impl_fut]<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> impl Future> + Send + 'a + )] fn serialize(&self, writer: &mut W) -> Result<()> { - self.as_byte().serialize(writer) + let byte = self.as_byte(); + if _sync { + BorshSerialize::serialize(&byte, writer) + } else { + writer.write_u8(byte) + } } } + #[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + )] impl BorshSerialize for ascii::AsciiStr { #[inline] + #[async_generic( + async_signature[impl_fut]<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> impl Future> + Send + 'a + )] fn serialize(&self, writer: &mut W) -> Result<()> { - self.as_bytes().serialize(writer) + let bytes = self.as_bytes(); + if _sync { + BorshSerialize::serialize(bytes, writer) + } else { + BorshSerializeAsync::serialize(bytes, writer) + } } } + #[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + )] impl BorshSerialize for ascii::AsciiString { #[inline] + #[async_generic( + async_signature[impl_fut]<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> impl Future> + Send + 'a + )] fn serialize(&self, writer: &mut W) -> Result<()> { - self.as_bytes().serialize(writer) + if _sync { + BorshSerialize::serialize(&**self, writer) + } else { + BorshSerializeAsync::serialize(&**self, writer) + } } } } /// Helper method that is used to serialize a slice of data (without the length marker). #[inline] +#[async_generic( + #[cfg(feature = "unstable__async")] + async_signature(data: &[T], writer: &mut W) -> Result<()> +)] fn serialize_slice(data: &[T], writer: &mut W) -> Result<()> { if let Some(u8_slice) = T::u8_slice(data) { - writer.write_all(u8_slice)?; + if _sync { + writer.write_all(u8_slice) + } else { + writer.write_all(u8_slice).await + }?; } else { for item in data { - item.serialize(writer)?; + if _sync { + BorshSerialize::serialize(item, writer) + } else { + BorshSerializeAsync::serialize(item, writer).await + }?; } } Ok(()) } +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + where + T: BorshSerializeAsync + Sync, +)] impl BorshSerialize for [T] where T: BorshSerialize, { #[inline] + #[async_generic(async_signature<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> Result<()>)] fn serialize(&self, writer: &mut W) -> Result<()> { - writer.write_all( - &(u32::try_from(self.len()).map_err(|_| ErrorKind::InvalidData)?).to_le_bytes(), - )?; - serialize_slice(self, writer) + let len = u32::try_from(self.len()).map_err(|_| ErrorKind::InvalidData)?; + if _sync { + writer.write_all(&len.to_le_bytes())?; + serialize_slice(self, writer) + } else { + writer.write_u32(len).await?; + serialize_slice_async(self, writer).await + } } } +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant +)] impl BorshSerialize for &T { #[inline] + #[async_generic( + async_signature[impl_fut]<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> impl Future> + Send + 'a + )] fn serialize(&self, writer: &mut W) -> Result<()> { - (*self).serialize(writer) + if _sync { + BorshSerialize::serialize(*self, writer) + } else { + BorshSerializeAsync::serialize(*self, writer) + } } } +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + where + T: BorshSerializeAsync + ToOwned + ?Sized, + ::Owned: Sync, +)] impl BorshSerialize for Cow<'_, T> where T: BorshSerialize + ToOwned + ?Sized, { #[inline] + #[async_generic( + async_signature[impl_fut]<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> impl Future> + Send + 'a + )] fn serialize(&self, writer: &mut W) -> Result<()> { - self.as_ref().serialize(writer) + let r#ref = self.as_ref(); + if _sync { + BorshSerialize::serialize(r#ref, writer) + } else { + BorshSerializeAsync::serialize(r#ref, writer) + } } } +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + where + T: BorshSerializeAsync, +)] impl BorshSerialize for Vec where T: BorshSerialize, { #[inline] + #[async_generic(async_signature<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> Result<()>)] fn serialize(&self, writer: &mut W) -> Result<()> { check_zst::()?; - - self.as_slice().serialize(writer) + let slice = self.as_slice(); + if _sync { + BorshSerialize::serialize(slice, writer) + } else { + // don't remove `.await`, because `async_signature` will remove the implicit `async` + // block and you would need to setup the state machine manually anyway, + // because of `?` in `check_zst::()?` + BorshSerializeAsync::serialize(slice, writer).await + } } } #[cfg(feature = "bytes")] +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant +)] impl BorshSerialize for bytes::Bytes { #[inline] + #[async_generic( + async_signature[impl_fut]<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> impl Future> + Send + 'a + )] fn serialize(&self, writer: &mut W) -> Result<()> { - self.as_ref().serialize(writer) + let bytes = self.as_ref(); + if _sync { + BorshSerialize::serialize(bytes, writer) + } else { + BorshSerializeAsync::serialize(bytes, writer) + } } } #[cfg(feature = "bytes")] +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant +)] impl BorshSerialize for bytes::BytesMut { #[inline] + #[async_generic( + async_signature[impl_fut]<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> impl Future> + Send + 'a + )] fn serialize(&self, writer: &mut W) -> Result<()> { - self.as_ref().serialize(writer) + let bytes = self.as_ref(); + if _sync { + BorshSerialize::serialize(bytes, writer) + } else { + BorshSerializeAsync::serialize(bytes, writer) + } } } +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant +)] #[cfg(feature = "bson")] impl BorshSerialize for bson::oid::ObjectId { #[inline] + #[async_generic( + async_signature[impl_fut]<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> impl Future> + Send + 'a + )] fn serialize(&self, writer: &mut W) -> Result<()> { - self.bytes().serialize(writer) + #[inline(always)] + fn as_bytes(r#ref: &bson::oid::ObjectId) -> &[u8; 12] { + // SAFETY: `ObjectId` is a `12` byte array. + unsafe { &*(r#ref as *const bson::oid::ObjectId as *const [u8; 12]) } + } + + let bytes = as_bytes(self); + if _sync { + writer.write_all(bytes) + } else { + writer.write_all(bytes) + } } } +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + where + T: BorshSerializeAsync, +)] impl BorshSerialize for VecDeque where T: BorshSerialize, { #[inline] + #[async_generic(async_signature<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> Result<()>)] fn serialize(&self, writer: &mut W) -> Result<()> { check_zst::()?; - writer.write_all( - &(u32::try_from(self.len()).map_err(|_| ErrorKind::InvalidData)?).to_le_bytes(), - )?; + let len = u32::try_from(self.len()).map_err(|_| ErrorKind::InvalidData)?; let slices = self.as_slices(); - serialize_slice(slices.0, writer)?; - serialize_slice(slices.1, writer) + if _sync { + writer.write_all(&len.to_le_bytes())?; + serialize_slice(slices.0, writer)?; + serialize_slice(slices.1, writer) + } else { + writer.write_u32(len).await?; + serialize_slice_async(slices.0, writer).await?; + serialize_slice_async(slices.1, writer).await + } } } +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + where + T: BorshSerializeAsync, +)] impl BorshSerialize for LinkedList where T: BorshSerialize, { #[inline] + #[async_generic(async_signature<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> Result<()>)] fn serialize(&self, writer: &mut W) -> Result<()> { check_zst::()?; - writer.write_all( - &(u32::try_from(self.len()).map_err(|_| ErrorKind::InvalidData)?).to_le_bytes(), - )?; + let len = u32::try_from(self.len()).map_err(|_| ErrorKind::InvalidData)?; + if _sync { + BorshSerialize::serialize(&len, writer) + } else { + writer.write_u32(len).await + }?; for item in self { - item.serialize(writer)?; + if _sync { + BorshSerialize::serialize(item, writer) + } else { + BorshSerializeAsync::serialize(item, writer).await + }?; } Ok(()) } @@ -354,21 +723,35 @@ where /// Module is available if borsh is built with `features = ["std"]` or `features = ["hashbrown"]`. /// -/// Module defines [BorshSerialize] implementation for -/// [HashMap](std::collections::HashMap)/[HashSet](std::collections::HashSet). +/// Module defines [`BorshSerialize`] +#[cfg_attr(feature = "unstable__async", doc = " & [`BorshSerializeAsync`]")] +/// implementation for [`HashMap`](std::collections::HashMap)/[`HashSet`](std::collections::HashSet). #[cfg(hash_collections)] pub mod hashes { - use crate::__private::maybestd::vec::Vec; - use crate::error::check_zst; + use core::{convert::TryFrom, hash::BuildHasher}; + + use async_generic::async_generic; + + use super::BorshSerialize; + #[cfg(feature = "unstable__async")] + use super::{AsyncWrite, BorshSerializeAsync}; use crate::{ - BorshSerialize, - __private::maybestd::collections::{HashMap, HashSet}, + __private::maybestd::{ + collections::{HashMap, HashSet}, + vec::Vec, + }, + error::check_zst, + io::{ErrorKind, Result, Write}, }; - use core::convert::TryFrom; - use core::hash::BuildHasher; - - use crate::io::{ErrorKind, Result, Write}; + #[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + where + K: BorshSerializeAsync + Ord, + V: BorshSerializeAsync, + H: BuildHasher + Sync, + )] impl BorshSerialize for HashMap where K: BorshSerialize + Ord, @@ -376,196 +759,385 @@ pub mod hashes { H: BuildHasher, { #[inline] + #[async_generic(async_signature<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> Result<()>)] fn serialize(&self, writer: &mut W) -> Result<()> { check_zst::()?; let mut vec = self.iter().collect::>(); vec.sort_by(|(a, _), (b, _)| a.cmp(b)); - u32::try_from(vec.len()) - .map_err(|_| ErrorKind::InvalidData)? - .serialize(writer)?; + let len = u32::try_from(vec.len()).map_err(|_| ErrorKind::InvalidData)?; + if _sync { + BorshSerialize::serialize(&len, writer) + } else { + writer.write_u32(len).await + }?; for kv in vec { - kv.serialize(writer)?; + if _sync { + BorshSerialize::serialize(&kv, writer) + } else { + BorshSerializeAsync::serialize(&kv, writer).await + }?; } Ok(()) } } + #[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + where + T: BorshSerializeAsync + Ord, + H: BuildHasher + Sync, + )] impl BorshSerialize for HashSet where T: BorshSerialize + Ord, H: BuildHasher, { #[inline] + #[async_generic(async_signature<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> Result<()>)] fn serialize(&self, writer: &mut W) -> Result<()> { check_zst::()?; let mut vec = self.iter().collect::>(); vec.sort(); - u32::try_from(vec.len()) - .map_err(|_| ErrorKind::InvalidData)? - .serialize(writer)?; + let len = u32::try_from(vec.len()).map_err(|_| ErrorKind::InvalidData)?; + if _sync { + BorshSerialize::serialize(&len, writer) + } else { + writer.write_u32(len).await + }?; for item in vec { - item.serialize(writer)?; + if _sync { + BorshSerialize::serialize(&item, writer) + } else { + BorshSerializeAsync::serialize(&item, writer).await + }?; } Ok(()) } } } +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + where + K: BorshSerializeAsync, + V: BorshSerializeAsync, +)] impl BorshSerialize for BTreeMap where K: BorshSerialize, V: BorshSerialize, { #[inline] + #[async_generic(async_signature<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> Result<()>)] fn serialize(&self, writer: &mut W) -> Result<()> { check_zst::()?; // NOTE: BTreeMap iterates over the entries that are sorted by key, so the serialization // result will be consistent without a need to sort the entries as we do for HashMap // serialization. - u32::try_from(self.len()) - .map_err(|_| ErrorKind::InvalidData)? - .serialize(writer)?; + let len = u32::try_from(self.len()).map_err(|_| ErrorKind::InvalidData)?; + if _sync { + BorshSerialize::serialize(&len, writer) + } else { + writer.write_u32(len).await + }?; for (key, value) in self { - key.serialize(writer)?; - value.serialize(writer)?; + if _sync { + BorshSerialize::serialize(&key, writer)?; + BorshSerialize::serialize(&value, writer) + } else { + BorshSerializeAsync::serialize(&key, writer).await?; + BorshSerializeAsync::serialize(&value, writer).await + }?; } Ok(()) } } +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + where + T: BorshSerializeAsync + Sync, +)] impl BorshSerialize for BTreeSet where T: BorshSerialize, { #[inline] + #[async_generic(async_signature<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> Result<()>)] fn serialize(&self, writer: &mut W) -> Result<()> { check_zst::()?; // NOTE: BTreeSet iterates over the items that are sorted, so the serialization result will // be consistent without a need to sort the entries as we do for HashSet serialization. - u32::try_from(self.len()) - .map_err(|_| ErrorKind::InvalidData)? - .serialize(writer)?; + let len = u32::try_from(self.len()).map_err(|_| ErrorKind::InvalidData)?; + if _sync { + BorshSerialize::serialize(&len, writer) + } else { + writer.write_u32(len).await + }?; for item in self { - item.serialize(writer)?; + if _sync { + BorshSerialize::serialize(&item, writer) + } else { + BorshSerializeAsync::serialize(&item, writer).await + }?; } Ok(()) } } #[cfg(feature = "std")] +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant +)] impl BorshSerialize for std::net::SocketAddr { #[inline] + #[async_generic(async_signature<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> Result<()>)] fn serialize(&self, writer: &mut W) -> Result<()> { - match *self { - std::net::SocketAddr::V4(ref addr) => { - 0u8.serialize(writer)?; - addr.serialize(writer) + match self { + std::net::SocketAddr::V4(addr) => { + if _sync { + BorshSerialize::serialize(&0u8, writer)?; + BorshSerialize::serialize(addr, writer) + } else { + BorshSerializeAsync::serialize(&0u8, writer).await?; + BorshSerializeAsync::serialize(addr, writer).await + } } - std::net::SocketAddr::V6(ref addr) => { - 1u8.serialize(writer)?; - addr.serialize(writer) + std::net::SocketAddr::V6(addr) => { + if _sync { + BorshSerialize::serialize(&1u8, writer)?; + BorshSerialize::serialize(addr, writer) + } else { + BorshSerializeAsync::serialize(&1u8, writer).await?; + BorshSerializeAsync::serialize(addr, writer).await + } } } } } #[cfg(feature = "std")] +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant +)] impl BorshSerialize for std::net::SocketAddrV4 { #[inline] + #[async_generic(async_signature<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> Result<()>)] fn serialize(&self, writer: &mut W) -> Result<()> { - self.ip().serialize(writer)?; - self.port().serialize(writer) + if _sync { + BorshSerialize::serialize(self.ip(), writer)?; + BorshSerialize::serialize(&self.port(), writer) + } else { + BorshSerializeAsync::serialize(self.ip(), writer).await?; + BorshSerializeAsync::serialize(&self.port(), writer).await + } } } #[cfg(feature = "std")] +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant +)] impl BorshSerialize for std::net::SocketAddrV6 { #[inline] + #[async_generic(async_signature<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> Result<()>)] fn serialize(&self, writer: &mut W) -> Result<()> { - self.ip().serialize(writer)?; - self.port().serialize(writer) + if _sync { + BorshSerialize::serialize(self.ip(), writer)?; + BorshSerialize::serialize(&self.port(), writer) + } else { + BorshSerializeAsync::serialize(self.ip(), writer).await?; + BorshSerializeAsync::serialize(&self.port(), writer).await + } } } #[cfg(feature = "std")] +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant +)] impl BorshSerialize for std::net::Ipv4Addr { #[inline] + #[async_generic( + async_signature[impl_fut]<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> impl Future> + Send + 'a + )] fn serialize(&self, writer: &mut W) -> Result<()> { - writer.write_all(&self.octets()) + #[inline(always)] + fn as_bytes(ip: &std::net::Ipv4Addr) -> &[u8; 4] { + // SAFETY: `Ipv4Addr` is a `4` byte array. + unsafe { &*(ip as *const std::net::Ipv4Addr as *const [u8; 4]) } + } + + let bytes = as_bytes(self); + if _sync { + writer.write_all(bytes) + } else { + writer.write_all(bytes) + } } } #[cfg(feature = "std")] +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant +)] impl BorshSerialize for std::net::Ipv6Addr { #[inline] + #[async_generic( + async_signature[impl_fut]<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> impl Future> + Send + 'a + )] fn serialize(&self, writer: &mut W) -> Result<()> { - writer.write_all(&self.octets()) + #[inline(always)] + fn as_bytes(ip: &std::net::Ipv6Addr) -> &[u8; 16] { + // SAFETY: `Ipv4Addr` is a `16` byte array. + unsafe { &*(ip as *const std::net::Ipv6Addr as *const [u8; 16]) } + } + + let bytes = as_bytes(self); + if _sync { + writer.write_all(bytes) + } else { + writer.write_all(bytes) + } } } #[cfg(feature = "std")] +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant +)] impl BorshSerialize for std::net::IpAddr { #[inline] + #[async_generic(async_signature<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> Result<()>)] fn serialize(&self, writer: &mut W) -> Result<()> { match self { std::net::IpAddr::V4(ipv4) => { - writer.write_all(&0u8.to_le_bytes())?; - ipv4.serialize(writer) + if _sync { + writer.write_all(&0u8.to_le_bytes())?; + BorshSerialize::serialize(ipv4, writer) + } else { + writer.write_all(&0u8.to_le_bytes()).await?; + BorshSerializeAsync::serialize(ipv4, writer).await + } } std::net::IpAddr::V6(ipv6) => { - writer.write_all(&1u8.to_le_bytes())?; - ipv6.serialize(writer) + if _sync { + writer.write_all(&1u8.to_le_bytes())?; + BorshSerialize::serialize(ipv6, writer) + } else { + writer.write_all(&1u8.to_le_bytes()).await?; + BorshSerializeAsync::serialize(ipv6, writer).await + } } } } } + +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + where + T: BorshSerializeAsync + ?Sized, +)] impl BorshSerialize for Box { + #[inline] + #[async_generic( + async_signature[impl_fut]<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> impl Future> + Send + 'a + )] fn serialize(&self, writer: &mut W) -> Result<()> { - self.as_ref().serialize(writer) + let r#ref = self.as_ref(); + if _sync { + BorshSerialize::serialize(r#ref, writer) + } else { + BorshSerializeAsync::serialize(r#ref, writer) + } } } +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + where + T: BorshSerializeAsync, +)] impl BorshSerialize for [T; N] where T: BorshSerialize, { #[inline] + #[async_generic(async_signature<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> Result<()>)] fn serialize(&self, writer: &mut W) -> Result<()> { if N == 0 { - return Ok(()); + Ok(()) } else if let Some(u8_slice) = T::u8_slice(self) { - writer.write_all(u8_slice)?; + if _sync { + writer.write_all(u8_slice) + } else { + writer.write_all(u8_slice).await + } } else { - for el in self.iter() { - el.serialize(writer)?; + for el in self { + if _sync { + BorshSerialize::serialize(el, writer) + } else { + BorshSerializeAsync::serialize(el, writer).await + }?; } + Ok(()) } - Ok(()) } } macro_rules! impl_tuple { (@unit $name:ty) => { + #[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + )] impl BorshSerialize for $name { #[inline] - fn serialize(&self, _writer: &mut W) -> Result<()> { + #[async_generic( + async_signature[ready]<'a, W: AsyncWrite>(&'a self, _: &'a mut W) -> impl Future> + Send + 'a + )] + fn serialize(&self, _: &mut W) -> Result<()> { Ok(()) } } }; ($($idx:tt $name:ident)+) => { - impl<$($name),+> BorshSerialize for ($($name,)+) - where $($name: BorshSerialize,)+ - { - #[inline] - fn serialize(&self, writer: &mut W) -> Result<()> { - $(self.$idx.serialize(writer)?;)+ - Ok(()) + #[async_generic( + #[cfg(feature = "unstable__async")] + async_variant<$($name),+> + where + $($name: BorshSerializeAsync,)+ + )] + impl<$($name),+> BorshSerialize for ($($name,)+) + where + $($name: BorshSerialize,)+ + { + #[inline] + #[async_generic(async_signature<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> Result<()>)] + fn serialize(&self, writer: &mut W) -> Result<()> { + if _sync { + $(BorshSerialize::serialize(&self.$idx, writer)?;)+ + } else { + $(BorshSerializeAsync::serialize(&self.$idx, writer).await?;)+ + } + Ok(()) + } } - } }; } @@ -595,11 +1167,22 @@ impl_tuple!(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T macro_rules! impl_range { ($type:ident, $this:ident, $($field:expr),*) => { + #[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + where + T: BorshSerializeAsync, + )] impl BorshSerialize for core::ops::$type { #[inline] + #[async_generic(async_signature<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> Result<()>)] fn serialize(&self, writer: &mut W) -> Result<()> { let $this = self; - $( $field.serialize(writer)?; )* + if _sync { + $( let _ = $field.serialize(writer)?; )* + } else { + $( let _ = $field.serialize(writer).await?; )* + } Ok(()) } } @@ -616,11 +1199,22 @@ impl_range!(RangeToInclusive, this, &this.end); #[cfg(feature = "rc")] pub mod rc { //! - //! Module defines [BorshSerialize] implementation for - //! [alloc::rc::Rc](std::rc::Rc) and [alloc::sync::Arc](std::sync::Arc). - use crate::__private::maybestd::{rc::Rc, sync::Arc}; - use crate::io::{Result, Write}; - use crate::BorshSerialize; + //! Module defines [`BorshSerialize`] + #![cfg_attr(feature = "unstable__async", doc = " & [`BorshSerializeAsync`]")] + //! implementation for [`Rc`] and [`Arc`]. + + #[cfg(feature = "unstable__async")] + use core::future::Future; + + use async_generic::async_generic; + + #[cfg(feature = "unstable__async")] + use super::{AsyncWrite, BorshSerializeAsync}; + use crate::{ + __private::maybestd::{rc::Rc, sync::Arc}, + io::{Result, Write}, + BorshSerialize, + }; /// This impl requires the [`"rc"`] Cargo feature of borsh. /// @@ -640,14 +1234,34 @@ pub mod rc { /// the contents of the `Arc` each time the `Arc` is referenced within the /// data structure. Serialization will not attempt to deduplicate these /// repeated data. + #[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + where + T: BorshSerializeAsync + ?Sized + Send, + )] impl BorshSerialize for Arc { + #[inline] + #[async_generic( + async_signature[impl_fut]<'a, W: AsyncWrite>(&'a self, writer: &'a mut W) -> impl Future> + Send + 'a + )] fn serialize(&self, writer: &mut W) -> Result<()> { (**self).serialize(writer) } } } +#[async_generic( + #[cfg(feature = "unstable__async")] + async_variant + where + T: ?Sized + Sync, +)] impl BorshSerialize for PhantomData { + #[inline] + #[async_generic( + async_signature[ready]<'a, W: AsyncWrite>(&'a self, _: &'a mut W) -> impl Future> + Send + )] fn serialize(&self, _: &mut W) -> Result<()> { Ok(()) } @@ -657,14 +1271,15 @@ impl BorshSerialize for core::cell::Cell where T: BorshSerialize + Copy, { + #[inline] fn serialize(&self, writer: &mut W) -> Result<()> { - ::serialize(&self.get(), writer) + T::serialize(&self.get(), writer) } } impl BorshSerialize for core::cell::RefCell where - T: BorshSerialize + Sized, + T: BorshSerialize + ?Sized, { fn serialize(&self, writer: &mut W) -> Result<()> { match self.try_borrow() { diff --git a/borsh/tests/common_macro.rs b/borsh/tests/common_macro.rs index bc5503ffb..dd82b0bf8 100644 --- a/borsh/tests/common_macro.rs +++ b/borsh/tests/common_macro.rs @@ -137,9 +137,11 @@ pub mod schema_imports { vec::Vec, }; - pub use borsh::schema::{ - add_definition, BorshSchemaContainer, Declaration, Definition, Fields, - SchemaContainerValidateError, SchemaMaxSerializedSizeError, + pub use borsh::{ + schema::{ + add_definition, BorshSchemaContainer, Declaration, Definition, Fields, + SchemaContainerValidateError, SchemaMaxSerializedSizeError, + }, + schema_container_of, BorshSchema, }; - pub use borsh::{schema_container_of, BorshSchema}; } diff --git a/borsh/tests/compile_derives/async_derives/test_generic_enums.rs b/borsh/tests/compile_derives/async_derives/test_generic_enums.rs new file mode 100644 index 000000000..854cbe343 --- /dev/null +++ b/borsh/tests/compile_derives/async_derives/test_generic_enums.rs @@ -0,0 +1,47 @@ +use alloc::collections::BTreeMap; +#[allow(unused)] +use alloc::{string::String, vec::Vec}; +#[cfg(hash_collections)] +use core::{cmp::Eq, hash::Hash}; +#[cfg(feature = "std")] +use std::collections::HashMap; + +use borsh::{BorshDeserializeAsync, BorshSerializeAsync}; +#[cfg(feature = "hashbrown")] +use hashbrown::HashMap; + +/// `T: Ord` bound is required for `BorshDeserialize` derive to be successful +#[derive(BorshSerializeAsync, BorshDeserializeAsync, PartialEq, Debug)] +enum E { + X { f: BTreeMap }, + Y(W), +} + +#[cfg(hash_collections)] +#[derive(BorshSerializeAsync, BorshDeserializeAsync, Debug)] +enum I1 { + B { + #[allow(unused)] + #[borsh(skip, async_bound(serialize = "V: Sync", deserialize = "V: Send"))] + x: HashMap, + y: String, + }, + C(K, Vec), +} + +#[cfg(hash_collections)] +#[derive(BorshSerializeAsync, BorshDeserializeAsync, Debug)] +enum I2 { + B { + x: HashMap, + y: String, + }, + C( + K, + #[borsh( + skip, + async_bound(serialize = "U: Sync", deserialize = "U: Default + Send") + )] + U, + ), +} diff --git a/borsh/tests/compile_derives/async_derives/test_generic_structs.rs b/borsh/tests/compile_derives/async_derives/test_generic_structs.rs new file mode 100644 index 000000000..e69de29bb diff --git a/borsh/tests/compile_derives/async_derives/test_macro_namespace_collisions.rs b/borsh/tests/compile_derives/async_derives/test_macro_namespace_collisions.rs new file mode 100644 index 000000000..121966ff5 --- /dev/null +++ b/borsh/tests/compile_derives/async_derives/test_macro_namespace_collisions.rs @@ -0,0 +1,21 @@ +// Borsh macros should not collide with the local modules: +// https://github.com/near/borsh-rs/issues/11 +mod std {} +mod core {} + +#[derive(borsh::BorshSerializeAsync, borsh::BorshDeserializeAsync)] +struct A; + +#[derive(borsh::BorshSerializeAsync, borsh::BorshDeserializeAsync)] +enum B { + C, + D, +} + +#[derive(borsh::BorshSerializeAsync, borsh::BorshDeserializeAsync)] +struct C { + x: u64, + #[allow(unused)] + #[borsh(skip)] + y: u64, +} diff --git a/borsh/tests/compile_derives/async_derives/test_recursive_structs.rs b/borsh/tests/compile_derives/async_derives/test_recursive_structs.rs new file mode 100644 index 000000000..e69de29bb diff --git a/borsh/tests/custom_reader/test_custom_reader.rs b/borsh/tests/custom_reader/test_custom_reader.rs index e0c6dc7de..aadd3f934 100644 --- a/borsh/tests/custom_reader/test_custom_reader.rs +++ b/borsh/tests/custom_reader/test_custom_reader.rs @@ -1,10 +1,10 @@ -use borsh::{from_reader, to_vec, BorshDeserialize, BorshSerialize}; - use alloc::{ string::{String, ToString}, vec::Vec, }; +use borsh::{from_reader, to_vec, BorshDeserialize, BorshSerialize}; + const ERROR_NOT_ALL_BYTES_READ: &str = "Not all bytes read"; const ERROR_UNEXPECTED_LENGTH_OF_INPUT: &str = "Unexpected length of input"; diff --git a/borsh/tests/deserialization_errors/test_ascii_strings.rs b/borsh/tests/deserialization_errors/test_ascii_strings.rs index ffcf90d8e..8f8ef786c 100644 --- a/borsh/tests/deserialization_errors/test_ascii_strings.rs +++ b/borsh/tests/deserialization_errors/test_ascii_strings.rs @@ -1,4 +1,5 @@ use alloc::string::ToString; + use borsh::from_slice; #[test] diff --git a/borsh/tests/deserialization_errors/test_initial.rs b/borsh/tests/deserialization_errors/test_initial.rs index 0fef5c5eb..33a33a086 100644 --- a/borsh/tests/deserialization_errors/test_initial.rs +++ b/borsh/tests/deserialization_errors/test_initial.rs @@ -1,8 +1,3 @@ -use borsh::from_slice; - -#[cfg(feature = "derive")] -use borsh::BorshDeserialize; - use alloc::{ format, string::{String, ToString}, @@ -10,6 +5,10 @@ use alloc::{ vec::Vec, }; +use borsh::from_slice; +#[cfg(feature = "derive")] +use borsh::BorshDeserialize; + #[cfg(feature = "derive")] #[derive(BorshDeserialize, Debug)] #[borsh(use_discriminant = true)] diff --git a/borsh/tests/tests.rs b/borsh/tests/tests.rs index ea8cad5d4..e82d7e98b 100644 --- a/borsh/tests/tests.rs +++ b/borsh/tests/tests.rs @@ -22,6 +22,14 @@ mod compile_derives { mod test_generic_enums; mod test_recursive_structs; + #[cfg(feature = "unstable__async")] + mod async_derives { + mod test_generic_structs; + mod test_generic_enums; + mod test_recursive_structs; + mod test_macro_namespace_collisions; + } + #[cfg(feature = "unstable__schema")] mod schema { mod test_generic_enums; diff --git a/borsh/tests/zero_sized_types/test_zero_sized_types_forbidden.rs b/borsh/tests/zero_sized_types/test_zero_sized_types_forbidden.rs index c48b9cf77..a88528f96 100644 --- a/borsh/tests/zero_sized_types/test_zero_sized_types_forbidden.rs +++ b/borsh/tests/zero_sized_types/test_zero_sized_types_forbidden.rs @@ -1,19 +1,15 @@ -use alloc::{string::ToString, vec, vec::Vec}; - +use alloc::{ + collections::{BTreeMap, BTreeSet, LinkedList, VecDeque}, + string::ToString, + vec, + vec::Vec, +}; #[cfg(feature = "std")] use std::collections::{HashMap, HashSet}; +use borsh::{error::ERROR_ZST_FORBIDDEN, from_slice, to_vec, BorshDeserialize, BorshSerialize}; #[cfg(feature = "hashbrown")] use hashbrown::{HashMap, HashSet}; - -use alloc::collections::{BTreeMap, BTreeSet, LinkedList, VecDeque}; - -use borsh::from_slice; -use borsh::to_vec; -use borsh::BorshDeserialize; -use borsh::BorshSerialize; - -use borsh::error::ERROR_ZST_FORBIDDEN; #[derive(BorshDeserialize, BorshSerialize, PartialEq, Debug, Eq, PartialOrd, Ord, Hash)] struct A(); diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 000000000..4d94d105b --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,4 @@ +edition = "2021" +unstable_features = true +group_imports = "StdExternalCrate" +imports_granularity = "Crate" \ No newline at end of file