Skip to content

Commit

Permalink
fix: extract #[callback_vec] vec type for abi (#863)
Browse files Browse the repository at this point in the history
  • Loading branch information
itegulov authored Jul 13, 2022
1 parent 41eb838 commit 61b5a8e
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 0 deletions.
9 changes: 9 additions & 0 deletions near-sdk-macros/src/core_impl/abi/abi_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>",
)
.into_compile_error();
};
callback_vec = Some(quote! {
Some(
near_sdk::__private::AbiType {
Expand Down
34 changes: 34 additions & 0 deletions near-sdk-macros/src/core_impl/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,37 @@ pub(crate) fn extract_ok_type(ty: &Type) -> Option<&Type> {
_ => None,
}
}

/// 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<String>`.
#[cfg(feature = "abi")]
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<String>` this function will return `String`.
#[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) => {
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,
}
}

0 comments on commit 61b5a8e

Please sign in to comment.