From b7faccfd2494a82c79aa0d88ccbf8f3e5eeed9d4 Mon Sep 17 00:00:00 2001 From: Daniyar Itegulov Date: Thu, 30 Jun 2022 17:28:41 +1000 Subject: [PATCH 1/3] extract #[callback_vec] vec type for abi --- .../src/core_impl/abi/abi_generator.rs | 9 ++++++ near-sdk-macros/src/core_impl/utils/mod.rs | 32 +++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/near-sdk-macros/src/core_impl/abi/abi_generator.rs b/near-sdk-macros/src/core_impl/abi/abi_generator.rs index 7b5fc95e1..17fbf2fe5 100644 --- a/near-sdk-macros/src/core_impl/abi/abi_generator.rs +++ b/near-sdk-macros/src/core_impl/abi/abi_generator.rs @@ -93,6 +93,15 @@ impl ImplItemMethodInfo { } BindgenArgType::CallbackArgVec => { if callback_vec.is_none() { + let typ = if let Some(vec_type) = utils::extract_vec_type(typ) { + vec_type + } else { + return syn::Error::new_spanned( + &arg.ty, + "Function parameters marked with #[callback_vec] should have type Vec", + ) + .into_compile_error(); + }; callback_vec = Some(quote! { Some( near_sdk::__private::AbiType { diff --git a/near-sdk-macros/src/core_impl/utils/mod.rs b/near-sdk-macros/src/core_impl/utils/mod.rs index 20c39633d..a427bf455 100644 --- a/near-sdk-macros/src/core_impl/utils/mod.rs +++ b/near-sdk-macros/src/core_impl/utils/mod.rs @@ -9,6 +9,15 @@ pub(crate) fn path_is_result(path: &Path) -> bool { && path.segments.iter().next().unwrap().ident == "Result" } +/// Checks whether the given path is literally "Vec". +/// Note that it won't match a fully qualified name `std::vec::Vec` or a type alias like +/// `type MyVec = Vec`. +pub(crate) fn path_is_vec(path: &Path) -> bool { + path.leading_colon.is_none() + && path.segments.len() == 1 + && path.segments.iter().next().unwrap().ident == "Vec" +} + /// Equivalent to `path_is_result` except that it works on `Type` values. pub(crate) fn type_is_result(ty: &Type) -> bool { match ty { @@ -39,3 +48,26 @@ pub(crate) fn extract_ok_type(ty: &Type) -> Option<&Type> { _ => None, } } + +/// Extracts the inner generic type from a `Vec<_>` type. +/// +/// For example, given `Vec` this function will return `String`. +pub(crate) fn extract_vec_type(ty: &Type) -> Option<&Type> { + match ty { + Type::Path(type_path) if type_path.qself.is_none() && path_is_vec(&type_path.path) => { + let type_params = &type_path.path.segments.first()?.arguments; + let generic_arg = match type_params { + // We are interested in the first (and only) angle-bracketed param: + PathArguments::AngleBracketed(params) if params.args.len() == 1 => { + Some(params.args.first()?) + } + _ => None, + }?; + match generic_arg { + GenericArgument::Type(ty) => Some(ty), + _ => None, + } + } + _ => None, + } +} From 1b3cde763c2046770fbbe7e240b5f20e455e85de Mon Sep 17 00:00:00 2001 From: Daniyar Itegulov Date: Thu, 30 Jun 2022 17:55:44 +1000 Subject: [PATCH 2/3] allow dead code --- near-sdk-macros/src/core_impl/utils/mod.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/near-sdk-macros/src/core_impl/utils/mod.rs b/near-sdk-macros/src/core_impl/utils/mod.rs index a427bf455..a720108dd 100644 --- a/near-sdk-macros/src/core_impl/utils/mod.rs +++ b/near-sdk-macros/src/core_impl/utils/mod.rs @@ -9,15 +9,6 @@ pub(crate) fn path_is_result(path: &Path) -> bool { && path.segments.iter().next().unwrap().ident == "Result" } -/// Checks whether the given path is literally "Vec". -/// Note that it won't match a fully qualified name `std::vec::Vec` or a type alias like -/// `type MyVec = Vec`. -pub(crate) fn path_is_vec(path: &Path) -> bool { - path.leading_colon.is_none() - && path.segments.len() == 1 - && path.segments.iter().next().unwrap().ident == "Vec" -} - /// Equivalent to `path_is_result` except that it works on `Type` values. pub(crate) fn type_is_result(ty: &Type) -> bool { match ty { @@ -49,9 +40,19 @@ pub(crate) fn extract_ok_type(ty: &Type) -> Option<&Type> { } } +/// Checks whether the given path is literally "Vec". +/// Note that it won't match a fully qualified name `std::vec::Vec` or a type alias like +/// `type MyVec = Vec`. +fn path_is_vec(path: &Path) -> bool { + path.leading_colon.is_none() + && path.segments.len() == 1 + && path.segments.iter().next().unwrap().ident == "Vec" +} + /// Extracts the inner generic type from a `Vec<_>` type. /// /// For example, given `Vec` this function will return `String`. +#[allow(dead_code)] pub(crate) fn extract_vec_type(ty: &Type) -> Option<&Type> { match ty { Type::Path(type_path) if type_path.qself.is_none() && path_is_vec(&type_path.path) => { From 56c2949b299db4a4dc42a3cceda2042dbe35ebb1 Mon Sep 17 00:00:00 2001 From: Daniyar Itegulov Date: Tue, 12 Jul 2022 13:29:52 +1000 Subject: [PATCH 3/3] move extract_vec_type under abi feature --- near-sdk-macros/src/core_impl/utils/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/near-sdk-macros/src/core_impl/utils/mod.rs b/near-sdk-macros/src/core_impl/utils/mod.rs index a720108dd..7048e976f 100644 --- a/near-sdk-macros/src/core_impl/utils/mod.rs +++ b/near-sdk-macros/src/core_impl/utils/mod.rs @@ -43,6 +43,7 @@ pub(crate) fn extract_ok_type(ty: &Type) -> Option<&Type> { /// Checks whether the given path is literally "Vec". /// Note that it won't match a fully qualified name `std::vec::Vec` or a type alias like /// `type MyVec = Vec`. +#[cfg(feature = "abi")] fn path_is_vec(path: &Path) -> bool { path.leading_colon.is_none() && path.segments.len() == 1 @@ -52,7 +53,7 @@ fn path_is_vec(path: &Path) -> bool { /// Extracts the inner generic type from a `Vec<_>` type. /// /// For example, given `Vec` this function will return `String`. -#[allow(dead_code)] +#[cfg(feature = "abi")] pub(crate) fn extract_vec_type(ty: &Type) -> Option<&Type> { match ty { Type::Path(type_path) if type_path.qself.is_none() && path_is_vec(&type_path.path) => {