From e92536f300f4ece151bcab62bf3dc1fbd36c8c41 Mon Sep 17 00:00:00 2001 From: Richard Dodd <richard.o.dodd@gmail.com> Date: Tue, 21 Aug 2018 13:47:00 +0100 Subject: [PATCH] Allow Vec as well as slice --- crates/macro-support/src/parser.rs | 39 +++++++++++++++++++++++++++--- tests/wasm/variadic.rs | 2 +- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/crates/macro-support/src/parser.rs b/crates/macro-support/src/parser.rs index dd52bc3c..97957f8f 100644 --- a/crates/macro-support/src/parser.rs +++ b/crates/macro-support/src/parser.rs @@ -1111,14 +1111,47 @@ fn assert_last_param_is_slice(decl: &syn::FnDecl) -> Result<(), Diagnostic> { #[inline] fn not_slice_error(tok: &dyn ToTokens) -> Diagnostic { Diagnostic::span_error(tok, "for variadic extern functions, the last argument must be a \ - slice, to hold the arguments of unknown length") + slice or `::std::vec::Vec`, to hold the arguments of unknown length") } - let arg = decl.inputs.last().ok_or_else(|| not_slice_error(&decl))?; + /// Is this path `::std::vec::Vec`. + /// + /// I could add `Vec`, but this would break in wierd ways if the user does + /// `use SomethingElse as Vec;`. + #[inline] + fn path_is_vec(path: &syn::Path) -> bool { + #[inline] + fn is_path_segment(path: Option<&syn::PathSegment>, + name: Option<&str>, + plain: bool) -> bool { + match (path, name) { + (Some(ref path), Some(ref name)) => + (path.arguments.is_empty() || ! plain) && path.ident == name, + (None, None) => true, + _ => false + } + } + + let mut iter = (&path.segments).into_iter(); + path.leading_colon.is_some() + && is_path_segment(iter.next(), Some("std"), true) + && is_path_segment(iter.next(), Some("vec"), true) + && is_path_segment(iter.next(), Some("Vec"), false) + && is_path_segment(iter.next(), None, true) + } + + let arg = decl.inputs.last().ok_or_else(|| not_slice_error(&decl.inputs))?; if let syn::FnArg::Captured(ref arg_cap) = arg.value() { + // check for slice reference if let syn::Type::Reference(ref ref_ty) = arg_cap.ty { if let syn::Type::Slice(_) = *ref_ty.elem { - return Ok(()) + return Ok(()); + } + } + // check for `Vec` + if let syn::Type::Path(ref path) = arg_cap.ty { + if path_is_vec(&path.path) { + return Ok(()); } } } diff --git a/tests/wasm/variadic.rs b/tests/wasm/variadic.rs index b2219078..a26c0fdb 100644 --- a/tests/wasm/variadic.rs +++ b/tests/wasm/variadic.rs @@ -32,7 +32,7 @@ extern { #[wasm_bindgen(variadic)] fn variadic_concat_str(first: &str, second: &str, rest: &[&str]) -> String; #[wasm_bindgen(variadic)] - fn variadic_concat_string(first: String, second: String, rest: Vec<String>) -> String; + fn variadic_concat_string(first: String, second: String, rest: ::std::vec::Vec<String>) -> String; } // ints