summaryrefslogtreecommitdiffstats
path: root/vendor/wasm-bindgen-backend/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:41:41 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:41:41 +0000
commit10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87 (patch)
treebdffd5d80c26cf4a7a518281a204be1ace85b4c1 /vendor/wasm-bindgen-backend/src
parentReleasing progress-linux version 1.70.0+dfsg1-9~progress7.99u1. (diff)
downloadrustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.tar.xz
rustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.zip
Merging upstream version 1.70.0+dfsg2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/wasm-bindgen-backend/src')
-rw-r--r--vendor/wasm-bindgen-backend/src/ast.rs453
-rw-r--r--vendor/wasm-bindgen-backend/src/codegen.rs1389
-rw-r--r--vendor/wasm-bindgen-backend/src/encode.rs536
-rw-r--r--vendor/wasm-bindgen-backend/src/error.rs134
-rw-r--r--vendor/wasm-bindgen-backend/src/lib.rs40
-rw-r--r--vendor/wasm-bindgen-backend/src/util.rs161
6 files changed, 2713 insertions, 0 deletions
diff --git a/vendor/wasm-bindgen-backend/src/ast.rs b/vendor/wasm-bindgen-backend/src/ast.rs
new file mode 100644
index 000000000..7703e2570
--- /dev/null
+++ b/vendor/wasm-bindgen-backend/src/ast.rs
@@ -0,0 +1,453 @@
+//! A representation of the Abstract Syntax Tree of a Rust program,
+//! with all the added metadata necessary to generate WASM bindings
+//! for it.
+
+use crate::Diagnostic;
+use proc_macro2::{Ident, Span};
+use std::hash::{Hash, Hasher};
+use wasm_bindgen_shared as shared;
+
+/// An abstract syntax tree representing a rust program. Contains
+/// extra information for joining up this rust code with javascript.
+#[cfg_attr(feature = "extra-traits", derive(Debug))]
+#[derive(Default, Clone)]
+pub struct Program {
+ /// rust -> js interfaces
+ pub exports: Vec<Export>,
+ /// js -> rust interfaces
+ pub imports: Vec<Import>,
+ /// rust enums
+ pub enums: Vec<Enum>,
+ /// rust structs
+ pub structs: Vec<Struct>,
+ /// custom typescript sections to be included in the definition file
+ pub typescript_custom_sections: Vec<String>,
+ /// Inline JS snippets
+ pub inline_js: Vec<String>,
+}
+
+impl Program {
+ /// Returns true if the Program is empty
+ pub fn is_empty(&self) -> bool {
+ self.exports.is_empty()
+ && self.imports.is_empty()
+ && self.enums.is_empty()
+ && self.structs.is_empty()
+ && self.typescript_custom_sections.is_empty()
+ && self.inline_js.is_empty()
+ }
+}
+
+/// A rust to js interface. Allows interaction with rust objects/functions
+/// from javascript.
+#[cfg_attr(feature = "extra-traits", derive(Debug))]
+#[derive(Clone)]
+pub struct Export {
+ /// Comments extracted from the rust source.
+ pub comments: Vec<String>,
+ /// The rust function
+ pub function: Function,
+ /// The class name in JS this is attached to
+ pub js_class: Option<String>,
+ /// The kind (static, named, regular)
+ pub method_kind: MethodKind,
+ /// The type of `self` (either `self`, `&self`, or `&mut self`)
+ pub method_self: Option<MethodSelf>,
+ /// The struct name, in Rust, this is attached to
+ pub rust_class: Option<Ident>,
+ /// The name of the rust function/method on the rust side.
+ pub rust_name: Ident,
+ /// Whether or not this function should be flagged as the wasm start
+ /// function.
+ pub start: bool,
+}
+
+/// The 3 types variations of `self`.
+#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
+#[derive(Clone)]
+pub enum MethodSelf {
+ /// `self`
+ ByValue,
+ /// `&mut self`
+ RefMutable,
+ /// `&self`
+ RefShared,
+}
+
+/// Things imported from a JS module (in an `extern` block)
+#[cfg_attr(feature = "extra-traits", derive(Debug))]
+#[derive(Clone)]
+pub struct Import {
+ /// The type of module being imported from, if any
+ pub module: Option<ImportModule>,
+ /// The namespace to access the item through, if any
+ pub js_namespace: Option<Vec<String>>,
+ /// The type of item being imported
+ pub kind: ImportKind,
+}
+
+/// The possible types of module to import from
+#[cfg_attr(feature = "extra-traits", derive(Debug))]
+#[derive(Clone)]
+pub enum ImportModule {
+ /// Import from the named module, with relative paths interpreted
+ Named(String, Span),
+ /// Import from the named module, without interpreting paths
+ RawNamed(String, Span),
+ /// Import from an inline JS snippet
+ Inline(usize, Span),
+}
+
+impl Hash for ImportModule {
+ fn hash<H: Hasher>(&self, h: &mut H) {
+ match self {
+ ImportModule::Named(name, _) => (1u8, name).hash(h),
+ ImportModule::Inline(idx, _) => (2u8, idx).hash(h),
+ ImportModule::RawNamed(name, _) => (3u8, name).hash(h),
+ }
+ }
+}
+
+/// The type of item being imported
+#[cfg_attr(feature = "extra-traits", derive(Debug))]
+#[derive(Clone)]
+pub enum ImportKind {
+ /// Importing a function
+ Function(ImportFunction),
+ /// Importing a static value
+ Static(ImportStatic),
+ /// Importing a type/class
+ Type(ImportType),
+ /// Importing a JS enum
+ Enum(ImportEnum),
+}
+
+/// A function being imported from JS
+#[cfg_attr(feature = "extra-traits", derive(Debug))]
+#[derive(Clone)]
+pub struct ImportFunction {
+ /// The full signature of the function
+ pub function: Function,
+ /// The name rust code will use
+ pub rust_name: Ident,
+ /// The type being returned
+ pub js_ret: Option<syn::Type>,
+ /// Whether to catch JS exceptions
+ pub catch: bool,
+ /// Whether the function is variadic on the JS side
+ pub variadic: bool,
+ /// Whether the function should use structural type checking
+ pub structural: bool,
+ /// Causes the Builder (See cli-support::js::binding::Builder) to error out if
+ /// it finds itself generating code for a function with this signature
+ pub assert_no_shim: bool,
+ /// The kind of function being imported
+ pub kind: ImportFunctionKind,
+ /// The shim name to use in the generated code. The 'shim' is a function that appears in
+ /// the generated JS as a wrapper around the actual function to import, performing any
+ /// necessary conversions (EG adding a try/catch to change a thrown error into a Result)
+ pub shim: Ident,
+ /// The doc comment on this import, if one is provided
+ pub doc_comment: String,
+}
+
+/// The type of a function being imported
+#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
+#[derive(Clone)]
+pub enum ImportFunctionKind {
+ /// A class method
+ Method {
+ /// The name of the class for this method, in JS
+ class: String,
+ /// The type of the class for this method, in Rust
+ ty: syn::Type,
+ /// The kind of method this is
+ kind: MethodKind,
+ },
+ /// A standard function
+ Normal,
+}
+
+/// The type of a method
+#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
+#[derive(Clone)]
+pub enum MethodKind {
+ /// A class constructor
+ Constructor,
+ /// Any other kind of method
+ Operation(Operation),
+}
+
+/// The operation performed by a class method
+#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
+#[derive(Clone)]
+pub struct Operation {
+ /// Whether this method is static
+ pub is_static: bool,
+ /// The internal kind of this Operation
+ pub kind: OperationKind,
+}
+
+/// The kind of operation performed by a method
+#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
+#[derive(Clone)]
+pub enum OperationKind {
+ /// A standard method, nothing special
+ Regular,
+ /// A method for getting the value of the provided Ident
+ Getter(Option<Ident>),
+ /// A method for setting the value of the provided Ident
+ Setter(Option<Ident>),
+ /// A dynamically intercepted getter
+ IndexingGetter,
+ /// A dynamically intercepted setter
+ IndexingSetter,
+ /// A dynamically intercepted deleter
+ IndexingDeleter,
+}
+
+/// The type of a static being imported
+#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
+#[derive(Clone)]
+pub struct ImportStatic {
+ /// The visibility of this static in Rust
+ pub vis: syn::Visibility,
+ /// The type of static being imported
+ pub ty: syn::Type,
+ /// The name of the shim function used to access this static
+ pub shim: Ident,
+ /// The name of this static on the Rust side
+ pub rust_name: Ident,
+ /// The name of this static on the JS side
+ pub js_name: String,
+}
+
+/// The metadata for a type being imported
+#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
+#[derive(Clone)]
+pub struct ImportType {
+ /// The visibility of this type in Rust
+ pub vis: syn::Visibility,
+ /// The name of this type on the Rust side
+ pub rust_name: Ident,
+ /// The name of this type on the JS side
+ pub js_name: String,
+ /// The custom attributes to apply to this type
+ pub attrs: Vec<syn::Attribute>,
+ /// The TS definition to generate for this type
+ pub typescript_type: Option<String>,
+ /// The doc comment applied to this type, if one exists
+ pub doc_comment: Option<String>,
+ /// The name of the shim to check instanceof for this type
+ pub instanceof_shim: String,
+ /// The name of the remote function to use for the generated is_type_of
+ pub is_type_of: Option<syn::Expr>,
+ /// The list of classes this extends, if any
+ pub extends: Vec<syn::Path>,
+ /// A custom prefix to add and attempt to fall back to, if the type isn't found
+ pub vendor_prefixes: Vec<Ident>,
+ /// If present, don't generate a `Deref` impl
+ pub no_deref: bool,
+}
+
+/// The metadata for an Enum being imported
+#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
+#[derive(Clone)]
+pub struct ImportEnum {
+ /// The Rust enum's visibility
+ pub vis: syn::Visibility,
+ /// The Rust enum's identifiers
+ pub name: Ident,
+ /// The Rust identifiers for the variants
+ pub variants: Vec<Ident>,
+ /// The JS string values of the variants
+ pub variant_values: Vec<String>,
+ /// Attributes to apply to the Rust enum
+ pub rust_attrs: Vec<syn::Attribute>,
+}
+
+/// Information about a function being imported or exported
+#[cfg_attr(feature = "extra-traits", derive(Debug))]
+#[derive(Clone)]
+pub struct Function {
+ /// The name of the function
+ pub name: String,
+ /// The span of the function's name in Rust code
+ pub name_span: Span,
+ /// Whether the function has a js_name attribute
+ pub renamed_via_js_name: bool,
+ /// The arguments to the function
+ pub arguments: Vec<syn::PatType>,
+ /// The return type of the function, if provided
+ pub ret: Option<syn::Type>,
+ /// Any custom attributes being applied to the function
+ pub rust_attrs: Vec<syn::Attribute>,
+ /// The visibility of this function in Rust
+ pub rust_vis: syn::Visibility,
+ /// Whether this is an `async` function
+ pub r#async: bool,
+ /// Whether to generate a typescript definition for this function
+ pub generate_typescript: bool,
+ /// Whether this is a function with a variadict parameter
+ pub variadic: bool,
+}
+
+/// Information about a Struct being exported
+#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
+#[derive(Clone)]
+pub struct Struct {
+ /// The name of the struct in Rust code
+ pub rust_name: Ident,
+ /// The name of the struct in JS code
+ pub js_name: String,
+ /// All the fields of this struct to export
+ pub fields: Vec<StructField>,
+ /// The doc comments on this struct, if provided
+ pub comments: Vec<String>,
+ /// Whether this struct is inspectable (provides toJSON/toString properties to JS)
+ pub is_inspectable: bool,
+ /// Whether to generate a typescript definition for this struct
+ pub generate_typescript: bool,
+}
+
+/// The field of a struct
+#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
+#[derive(Clone)]
+pub struct StructField {
+ /// The name of the field in Rust code
+ pub rust_name: syn::Member,
+ /// The name of the field in JS code
+ pub js_name: String,
+ /// The name of the struct this field is part of
+ pub struct_name: Ident,
+ /// Whether this value is read-only to JS
+ pub readonly: bool,
+ /// The type of this field
+ pub ty: syn::Type,
+ /// The name of the getter shim for this field
+ pub getter: Ident,
+ /// The name of the setter shim for this field
+ pub setter: Ident,
+ /// The doc comments on this field, if any
+ pub comments: Vec<String>,
+ /// Whether to generate a typescript definition for this field
+ pub generate_typescript: bool,
+ /// Whether to use .clone() in the auto-generated getter for this field
+ pub getter_with_clone: bool,
+}
+
+/// Information about an Enum being exported
+#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
+#[derive(Clone)]
+pub struct Enum {
+ /// The name of this enum in Rust code
+ pub rust_name: Ident,
+ /// The name of this enum in JS code
+ pub js_name: String,
+ /// The variants provided by this enum
+ pub variants: Vec<Variant>,
+ /// The doc comments on this enum, if any
+ pub comments: Vec<String>,
+ /// The value to use for a `none` variant of the enum
+ pub hole: u32,
+ /// Whether to generate a typescript definition for this enum
+ pub generate_typescript: bool,
+}
+
+/// The variant of an enum
+#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
+#[derive(Clone)]
+pub struct Variant {
+ /// The name of this variant
+ pub name: Ident,
+ /// The backing value of this variant
+ pub value: u32,
+ /// The doc comments on this variant, if any
+ pub comments: Vec<String>,
+}
+
+/// Unused, the type of an argument to / return from a function
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum TypeKind {
+ /// A by-reference arg, EG `&T`
+ ByRef,
+ /// A by-mutable-reference arg, EG `&mut T`
+ ByMutRef,
+ /// A by-value arg, EG `T`
+ ByValue,
+}
+
+/// Unused, the location of a type for a function argument (import/export, argument/ret)
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum TypeLocation {
+ /// An imported argument (JS side type)
+ ImportArgument,
+ /// An imported return
+ ImportRet,
+ /// An exported argument (Rust side type)
+ ExportArgument,
+ /// An exported return
+ ExportRet,
+}
+
+impl Export {
+ /// Mangles a rust -> javascript export, so that the created Ident will be unique over function
+ /// name and class name, if the function belongs to a javascript class.
+ pub(crate) fn rust_symbol(&self) -> Ident {
+ let mut generated_name = String::from("__wasm_bindgen_generated");
+ if let Some(class) = &self.js_class {
+ generated_name.push_str("_");
+ generated_name.push_str(class);
+ }
+ generated_name.push_str("_");
+ generated_name.push_str(&self.function.name.to_string());
+ Ident::new(&generated_name, Span::call_site())
+ }
+
+ /// This is the name of the shim function that gets exported and takes the raw
+ /// ABI form of its arguments and converts them back into their normal,
+ /// "high level" form before calling the actual function.
+ pub(crate) fn export_name(&self) -> String {
+ let fn_name = self.function.name.to_string();
+ match &self.js_class {
+ Some(class) => shared::struct_function_export_name(class, &fn_name),
+ None => shared::free_function_export_name(&fn_name),
+ }
+ }
+}
+
+impl ImportKind {
+ /// Whether this type can be inside an `impl` block.
+ pub fn fits_on_impl(&self) -> bool {
+ match *self {
+ ImportKind::Function(_) => true,
+ ImportKind::Static(_) => false,
+ ImportKind::Type(_) => false,
+ ImportKind::Enum(_) => false,
+ }
+ }
+}
+
+impl Function {
+ /// If the rust object has a `fn xxx(&self) -> MyType` method, get the name for a getter in
+ /// javascript (in this case `xxx`, so you can write `val = obj.xxx`)
+ pub fn infer_getter_property(&self) -> &str {
+ &self.name
+ }
+
+ /// If the rust object has a `fn set_xxx(&mut self, MyType)` style method, get the name
+ /// for a setter in javascript (in this case `xxx`, so you can write `obj.xxx = val`)
+ pub fn infer_setter_property(&self) -> Result<String, Diagnostic> {
+ let name = self.name.to_string();
+
+ // Otherwise we infer names based on the Rust function name.
+ if !name.starts_with("set_") {
+ bail_span!(
+ syn::token::Pub(self.name_span),
+ "setters must start with `set_`, found: {}",
+ name,
+ );
+ }
+ Ok(name[4..].to_string())
+ }
+}
diff --git a/vendor/wasm-bindgen-backend/src/codegen.rs b/vendor/wasm-bindgen-backend/src/codegen.rs
new file mode 100644
index 000000000..5be0fad33
--- /dev/null
+++ b/vendor/wasm-bindgen-backend/src/codegen.rs
@@ -0,0 +1,1389 @@
+use crate::ast;
+use crate::encode;
+use crate::util::ShortHash;
+use crate::Diagnostic;
+use once_cell::sync::Lazy;
+use proc_macro2::{Ident, Literal, Span, TokenStream};
+use quote::{quote, ToTokens};
+use std::collections::{HashMap, HashSet};
+use std::sync::Mutex;
+use wasm_bindgen_shared as shared;
+
+/// A trait for converting AST structs into Tokens and adding them to a TokenStream,
+/// or providing a diagnostic if conversion fails.
+pub trait TryToTokens {
+ /// Attempt to convert a `Self` into tokens and add it to the `TokenStream`
+ fn try_to_tokens(&self, tokens: &mut TokenStream) -> Result<(), Diagnostic>;
+
+ /// Attempt to convert a `Self` into a new `TokenStream`
+ fn try_to_token_stream(&self) -> Result<TokenStream, Diagnostic> {
+ let mut tokens = TokenStream::new();
+ self.try_to_tokens(&mut tokens)?;
+ Ok(tokens)
+ }
+}
+
+impl TryToTokens for ast::Program {
+ // Generate wrappers for all the items that we've found
+ fn try_to_tokens(&self, tokens: &mut TokenStream) -> Result<(), Diagnostic> {
+ let mut errors = Vec::new();
+ for export in self.exports.iter() {
+ if let Err(e) = export.try_to_tokens(tokens) {
+ errors.push(e);
+ }
+ }
+ for s in self.structs.iter() {
+ s.to_tokens(tokens);
+ }
+ let mut types = HashMap::new();
+ for i in self.imports.iter() {
+ if let ast::ImportKind::Type(t) = &i.kind {
+ types.insert(t.rust_name.to_string(), t.rust_name.clone());
+ }
+ }
+ for i in self.imports.iter() {
+ DescribeImport { kind: &i.kind }.to_tokens(tokens);
+
+ // If there is a js namespace, check that name isn't a type. If it is,
+ // this import might be a method on that type.
+ if let Some(nss) = &i.js_namespace {
+ // When the namespace is `A.B`, the type name should be `B`.
+ if let Some(ns) = nss.last().and_then(|t| types.get(t)) {
+ if i.kind.fits_on_impl() {
+ let kind = match i.kind.try_to_token_stream() {
+ Ok(kind) => kind,
+ Err(e) => {
+ errors.push(e);
+ continue;
+ }
+ };
+ (quote! {
+ #[automatically_derived]
+ impl #ns { #kind }
+ })
+ .to_tokens(tokens);
+ continue;
+ }
+ }
+ }
+
+ if let Err(e) = i.kind.try_to_tokens(tokens) {
+ errors.push(e);
+ }
+ }
+ for e in self.enums.iter() {
+ e.to_tokens(tokens);
+ }
+
+ Diagnostic::from_vec(errors)?;
+
+ // Generate a static which will eventually be what lives in a custom section
+ // of the wasm executable. For now it's just a plain old static, but we'll
+ // eventually have it actually in its own section.
+
+ // See comments in `crates/cli-support/src/lib.rs` about what this
+ // `schema_version` is.
+ let prefix_json = format!(
+ r#"{{"schema_version":"{}","version":"{}"}}"#,
+ shared::SCHEMA_VERSION,
+ shared::version()
+ );
+ let encoded = encode::encode(self)?;
+ let len = prefix_json.len() as u32;
+ let bytes = [
+ &len.to_le_bytes()[..],
+ prefix_json.as_bytes(),
+ &encoded.custom_section,
+ ]
+ .concat();
+
+ let generated_static_length = bytes.len();
+ let generated_static_value = syn::LitByteStr::new(&bytes, Span::call_site());
+
+ // We already consumed the contents of included files when generating
+ // the custom section, but we want to make sure that updates to the
+ // generated files will cause this macro to rerun incrementally. To do
+ // that we use `include_str!` to force rustc to think it has a
+ // dependency on these files. That way when the file changes Cargo will
+ // automatically rerun rustc which will rerun this macro. Other than
+ // this we don't actually need the results of the `include_str!`, so
+ // it's just shoved into an anonymous static.
+ let file_dependencies = encoded.included_files.iter().map(|file| {
+ let file = file.to_str().unwrap();
+ quote! { include_str!(#file) }
+ });
+
+ (quote! {
+ #[cfg(target_arch = "wasm32")]
+ #[automatically_derived]
+ const _: () = {
+ static _INCLUDED_FILES: &[&str] = &[#(#file_dependencies),*];
+
+ #[link_section = "__wasm_bindgen_unstable"]
+ pub static _GENERATED: [u8; #generated_static_length] =
+ *#generated_static_value;
+ };
+ })
+ .to_tokens(tokens);
+
+ Ok(())
+ }
+}
+
+impl ToTokens for ast::Struct {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ let name = &self.rust_name;
+ let name_str = self.js_name.to_string();
+ let name_len = name_str.len() as u32;
+ let name_chars = name_str.chars().map(|c| c as u32);
+ let new_fn = Ident::new(&shared::new_function(&name_str), Span::call_site());
+ let free_fn = Ident::new(&shared::free_function(&name_str), Span::call_site());
+ let free_fn_const = Ident::new(&format!("{}__const", free_fn), free_fn.span());
+ (quote! {
+ #[automatically_derived]
+ impl wasm_bindgen::describe::WasmDescribe for #name {
+ fn describe() {
+ use wasm_bindgen::__wbindgen_if_not_std;
+ __wbindgen_if_not_std! {
+ compile_error! {
+ "exporting a class to JS requires the `std` feature to \
+ be enabled in the `wasm-bindgen` crate"
+ }
+ }
+ use wasm_bindgen::describe::*;
+ inform(RUST_STRUCT);
+ inform(#name_len);
+ #(inform(#name_chars);)*
+ }
+ }
+
+ #[automatically_derived]
+ impl wasm_bindgen::convert::IntoWasmAbi for #name {
+ type Abi = u32;
+
+ fn into_abi(self) -> u32 {
+ use wasm_bindgen::__rt::std::boxed::Box;
+ use wasm_bindgen::__rt::WasmRefCell;
+ Box::into_raw(Box::new(WasmRefCell::new(self))) as u32
+ }
+ }
+
+ #[automatically_derived]
+ impl wasm_bindgen::convert::FromWasmAbi for #name {
+ type Abi = u32;
+
+ unsafe fn from_abi(js: u32) -> Self {
+ use wasm_bindgen::__rt::std::boxed::Box;
+ use wasm_bindgen::__rt::{assert_not_null, WasmRefCell};
+
+ let ptr = js as *mut WasmRefCell<#name>;
+ assert_not_null(ptr);
+ let js = Box::from_raw(ptr);
+ (*js).borrow_mut(); // make sure no one's borrowing
+ js.into_inner()
+ }
+ }
+
+ #[automatically_derived]
+ impl wasm_bindgen::__rt::core::convert::From<#name> for
+ wasm_bindgen::JsValue
+ {
+ fn from(value: #name) -> Self {
+ let ptr = wasm_bindgen::convert::IntoWasmAbi::into_abi(value);
+
+ #[link(wasm_import_module = "__wbindgen_placeholder__")]
+ #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
+ extern "C" {
+ fn #new_fn(ptr: u32) -> u32;
+ }
+
+ #[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))]
+ unsafe fn #new_fn(_: u32) -> u32 {
+ panic!("cannot convert to JsValue outside of the wasm target")
+ }
+
+ unsafe {
+ <wasm_bindgen::JsValue as wasm_bindgen::convert::FromWasmAbi>
+ ::from_abi(#new_fn(ptr))
+ }
+ }
+ }
+
+ #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
+ #[automatically_derived]
+ const #free_fn_const: () = {
+ #[no_mangle]
+ #[doc(hidden)]
+ pub unsafe extern "C" fn #free_fn(ptr: u32) {
+ drop(<#name as wasm_bindgen::convert::FromWasmAbi>::from_abi(ptr));
+ }
+ };
+
+ #[automatically_derived]
+ impl wasm_bindgen::convert::RefFromWasmAbi for #name {
+ type Abi = u32;
+ type Anchor = wasm_bindgen::__rt::Ref<'static, #name>;
+
+ unsafe fn ref_from_abi(js: Self::Abi) -> Self::Anchor {
+ let js = js as *mut wasm_bindgen::__rt::WasmRefCell<#name>;
+ wasm_bindgen::__rt::assert_not_null(js);
+ (*js).borrow()
+ }
+ }
+
+ #[automatically_derived]
+ impl wasm_bindgen::convert::RefMutFromWasmAbi for #name {
+ type Abi = u32;
+ type Anchor = wasm_bindgen::__rt::RefMut<'static, #name>;
+
+ unsafe fn ref_mut_from_abi(js: Self::Abi) -> Self::Anchor {
+ let js = js as *mut wasm_bindgen::__rt::WasmRefCell<#name>;
+ wasm_bindgen::__rt::assert_not_null(js);
+ (*js).borrow_mut()
+ }
+ }
+
+ #[automatically_derived]
+ impl wasm_bindgen::convert::OptionIntoWasmAbi for #name {
+ #[inline]
+ fn none() -> Self::Abi { 0 }
+ }
+
+ #[automatically_derived]
+ impl wasm_bindgen::convert::OptionFromWasmAbi for #name {
+ #[inline]
+ fn is_none(abi: &Self::Abi) -> bool { *abi == 0 }
+ }
+ })
+ .to_tokens(tokens);
+
+ for field in self.fields.iter() {
+ field.to_tokens(tokens);
+ }
+ }
+}
+
+impl ToTokens for ast::StructField {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ let rust_name = &self.rust_name;
+ let struct_name = &self.struct_name;
+ let ty = &self.ty;
+ let getter = &self.getter;
+ let setter = &self.setter;
+
+ let maybe_assert_copy = if self.getter_with_clone {
+ quote! {}
+ } else {
+ quote! { assert_copy::<#ty>() }
+ };
+ let maybe_assert_copy = respan(maybe_assert_copy, ty);
+
+ let maybe_clone = if self.getter_with_clone {
+ quote! { .clone() }
+ } else {
+ quote! {}
+ };
+
+ let getter_const = Ident::new(&format!("{}__const", getter), getter.span());
+
+ (quote! {
+ #[automatically_derived]
+ const #getter_const: () = {
+ #[cfg_attr(all(target_arch = "wasm32", not(target_os = "emscripten")), no_mangle)]
+ #[doc(hidden)]
+ pub unsafe extern "C" fn #getter(js: u32)
+ -> <#ty as wasm_bindgen::convert::IntoWasmAbi>::Abi
+ {
+ use wasm_bindgen::__rt::{WasmRefCell, assert_not_null};
+ use wasm_bindgen::convert::IntoWasmAbi;
+
+ fn assert_copy<T: Copy>(){}
+ #maybe_assert_copy;
+
+ let js = js as *mut WasmRefCell<#struct_name>;
+ assert_not_null(js);
+ let val = (*js).borrow().#rust_name#maybe_clone;
+ <#ty as IntoWasmAbi>::into_abi(val)
+ }
+ };
+ })
+ .to_tokens(tokens);
+
+ Descriptor {
+ ident: &getter,
+ inner: quote! {
+ <#ty as WasmDescribe>::describe();
+ },
+ attrs: vec![],
+ }
+ .to_tokens(tokens);
+
+ if self.readonly {
+ return;
+ }
+
+ let setter_const = Ident::new(&format!("{}__const", setter), setter.span());
+
+ (quote! {
+ #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
+ #[automatically_derived]
+ const #setter_const: () = {
+ #[no_mangle]
+ #[doc(hidden)]
+ pub unsafe extern "C" fn #setter(
+ js: u32,
+ val: <#ty as wasm_bindgen::convert::FromWasmAbi>::Abi,
+ ) {
+ use wasm_bindgen::__rt::{WasmRefCell, assert_not_null};
+ use wasm_bindgen::convert::FromWasmAbi;
+
+ let js = js as *mut WasmRefCell<#struct_name>;
+ assert_not_null(js);
+ let val = <#ty as FromWasmAbi>::from_abi(val);
+ (*js).borrow_mut().#rust_name = val;
+ }
+ };
+ })
+ .to_tokens(tokens);
+ }
+}
+
+impl TryToTokens for ast::Export {
+ fn try_to_tokens(self: &ast::Export, into: &mut TokenStream) -> Result<(), Diagnostic> {
+ let generated_name = self.rust_symbol();
+ let export_name = self.export_name();
+ let mut args = vec![];
+ let mut arg_conversions = vec![];
+ let mut converted_arguments = vec![];
+ let ret = Ident::new("_ret", Span::call_site());
+
+ let offset = if self.method_self.is_some() {
+ args.push(quote! { me: u32 });
+ 1
+ } else {
+ 0
+ };
+
+ let name = &self.rust_name;
+ let receiver = match self.method_self {
+ Some(ast::MethodSelf::ByValue) => {
+ let class = self.rust_class.as_ref().unwrap();
+ arg_conversions.push(quote! {
+ let me = unsafe {
+ <#class as wasm_bindgen::convert::FromWasmAbi>::from_abi(me)
+ };
+ });
+ quote! { me.#name }
+ }
+ Some(ast::MethodSelf::RefMutable) => {
+ let class = self.rust_class.as_ref().unwrap();
+ arg_conversions.push(quote! {
+ let mut me = unsafe {
+ <#class as wasm_bindgen::convert::RefMutFromWasmAbi>
+ ::ref_mut_from_abi(me)
+ };
+ let me = &mut *me;
+ });
+ quote! { me.#name }
+ }
+ Some(ast::MethodSelf::RefShared) => {
+ let class = self.rust_class.as_ref().unwrap();
+ arg_conversions.push(quote! {
+ let me = unsafe {
+ <#class as wasm_bindgen::convert::RefFromWasmAbi>
+ ::ref_from_abi(me)
+ };
+ let me = &*me;
+ });
+ quote! { me.#name }
+ }
+ None => match &self.rust_class {
+ Some(class) => quote! { #class::#name },
+ None => quote! { #name },
+ },
+ };
+
+ let mut argtys = Vec::new();
+ for (i, arg) in self.function.arguments.iter().enumerate() {
+ argtys.push(&arg.ty);
+ let i = i + offset;
+ let ident = Ident::new(&format!("arg{}", i), Span::call_site());
+ let ty = &arg.ty;
+ match &*arg.ty {
+ syn::Type::Reference(syn::TypeReference {
+ mutability: Some(_),
+ elem,
+ ..
+ }) => {
+ args.push(quote! {
+ #ident: <#elem as wasm_bindgen::convert::RefMutFromWasmAbi>::Abi
+ });
+ arg_conversions.push(quote! {
+ let mut #ident = unsafe {
+ <#elem as wasm_bindgen::convert::RefMutFromWasmAbi>
+ ::ref_mut_from_abi(#ident)
+ };
+ let #ident = &mut *#ident;
+ });
+ }
+ syn::Type::Reference(syn::TypeReference { elem, .. }) => {
+ args.push(quote! {
+ #ident: <#elem as wasm_bindgen::convert::RefFromWasmAbi>::Abi
+ });
+ arg_conversions.push(quote! {
+ let #ident = unsafe {
+ <#elem as wasm_bindgen::convert::RefFromWasmAbi>
+ ::ref_from_abi(#ident)
+ };
+ let #ident = &*#ident;
+ });
+ }
+ _ => {
+ args.push(quote! {
+ #ident: <#ty as wasm_bindgen::convert::FromWasmAbi>::Abi
+ });
+ arg_conversions.push(quote! {
+ let #ident = unsafe {
+ <#ty as wasm_bindgen::convert::FromWasmAbi>
+ ::from_abi(#ident)
+ };
+ });
+ }
+ }
+ converted_arguments.push(quote! { #ident });
+ }
+ let syn_unit = syn::Type::Tuple(syn::TypeTuple {
+ elems: Default::default(),
+ paren_token: Default::default(),
+ });
+ let syn_ret = self.function.ret.as_ref().unwrap_or(&syn_unit);
+ if let syn::Type::Reference(_) = syn_ret {
+ bail_span!(syn_ret, "cannot return a borrowed ref with #[wasm_bindgen]",)
+ }
+
+ // For an `async` function we always run it through `future_to_promise`
+ // since we're returning a promise to JS, and this will implicitly
+ // require that the function returns a `Future<Output = Result<...>>`
+ let (ret_ty, inner_ret_ty, ret_expr) = if self.function.r#async {
+ if self.start {
+ (
+ quote! { () },
+ quote! { () },
+ quote! {
+ <#syn_ret as wasm_bindgen::__rt::Start>::start(#ret.await)
+ },
+ )
+ } else {
+ (
+ quote! { wasm_bindgen::JsValue },
+ quote! { #syn_ret },
+ quote! {
+ <#syn_ret as wasm_bindgen::__rt::IntoJsResult>::into_js_result(#ret.await)
+ },
+ )
+ }
+ } else if self.start {
+ (
+ quote! { () },
+ quote! { () },
+ quote! { <#syn_ret as wasm_bindgen::__rt::Start>::start(#ret) },
+ )
+ } else {
+ (quote! { #syn_ret }, quote! { #syn_ret }, quote! { #ret })
+ };
+
+ let mut call = quote! {
+ {
+ #(#arg_conversions)*
+ let #ret = #receiver(#(#converted_arguments),*);
+ #ret_expr
+ }
+ };
+
+ if self.function.r#async {
+ if self.start {
+ call = quote! {
+ wasm_bindgen_futures::spawn_local(async move {
+ #call
+ })
+ }
+ } else {
+ call = quote! {
+ wasm_bindgen_futures::future_to_promise(async move {
+ #call
+ }).into()
+ }
+ }
+ }
+
+ let projection = quote! { <#ret_ty as wasm_bindgen::convert::ReturnWasmAbi> };
+ let convert_ret = quote! { #projection::return_abi(#ret) };
+ let describe_ret = quote! {
+ <#ret_ty as WasmDescribe>::describe();
+ <#inner_ret_ty as WasmDescribe>::describe();
+ };
+ let nargs = self.function.arguments.len() as u32;
+ let attrs = &self.function.rust_attrs;
+
+ let start_check = if self.start {
+ quote! { const _ASSERT: fn() = || -> #projection::Abi { loop {} }; }
+ } else {
+ quote! {}
+ };
+
+ let generated_name_const =
+ Ident::new(&format!("{}__const", generated_name), generated_name.span());
+ (quote! {
+ #[automatically_derived]
+ const #generated_name_const: () = {
+ #(#attrs)*
+ #[cfg_attr(
+ all(target_arch = "wasm32", not(target_os = "emscripten")),
+ export_name = #export_name,
+ )]
+ pub unsafe extern "C" fn #generated_name(#(#args),*) -> #projection::Abi {
+ #start_check
+
+ let #ret = #call;
+ #convert_ret
+ }
+ };
+ })
+ .to_tokens(into);
+
+ // In addition to generating the shim function above which is what
+ // our generated JS will invoke, we *also* generate a "descriptor"
+ // shim. This descriptor shim uses the `WasmDescribe` trait to
+ // programmatically describe the type signature of the generated
+ // shim above. This in turn is then used to inform the
+ // `wasm-bindgen` CLI tool exactly what types and such it should be
+ // using in JS.
+ //
+ // Note that this descriptor function is a purely an internal detail
+ // of `#[wasm_bindgen]` and isn't intended to be exported to anyone
+ // or actually part of the final was binary. Additionally, this is
+ // literally executed when the `wasm-bindgen` tool executes.
+ //
+ // In any case, there's complications in `wasm-bindgen` to handle
+ // this, but the tl;dr; is that this is stripped from the final wasm
+ // binary along with anything it references.
+ let export = Ident::new(&export_name, Span::call_site());
+ Descriptor {
+ ident: &export,
+ inner: quote! {
+ inform(FUNCTION);
+ inform(0);
+ inform(#nargs);
+ #(<#argtys as WasmDescribe>::describe();)*
+ #describe_ret
+ },
+ attrs: attrs.clone(),
+ }
+ .to_tokens(into);
+
+ Ok(())
+ }
+}
+
+impl TryToTokens for ast::ImportKind {
+ fn try_to_tokens(&self, tokens: &mut TokenStream) -> Result<(), Diagnostic> {
+ match *self {
+ ast::ImportKind::Function(ref f) => f.try_to_tokens(tokens)?,
+ ast::ImportKind::Static(ref s) => s.to_tokens(tokens),
+ ast::ImportKind::Type(ref t) => t.to_tokens(tokens),
+ ast::ImportKind::Enum(ref e) => e.to_tokens(tokens),
+ }
+
+ Ok(())
+ }
+}
+
+impl ToTokens for ast::ImportType {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ let vis = &self.vis;
+ let rust_name = &self.rust_name;
+ let attrs = &self.attrs;
+ let doc_comment = match &self.doc_comment {
+ None => "",
+ Some(comment) => comment,
+ };
+ let const_name = format!("__wbg_generated_const_{}", rust_name);
+ let const_name = Ident::new(&const_name, Span::call_site());
+ let instanceof_shim = Ident::new(&self.instanceof_shim, Span::call_site());
+
+ let internal_obj = match self.extends.first() {
+ Some(target) => {
+ quote! { #target }
+ }
+ None => {
+ quote! { wasm_bindgen::JsValue }
+ }
+ };
+
+ let description = if let Some(typescript_type) = &self.typescript_type {
+ let typescript_type_len = typescript_type.len() as u32;
+ let typescript_type_chars = typescript_type.chars().map(|c| c as u32);
+ quote! {
+ use wasm_bindgen::describe::*;
+ inform(NAMED_EXTERNREF);
+ inform(#typescript_type_len);
+ #(inform(#typescript_type_chars);)*
+ }
+ } else {
+ quote! {
+ JsValue::describe()
+ }
+ };
+
+ let is_type_of = self.is_type_of.as_ref().map(|is_type_of| {
+ quote! {
+ #[inline]
+ fn is_type_of(val: &JsValue) -> bool {
+ let is_type_of: fn(&JsValue) -> bool = #is_type_of;
+ is_type_of(val)
+ }
+ }
+ });
+
+ let no_deref = self.no_deref;
+
+ (quote! {
+ #[automatically_derived]
+ #(#attrs)*
+ #[doc = #doc_comment]
+ #[repr(transparent)]
+ #vis struct #rust_name {
+ obj: #internal_obj
+ }
+
+ #[automatically_derived]
+ const #const_name: () = {
+ use wasm_bindgen::convert::{IntoWasmAbi, FromWasmAbi};
+ use wasm_bindgen::convert::{OptionIntoWasmAbi, OptionFromWasmAbi};
+ use wasm_bindgen::convert::RefFromWasmAbi;
+ use wasm_bindgen::describe::WasmDescribe;
+ use wasm_bindgen::{JsValue, JsCast, JsObject};
+ use wasm_bindgen::__rt::core;
+
+ impl WasmDescribe for #rust_name {
+ fn describe() {
+ #description
+ }
+ }
+
+ impl IntoWasmAbi for #rust_name {
+ type Abi = <JsValue as IntoWasmAbi>::Abi;
+
+ #[inline]
+ fn into_abi(self) -> Self::Abi {
+ self.obj.into_abi()
+ }
+ }
+
+ impl OptionIntoWasmAbi for #rust_name {
+ #[inline]
+ fn none() -> Self::Abi {
+ 0
+ }
+ }
+
+ impl<'a> OptionIntoWasmAbi for &'a #rust_name {
+ #[inline]
+ fn none() -> Self::Abi {
+ 0
+ }
+ }
+
+ impl FromWasmAbi for #rust_name {
+ type Abi = <JsValue as FromWasmAbi>::Abi;
+
+ #[inline]
+ unsafe fn from_abi(js: Self::Abi) -> Self {
+ #rust_name {
+ obj: JsValue::from_abi(js).into(),
+ }
+ }
+ }
+
+ impl OptionFromWasmAbi for #rust_name {
+ #[inline]
+ fn is_none(abi: &Self::Abi) -> bool { *abi == 0 }
+ }
+
+ impl<'a> IntoWasmAbi for &'a #rust_name {
+ type Abi = <&'a JsValue as IntoWasmAbi>::Abi;
+
+ #[inline]
+ fn into_abi(self) -> Self::Abi {
+ (&self.obj).into_abi()
+ }
+ }
+
+ impl RefFromWasmAbi for #rust_name {
+ type Abi = <JsValue as RefFromWasmAbi>::Abi;
+ type Anchor = core::mem::ManuallyDrop<#rust_name>;
+
+ #[inline]
+ unsafe fn ref_from_abi(js: Self::Abi) -> Self::Anchor {
+ let tmp = <JsValue as RefFromWasmAbi>::ref_from_abi(js);
+ core::mem::ManuallyDrop::new(#rust_name {
+ obj: core::mem::ManuallyDrop::into_inner(tmp).into(),
+ })
+ }
+ }
+
+ // TODO: remove this on the next major version
+ impl From<JsValue> for #rust_name {
+ #[inline]
+ fn from(obj: JsValue) -> #rust_name {
+ #rust_name { obj: obj.into() }
+ }
+ }
+
+ impl AsRef<JsValue> for #rust_name {
+ #[inline]
+ fn as_ref(&self) -> &JsValue { self.obj.as_ref() }
+ }
+
+ impl AsRef<#rust_name> for #rust_name {
+ #[inline]
+ fn as_ref(&self) -> &#rust_name { self }
+ }
+
+
+ impl From<#rust_name> for JsValue {
+ #[inline]
+ fn from(obj: #rust_name) -> JsValue {
+ obj.obj.into()
+ }
+ }
+
+ impl JsCast for #rust_name {
+ fn instanceof(val: &JsValue) -> bool {
+ #[link(wasm_import_module = "__wbindgen_placeholder__")]
+ #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
+ extern "C" {
+ fn #instanceof_shim(val: u32) -> u32;
+ }
+ #[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))]
+ unsafe fn #instanceof_shim(_: u32) -> u32 {
+ panic!("cannot check instanceof on non-wasm targets");
+ }
+ unsafe {
+ let idx = val.into_abi();
+ #instanceof_shim(idx) != 0
+ }
+ }
+
+ #is_type_of
+
+ #[inline]
+ fn unchecked_from_js(val: JsValue) -> Self {
+ #rust_name { obj: val.into() }
+ }
+
+ #[inline]
+ fn unchecked_from_js_ref(val: &JsValue) -> &Self {
+ // Should be safe because `#rust_name` is a transparent
+ // wrapper around `val`
+ unsafe { &*(val as *const JsValue as *const #rust_name) }
+ }
+ }
+
+ impl JsObject for #rust_name {}
+ };
+ })
+ .to_tokens(tokens);
+
+ if !no_deref {
+ (quote! {
+ #[automatically_derived]
+ impl core::ops::Deref for #rust_name {
+ type Target = #internal_obj;
+
+ #[inline]
+ fn deref(&self) -> &#internal_obj {
+ &self.obj
+ }
+ }
+ })
+ .to_tokens(tokens);
+ }
+
+ for superclass in self.extends.iter() {
+ (quote! {
+ #[automatically_derived]
+ impl From<#rust_name> for #superclass {
+ #[inline]
+ fn from(obj: #rust_name) -> #superclass {
+ use wasm_bindgen::JsCast;
+ #superclass::unchecked_from_js(obj.into())
+ }
+ }
+
+ #[automatically_derived]
+ impl AsRef<#superclass> for #rust_name {
+ #[inline]
+ fn as_ref(&self) -> &#superclass {
+ use wasm_bindgen::JsCast;
+ #superclass::unchecked_from_js_ref(self.as_ref())
+ }
+ }
+ })
+ .to_tokens(tokens);
+ }
+ }
+}
+
+impl ToTokens for ast::ImportEnum {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ let vis = &self.vis;
+ let name = &self.name;
+ let expect_string = format!("attempted to convert invalid {} into JSValue", name);
+ let variants = &self.variants;
+ let variant_strings = &self.variant_values;
+ let attrs = &self.rust_attrs;
+
+ let mut current_idx: usize = 0;
+ let variant_indexes: Vec<Literal> = variants
+ .iter()
+ .map(|_| {
+ let this_index = current_idx;
+ current_idx += 1;
+ Literal::usize_unsuffixed(this_index)
+ })
+ .collect();
+
+ // Borrow variant_indexes because we need to use it multiple times inside the quote! macro
+ let variant_indexes_ref = &variant_indexes;
+
+ // A vector of EnumName::VariantName tokens for this enum
+ let variant_paths: Vec<TokenStream> = self
+ .variants
+ .iter()
+ .map(|v| quote!(#name::#v).into_token_stream())
+ .collect();
+
+ // Borrow variant_paths because we need to use it multiple times inside the quote! macro
+ let variant_paths_ref = &variant_paths;
+
+ (quote! {
+ #(#attrs)*
+ #vis enum #name {
+ #(#variants = #variant_indexes_ref,)*
+ #[automatically_derived]
+ #[doc(hidden)]
+ __Nonexhaustive,
+ }
+
+ #[automatically_derived]
+ impl #name {
+ fn from_str(s: &str) -> Option<#name> {
+ match s {
+ #(#variant_strings => Some(#variant_paths_ref),)*
+ _ => None,
+ }
+ }
+
+ fn to_str(&self) -> &'static str {
+ match self {
+ #(#variant_paths_ref => #variant_strings,)*
+ #name::__Nonexhaustive => panic!(#expect_string),
+ }
+ }
+
+ #vis fn from_js_value(obj: &wasm_bindgen::JsValue) -> Option<#name> {
+ obj.as_string().and_then(|obj_str| Self::from_str(obj_str.as_str()))
+ }
+ }
+
+ // It should really be using &str for all of these, but that requires some major changes to cli-support
+ #[automatically_derived]
+ impl wasm_bindgen::describe::WasmDescribe for #name {
+ fn describe() {
+ <wasm_bindgen::JsValue as wasm_bindgen::describe::WasmDescribe>::describe()
+ }
+ }
+
+ #[automatically_derived]
+ impl wasm_bindgen::convert::IntoWasmAbi for #name {
+ type Abi = <wasm_bindgen::JsValue as wasm_bindgen::convert::IntoWasmAbi>::Abi;
+
+ #[inline]
+ fn into_abi(self) -> Self::Abi {
+ <wasm_bindgen::JsValue as wasm_bindgen::convert::IntoWasmAbi>::into_abi(self.into())
+ }
+ }
+
+ #[automatically_derived]
+ impl wasm_bindgen::convert::FromWasmAbi for #name {
+ type Abi = <wasm_bindgen::JsValue as wasm_bindgen::convert::FromWasmAbi>::Abi;
+
+ unsafe fn from_abi(js: Self::Abi) -> Self {
+ let s = <wasm_bindgen::JsValue as wasm_bindgen::convert::FromWasmAbi>::from_abi(js);
+ #name::from_js_value(&s).unwrap_or(#name::__Nonexhaustive)
+ }
+ }
+
+ #[automatically_derived]
+ impl wasm_bindgen::convert::OptionIntoWasmAbi for #name {
+ #[inline]
+ fn none() -> Self::Abi { <::js_sys::Object as wasm_bindgen::convert::OptionIntoWasmAbi>::none() }
+ }
+
+ #[automatically_derived]
+ impl wasm_bindgen::convert::OptionFromWasmAbi for #name {
+ #[inline]
+ fn is_none(abi: &Self::Abi) -> bool { <::js_sys::Object as wasm_bindgen::convert::OptionFromWasmAbi>::is_none(abi) }
+ }
+
+ #[automatically_derived]
+ impl From<#name> for wasm_bindgen::JsValue {
+ fn from(obj: #name) -> wasm_bindgen::JsValue {
+ wasm_bindgen::JsValue::from(obj.to_str())
+ }
+ }
+ }).to_tokens(tokens);
+ }
+}
+
+impl TryToTokens for ast::ImportFunction {
+ fn try_to_tokens(&self, tokens: &mut TokenStream) -> Result<(), Diagnostic> {
+ let mut class_ty = None;
+ let mut is_method = false;
+ match self.kind {
+ ast::ImportFunctionKind::Method {
+ ref ty, ref kind, ..
+ } => {
+ if let ast::MethodKind::Operation(ast::Operation {
+ is_static: false, ..
+ }) = kind
+ {
+ is_method = true;
+ }
+ class_ty = Some(ty);
+ }
+ ast::ImportFunctionKind::Normal => {}
+ }
+ let vis = &self.function.rust_vis;
+ let ret = match &self.function.ret {
+ Some(ty) => quote! { -> #ty },
+ None => quote!(),
+ };
+
+ let mut abi_argument_names = Vec::new();
+ let mut abi_arguments = Vec::new();
+ let mut arg_conversions = Vec::new();
+ let mut arguments = Vec::new();
+ let ret_ident = Ident::new("_ret", Span::call_site());
+
+ for (i, arg) in self.function.arguments.iter().enumerate() {
+ let ty = &arg.ty;
+ let name = match &*arg.pat {
+ syn::Pat::Ident(syn::PatIdent {
+ by_ref: None,
+ ident,
+ subpat: None,
+ ..
+ }) => ident.clone(),
+ syn::Pat::Wild(_) => syn::Ident::new(&format!("__genarg_{}", i), Span::call_site()),
+ _ => bail_span!(
+ arg.pat,
+ "unsupported pattern in #[wasm_bindgen] imported function",
+ ),
+ };
+
+ abi_argument_names.push(name.clone());
+ abi_arguments.push(quote! {
+ #name: <#ty as wasm_bindgen::convert::IntoWasmAbi>::Abi
+ });
+ let var = if i == 0 && is_method {
+ quote! { self }
+ } else {
+ arguments.push(quote! { #name: #ty });
+ quote! { #name }
+ };
+ arg_conversions.push(quote! {
+ let #name = <#ty as wasm_bindgen::convert::IntoWasmAbi>
+ ::into_abi(#var);
+ });
+ }
+ let abi_ret;
+ let mut convert_ret;
+ match &self.js_ret {
+ Some(syn::Type::Reference(_)) => {
+ bail_span!(
+ self.js_ret,
+ "cannot return references in #[wasm_bindgen] imports yet"
+ );
+ }
+ Some(ref ty) => {
+ if self.function.r#async {
+ abi_ret =
+ quote! { <js_sys::Promise as wasm_bindgen::convert::FromWasmAbi>::Abi };
+ let future = quote! {
+ wasm_bindgen_futures::JsFuture::from(
+ <js_sys::Promise as wasm_bindgen::convert::FromWasmAbi>
+ ::from_abi(#ret_ident)
+ ).await
+ };
+ convert_ret = if self.catch {
+ quote! { Ok(#future?) }
+ } else {
+ quote! { #future.expect("unexpected exception") }
+ };
+ } else {
+ abi_ret = quote! {
+ <#ty as wasm_bindgen::convert::FromWasmAbi>::Abi
+ };
+ convert_ret = quote! {
+ <#ty as wasm_bindgen::convert::FromWasmAbi>
+ ::from_abi(#ret_ident)
+ };
+ }
+ }
+ None => {
+ if self.function.r#async {
+ abi_ret =
+ quote! { <js_sys::Promise as wasm_bindgen::convert::FromWasmAbi>::Abi };
+ let future = quote! {
+ wasm_bindgen_futures::JsFuture::from(
+ <js_sys::Promise as wasm_bindgen::convert::FromWasmAbi>
+ ::from_abi(#ret_ident)
+ ).await
+ };
+ convert_ret = if self.catch {
+ quote! { #future?; Ok(()) }
+ } else {
+ quote! { #future.expect("uncaught exception"); }
+ };
+ } else {
+ abi_ret = quote! { () };
+ convert_ret = quote! { () };
+ }
+ }
+ }
+
+ let mut exceptional_ret = quote!();
+ if self.catch && !self.function.r#async {
+ convert_ret = quote! { Ok(#convert_ret) };
+ exceptional_ret = quote! {
+ wasm_bindgen::__rt::take_last_exception()?;
+ };
+ }
+
+ let rust_name = &self.rust_name;
+ let import_name = &self.shim;
+ let attrs = &self.function.rust_attrs;
+ let arguments = &arguments;
+ let abi_arguments = &abi_arguments;
+ let abi_argument_names = &abi_argument_names;
+
+ let doc_comment = &self.doc_comment;
+ let me = if is_method {
+ quote! { &self, }
+ } else {
+ quote!()
+ };
+
+ // Route any errors pointing to this imported function to the identifier
+ // of the function we're imported from so we at least know what function
+ // is causing issues.
+ //
+ // Note that this is where type errors like "doesn't implement
+ // FromWasmAbi" or "doesn't implement IntoWasmAbi" currently get routed.
+ // I suspect that's because they show up in the signature via trait
+ // projections as types of arguments, and all that needs to typecheck
+ // before the body can be typechecked. Due to rust-lang/rust#60980 (and
+ // probably related issues) we can't really get a precise span.
+ //
+ // Ideally what we want is to point errors for particular types back to
+ // the specific argument/type that generated the error, but it looks
+ // like rustc itself doesn't do great in that regard so let's just do
+ // the best we can in the meantime.
+ let extern_fn = respan(
+ quote! {
+ #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
+ #(#attrs)*
+ #[link(wasm_import_module = "__wbindgen_placeholder__")]
+ extern "C" {
+ fn #import_name(#(#abi_arguments),*) -> #abi_ret;
+ }
+
+ #[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))]
+ unsafe fn #import_name(#(#abi_arguments),*) -> #abi_ret {
+ #(
+ drop(#abi_argument_names);
+ )*
+ panic!("cannot call wasm-bindgen imported functions on \
+ non-wasm targets");
+ }
+ },
+ &self.rust_name,
+ );
+
+ let maybe_async = if self.function.r#async {
+ Some(quote! {async})
+ } else {
+ None
+ };
+ let invocation = quote! {
+ // This is due to `#[automatically_derived]` attribute cannot be
+ // placed onto bare functions.
+ #[allow(nonstandard_style)]
+ #[allow(clippy::all, clippy::nursery, clippy::pedantic, clippy::restriction)]
+ #(#attrs)*
+ #[doc = #doc_comment]
+ #vis #maybe_async fn #rust_name(#me #(#arguments),*) #ret {
+ #extern_fn
+
+ unsafe {
+ let #ret_ident = {
+ #(#arg_conversions)*
+ #import_name(#(#abi_argument_names),*)
+ };
+ #exceptional_ret
+ #convert_ret
+ }
+ }
+ };
+
+ if let Some(class) = class_ty {
+ (quote! {
+ #[automatically_derived]
+ impl #class {
+ #invocation
+ }
+ })
+ .to_tokens(tokens);
+ } else {
+ invocation.to_tokens(tokens);
+ }
+
+ Ok(())
+ }
+}
+
+// See comment above in ast::Export for what's going on here.
+struct DescribeImport<'a> {
+ kind: &'a ast::ImportKind,
+}
+
+impl<'a> ToTokens for DescribeImport<'a> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ let f = match *self.kind {
+ ast::ImportKind::Function(ref f) => f,
+ ast::ImportKind::Static(_) => return,
+ ast::ImportKind::Type(_) => return,
+ ast::ImportKind::Enum(_) => return,
+ };
+ let argtys = f.function.arguments.iter().map(|arg| &arg.ty);
+ let nargs = f.function.arguments.len() as u32;
+ let inform_ret = match &f.js_ret {
+ Some(ref t) => quote! { <#t as WasmDescribe>::describe(); },
+ // async functions always return a JsValue, even if they say to return ()
+ None if f.function.r#async => quote! { <JsValue as WasmDescribe>::describe(); },
+ None => quote! { <() as WasmDescribe>::describe(); },
+ };
+
+ Descriptor {
+ ident: &f.shim,
+ inner: quote! {
+ inform(FUNCTION);
+ inform(0);
+ inform(#nargs);
+ #(<#argtys as WasmDescribe>::describe();)*
+ #inform_ret
+ #inform_ret
+ },
+ attrs: f.function.rust_attrs.clone(),
+ }
+ .to_tokens(tokens);
+ }
+}
+
+impl ToTokens for ast::Enum {
+ fn to_tokens(&self, into: &mut TokenStream) {
+ let enum_name = &self.rust_name;
+ let hole = &self.hole;
+ let cast_clauses = self.variants.iter().map(|variant| {
+ let variant_name = &variant.name;
+ quote! {
+ if js == #enum_name::#variant_name as u32 {
+ #enum_name::#variant_name
+ }
+ }
+ });
+ (quote! {
+ #[automatically_derived]
+ impl wasm_bindgen::convert::IntoWasmAbi for #enum_name {
+ type Abi = u32;
+
+ #[inline]
+ fn into_abi(self) -> u32 {
+ self as u32
+ }
+ }
+
+ #[automatically_derived]
+ impl wasm_bindgen::convert::FromWasmAbi for #enum_name {
+ type Abi = u32;
+
+ #[inline]
+ unsafe fn from_abi(js: u32) -> Self {
+ #(#cast_clauses else)* {
+ wasm_bindgen::throw_str("invalid enum value passed")
+ }
+ }
+ }
+
+ #[automatically_derived]
+ impl wasm_bindgen::convert::OptionFromWasmAbi for #enum_name {
+ #[inline]
+ fn is_none(val: &u32) -> bool { *val == #hole }
+ }
+
+ #[automatically_derived]
+ impl wasm_bindgen::convert::OptionIntoWasmAbi for #enum_name {
+ #[inline]
+ fn none() -> Self::Abi { #hole }
+ }
+
+ #[automatically_derived]
+ impl wasm_bindgen::describe::WasmDescribe for #enum_name {
+ fn describe() {
+ use wasm_bindgen::describe::*;
+ inform(ENUM);
+ inform(#hole);
+ }
+ }
+ })
+ .to_tokens(into);
+ }
+}
+
+impl ToTokens for ast::ImportStatic {
+ fn to_tokens(&self, into: &mut TokenStream) {
+ let name = &self.rust_name;
+ let ty = &self.ty;
+ let shim_name = &self.shim;
+ let vis = &self.vis;
+ (quote! {
+ #[automatically_derived]
+ #vis static #name: wasm_bindgen::JsStatic<#ty> = {
+ fn init() -> #ty {
+ #[link(wasm_import_module = "__wbindgen_placeholder__")]
+ #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
+ extern "C" {
+ fn #shim_name() -> <#ty as wasm_bindgen::convert::FromWasmAbi>::Abi;
+ }
+ #[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))]
+ unsafe fn #shim_name() -> <#ty as wasm_bindgen::convert::FromWasmAbi>::Abi {
+ panic!("cannot access imported statics on non-wasm targets")
+ }
+
+ unsafe {
+ <#ty as wasm_bindgen::convert::FromWasmAbi>::from_abi(#shim_name())
+ }
+ }
+ thread_local!(static _VAL: #ty = init(););
+ wasm_bindgen::JsStatic {
+ __inner: &_VAL,
+ }
+ };
+ })
+ .to_tokens(into);
+
+ Descriptor {
+ ident: &shim_name,
+ inner: quote! {
+ <#ty as WasmDescribe>::describe();
+ },
+ attrs: vec![],
+ }
+ .to_tokens(into);
+ }
+}
+
+/// Emits the necessary glue tokens for "descriptor", generating an appropriate
+/// symbol name as well as attributes around the descriptor function itself.
+struct Descriptor<'a, T> {
+ ident: &'a Ident,
+ inner: T,
+ attrs: Vec<syn::Attribute>,
+}
+
+impl<'a, T: ToTokens> ToTokens for Descriptor<'a, T> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ // It's possible for the same descriptor to be emitted in two different
+ // modules (aka a value imported twice in a crate, each in a separate
+ // module). In this case no need to emit duplicate descriptors (which
+ // leads to duplicate symbol errors), instead just emit one.
+ //
+ // It's up to the descriptors themselves to ensure they have unique
+ // names for unique items imported, currently done via `ShortHash` and
+ // hashing appropriate data into the symbol name.
+ static DESCRIPTORS_EMITTED: Lazy<Mutex<HashSet<String>>> = Lazy::new(Default::default);
+
+ let ident = self.ident;
+
+ if !DESCRIPTORS_EMITTED
+ .lock()
+ .unwrap()
+ .insert(ident.to_string())
+ {
+ return;
+ }
+
+ let name = Ident::new(&format!("__wbindgen_describe_{}", ident), ident.span());
+ let const_name = Ident::new(
+ &format!("__wbindgen_const_describe_{}", ident),
+ ident.span(),
+ );
+ let inner = &self.inner;
+ let attrs = &self.attrs;
+ (quote! {
+ #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
+ #[automatically_derived]
+ const #const_name: () = {
+ #(#attrs)*
+ #[no_mangle]
+ #[doc(hidden)]
+ pub extern "C" fn #name() {
+ use wasm_bindgen::describe::*;
+ // See definition of `link_mem_intrinsics` for what this is doing
+ wasm_bindgen::__rt::link_mem_intrinsics();
+ #inner
+ }
+ };
+ })
+ .to_tokens(tokens);
+ }
+}
+
+/// Converts `span` into a stream of tokens, and attempts to ensure that `input`
+/// has all the appropriate span information so errors in it point to `span`.
+fn respan(input: TokenStream, span: &dyn ToTokens) -> TokenStream {
+ let mut first_span = Span::call_site();
+ let mut last_span = Span::call_site();
+ let mut spans = TokenStream::new();
+ span.to_tokens(&mut spans);
+
+ for (i, token) in spans.into_iter().enumerate() {
+ if i == 0 {
+ first_span = token.span();
+ }
+ last_span = token.span();
+ }
+
+ let mut new_tokens = Vec::new();
+ for (i, mut token) in input.into_iter().enumerate() {
+ if i == 0 {
+ token.set_span(first_span);
+ } else {
+ token.set_span(last_span);
+ }
+ new_tokens.push(token);
+ }
+ new_tokens.into_iter().collect()
+}
diff --git a/vendor/wasm-bindgen-backend/src/encode.rs b/vendor/wasm-bindgen-backend/src/encode.rs
new file mode 100644
index 000000000..41d3c8b77
--- /dev/null
+++ b/vendor/wasm-bindgen-backend/src/encode.rs
@@ -0,0 +1,536 @@
+use crate::util::ShortHash;
+use proc_macro2::{Ident, Span};
+use std::cell::{Cell, RefCell};
+use std::collections::HashMap;
+use std::env;
+use std::fs;
+use std::path::PathBuf;
+
+use crate::ast;
+use crate::Diagnostic;
+
+pub struct EncodeResult {
+ pub custom_section: Vec<u8>,
+ pub included_files: Vec<PathBuf>,
+}
+
+pub fn encode(program: &ast::Program) -> Result<EncodeResult, Diagnostic> {
+ let mut e = Encoder::new();
+ let i = Interner::new();
+ shared_program(program, &i)?.encode(&mut e);
+ let custom_section = e.finish();
+ let included_files = i
+ .files
+ .borrow()
+ .values()
+ .map(|p| &p.path)
+ .cloned()
+ .collect();
+ Ok(EncodeResult {
+ custom_section,
+ included_files,
+ })
+}
+
+struct Interner {
+ bump: bumpalo::Bump,
+ files: RefCell<HashMap<String, LocalFile>>,
+ root: PathBuf,
+ crate_name: String,
+ has_package_json: Cell<bool>,
+}
+
+struct LocalFile {
+ path: PathBuf,
+ definition: Span,
+ new_identifier: String,
+}
+
+impl Interner {
+ fn new() -> Interner {
+ let root = env::var_os("CARGO_MANIFEST_DIR")
+ .expect("should have CARGO_MANIFEST_DIR env var")
+ .into();
+ let crate_name = env::var("CARGO_PKG_NAME").expect("should have CARGO_PKG_NAME env var");
+ Interner {
+ bump: bumpalo::Bump::new(),
+ files: RefCell::new(HashMap::new()),
+ root,
+ crate_name,
+ has_package_json: Cell::new(false),
+ }
+ }
+
+ fn intern(&self, s: &Ident) -> &str {
+ self.intern_str(&s.to_string())
+ }
+
+ fn intern_str(&self, s: &str) -> &str {
+ // NB: eventually this could be used to intern `s` to only allocate one
+ // copy, but for now let's just "transmute" `s` to have the same
+ // lifetime as this struct itself (which is our main goal here)
+ self.bump.alloc_str(s)
+ }
+
+ /// Given an import to a local module `id` this generates a unique module id
+ /// to assign to the contents of `id`.
+ ///
+ /// Note that repeated invocations of this function will be memoized, so the
+ /// same `id` will always return the same resulting unique `id`.
+ fn resolve_import_module(&self, id: &str, span: Span) -> Result<ImportModule, Diagnostic> {
+ let mut files = self.files.borrow_mut();
+ if let Some(file) = files.get(id) {
+ return Ok(ImportModule::Named(self.intern_str(&file.new_identifier)));
+ }
+ self.check_for_package_json();
+ let path = if id.starts_with("/") {
+ self.root.join(&id[1..])
+ } else if id.starts_with("./") || id.starts_with("../") {
+ let msg = "relative module paths aren't supported yet";
+ return Err(Diagnostic::span_error(span, msg));
+ } else {
+ return Ok(ImportModule::RawNamed(self.intern_str(id)));
+ };
+
+ // Generate a unique ID which is somewhat readable as well, so mix in
+ // the crate name, hash to make it unique, and then the original path.
+ let new_identifier = format!("{}{}", self.unique_crate_identifier(), id);
+ let file = LocalFile {
+ path,
+ definition: span,
+ new_identifier,
+ };
+ files.insert(id.to_string(), file);
+ drop(files);
+ self.resolve_import_module(id, span)
+ }
+
+ fn unique_crate_identifier(&self) -> String {
+ format!("{}-{}", self.crate_name, ShortHash(0))
+ }
+
+ fn check_for_package_json(&self) {
+ if self.has_package_json.get() {
+ return;
+ }
+ let path = self.root.join("package.json");
+ if path.exists() {
+ self.has_package_json.set(true);
+ }
+ }
+}
+
+fn shared_program<'a>(
+ prog: &'a ast::Program,
+ intern: &'a Interner,
+) -> Result<Program<'a>, Diagnostic> {
+ Ok(Program {
+ exports: prog
+ .exports
+ .iter()
+ .map(|a| shared_export(a, intern))
+ .collect::<Result<Vec<_>, _>>()?,
+ structs: prog
+ .structs
+ .iter()
+ .map(|a| shared_struct(a, intern))
+ .collect(),
+ enums: prog.enums.iter().map(|a| shared_enum(a, intern)).collect(),
+ imports: prog
+ .imports
+ .iter()
+ .map(|a| shared_import(a, intern))
+ .collect::<Result<Vec<_>, _>>()?,
+ typescript_custom_sections: prog
+ .typescript_custom_sections
+ .iter()
+ .map(|x| -> &'a str { &x })
+ .collect(),
+ local_modules: intern
+ .files
+ .borrow()
+ .values()
+ .map(|file| {
+ fs::read_to_string(&file.path)
+ .map(|s| LocalModule {
+ identifier: intern.intern_str(&file.new_identifier),
+ contents: intern.intern_str(&s),
+ })
+ .map_err(|e| {
+ let msg = format!("failed to read file `{}`: {}", file.path.display(), e);
+ Diagnostic::span_error(file.definition, msg)
+ })
+ })
+ .collect::<Result<Vec<_>, _>>()?,
+ inline_js: prog
+ .inline_js
+ .iter()
+ .map(|js| intern.intern_str(js))
+ .collect(),
+ unique_crate_identifier: intern.intern_str(&intern.unique_crate_identifier()),
+ package_json: if intern.has_package_json.get() {
+ Some(intern.intern_str(intern.root.join("package.json").to_str().unwrap()))
+ } else {
+ None
+ },
+ })
+}
+
+fn shared_export<'a>(
+ export: &'a ast::Export,
+ intern: &'a Interner,
+) -> Result<Export<'a>, Diagnostic> {
+ let consumed = match export.method_self {
+ Some(ast::MethodSelf::ByValue) => true,
+ _ => false,
+ };
+ let method_kind = from_ast_method_kind(&export.function, intern, &export.method_kind)?;
+ Ok(Export {
+ class: export.js_class.as_ref().map(|s| &**s),
+ comments: export.comments.iter().map(|s| &**s).collect(),
+ consumed,
+ function: shared_function(&export.function, intern),
+ method_kind,
+ start: export.start,
+ })
+}
+
+fn shared_function<'a>(func: &'a ast::Function, _intern: &'a Interner) -> Function<'a> {
+ let arg_names = func
+ .arguments
+ .iter()
+ .enumerate()
+ .map(|(idx, arg)| {
+ if let syn::Pat::Ident(x) = &*arg.pat {
+ return x.ident.to_string();
+ }
+ format!("arg{}", idx)
+ })
+ .collect::<Vec<_>>();
+ Function {
+ arg_names,
+ asyncness: func.r#async,
+ name: &func.name,
+ generate_typescript: func.generate_typescript,
+ variadic: func.variadic,
+ }
+}
+
+fn shared_enum<'a>(e: &'a ast::Enum, intern: &'a Interner) -> Enum<'a> {
+ Enum {
+ name: &e.js_name,
+ variants: e
+ .variants
+ .iter()
+ .map(|v| shared_variant(v, intern))
+ .collect(),
+ comments: e.comments.iter().map(|s| &**s).collect(),
+ generate_typescript: e.generate_typescript,
+ }
+}
+
+fn shared_variant<'a>(v: &'a ast::Variant, intern: &'a Interner) -> EnumVariant<'a> {
+ EnumVariant {
+ name: intern.intern(&v.name),
+ value: v.value,
+ comments: v.comments.iter().map(|s| &**s).collect(),
+ }
+}
+
+fn shared_import<'a>(i: &'a ast::Import, intern: &'a Interner) -> Result<Import<'a>, Diagnostic> {
+ Ok(Import {
+ module: i
+ .module
+ .as_ref()
+ .map(|m| shared_module(m, intern))
+ .transpose()?,
+ js_namespace: i.js_namespace.clone(),
+ kind: shared_import_kind(&i.kind, intern)?,
+ })
+}
+
+fn shared_module<'a>(
+ m: &'a ast::ImportModule,
+ intern: &'a Interner,
+) -> Result<ImportModule<'a>, Diagnostic> {
+ Ok(match m {
+ ast::ImportModule::Named(m, span) => intern.resolve_import_module(m, *span)?,
+ ast::ImportModule::RawNamed(m, _span) => ImportModule::RawNamed(intern.intern_str(m)),
+ ast::ImportModule::Inline(idx, _) => ImportModule::Inline(*idx as u32),
+ })
+}
+
+fn shared_import_kind<'a>(
+ i: &'a ast::ImportKind,
+ intern: &'a Interner,
+) -> Result<ImportKind<'a>, Diagnostic> {
+ Ok(match i {
+ ast::ImportKind::Function(f) => ImportKind::Function(shared_import_function(f, intern)?),
+ ast::ImportKind::Static(f) => ImportKind::Static(shared_import_static(f, intern)),
+ ast::ImportKind::Type(f) => ImportKind::Type(shared_import_type(f, intern)),
+ ast::ImportKind::Enum(f) => ImportKind::Enum(shared_import_enum(f, intern)),
+ })
+}
+
+fn shared_import_function<'a>(
+ i: &'a ast::ImportFunction,
+ intern: &'a Interner,
+) -> Result<ImportFunction<'a>, Diagnostic> {
+ let method = match &i.kind {
+ ast::ImportFunctionKind::Method { class, kind, .. } => {
+ let kind = from_ast_method_kind(&i.function, intern, kind)?;
+ Some(MethodData { class, kind })
+ }
+ ast::ImportFunctionKind::Normal => None,
+ };
+
+ Ok(ImportFunction {
+ shim: intern.intern(&i.shim),
+ catch: i.catch,
+ method,
+ assert_no_shim: i.assert_no_shim,
+ structural: i.structural,
+ function: shared_function(&i.function, intern),
+ variadic: i.variadic,
+ })
+}
+
+fn shared_import_static<'a>(i: &'a ast::ImportStatic, intern: &'a Interner) -> ImportStatic<'a> {
+ ImportStatic {
+ name: &i.js_name,
+ shim: intern.intern(&i.shim),
+ }
+}
+
+fn shared_import_type<'a>(i: &'a ast::ImportType, intern: &'a Interner) -> ImportType<'a> {
+ ImportType {
+ name: &i.js_name,
+ instanceof_shim: &i.instanceof_shim,
+ vendor_prefixes: i.vendor_prefixes.iter().map(|x| intern.intern(x)).collect(),
+ }
+}
+
+fn shared_import_enum<'a>(_i: &'a ast::ImportEnum, _intern: &'a Interner) -> ImportEnum {
+ ImportEnum {}
+}
+
+fn shared_struct<'a>(s: &'a ast::Struct, intern: &'a Interner) -> Struct<'a> {
+ Struct {
+ name: &s.js_name,
+ fields: s
+ .fields
+ .iter()
+ .map(|s| shared_struct_field(s, intern))
+ .collect(),
+ comments: s.comments.iter().map(|s| &**s).collect(),
+ is_inspectable: s.is_inspectable,
+ generate_typescript: s.generate_typescript,
+ }
+}
+
+fn shared_struct_field<'a>(s: &'a ast::StructField, _intern: &'a Interner) -> StructField<'a> {
+ StructField {
+ name: &s.js_name,
+ readonly: s.readonly,
+ comments: s.comments.iter().map(|s| &**s).collect(),
+ generate_typescript: s.generate_typescript,
+ }
+}
+
+trait Encode {
+ fn encode(&self, dst: &mut Encoder);
+}
+
+struct Encoder {
+ dst: Vec<u8>,
+}
+
+impl Encoder {
+ fn new() -> Encoder {
+ Encoder {
+ dst: vec![0, 0, 0, 0],
+ }
+ }
+
+ fn finish(mut self) -> Vec<u8> {
+ let len = (self.dst.len() - 4) as u32;
+ self.dst[..4].copy_from_slice(&len.to_le_bytes()[..]);
+ self.dst
+ }
+
+ fn byte(&mut self, byte: u8) {
+ self.dst.push(byte);
+ }
+}
+
+impl Encode for bool {
+ fn encode(&self, dst: &mut Encoder) {
+ dst.byte(*self as u8);
+ }
+}
+
+impl Encode for u32 {
+ fn encode(&self, dst: &mut Encoder) {
+ let mut val = *self;
+ while (val >> 7) != 0 {
+ dst.byte((val as u8) | 0x80);
+ val >>= 7;
+ }
+ assert_eq!(val >> 7, 0);
+ dst.byte(val as u8);
+ }
+}
+
+impl Encode for usize {
+ fn encode(&self, dst: &mut Encoder) {
+ assert!(*self <= u32::max_value() as usize);
+ (*self as u32).encode(dst);
+ }
+}
+
+impl<'a> Encode for &'a [u8] {
+ fn encode(&self, dst: &mut Encoder) {
+ self.len().encode(dst);
+ dst.dst.extend_from_slice(*self);
+ }
+}
+
+impl<'a> Encode for &'a str {
+ fn encode(&self, dst: &mut Encoder) {
+ self.as_bytes().encode(dst);
+ }
+}
+
+impl<'a> Encode for String {
+ fn encode(&self, dst: &mut Encoder) {
+ self.as_bytes().encode(dst);
+ }
+}
+
+impl<T: Encode> Encode for Vec<T> {
+ fn encode(&self, dst: &mut Encoder) {
+ self.len().encode(dst);
+ for item in self {
+ item.encode(dst);
+ }
+ }
+}
+
+impl<T: Encode> Encode for Option<T> {
+ fn encode(&self, dst: &mut Encoder) {
+ match self {
+ None => dst.byte(0),
+ Some(val) => {
+ dst.byte(1);
+ val.encode(dst)
+ }
+ }
+ }
+}
+
+macro_rules! encode_struct {
+ ($name:ident ($($lt:tt)*) $($field:ident: $ty:ty,)*) => {
+ struct $name $($lt)* {
+ $($field: $ty,)*
+ }
+
+ impl $($lt)* Encode for $name $($lt)* {
+ fn encode(&self, _dst: &mut Encoder) {
+ $(self.$field.encode(_dst);)*
+ }
+ }
+ }
+}
+
+macro_rules! encode_enum {
+ ($name:ident ($($lt:tt)*) $($fields:tt)*) => (
+ enum $name $($lt)* { $($fields)* }
+
+ impl$($lt)* Encode for $name $($lt)* {
+ fn encode(&self, dst: &mut Encoder) {
+ use self::$name::*;
+ encode_enum!(@arms self dst (0) () $($fields)*)
+ }
+ }
+ );
+
+ (@arms $me:ident $dst:ident ($cnt:expr) ($($arms:tt)*)) => (
+ encode_enum!(@expr match $me { $($arms)* })
+ );
+
+ (@arms $me:ident $dst:ident ($cnt:expr) ($($arms:tt)*) $name:ident, $($rest:tt)*) => (
+ encode_enum!(
+ @arms
+ $me
+ $dst
+ ($cnt+1)
+ ($($arms)* $name => $dst.byte($cnt),)
+ $($rest)*
+ )
+ );
+
+ (@arms $me:ident $dst:ident ($cnt:expr) ($($arms:tt)*) $name:ident($t:ty), $($rest:tt)*) => (
+ encode_enum!(
+ @arms
+ $me
+ $dst
+ ($cnt+1)
+ ($($arms)* $name(val) => { $dst.byte($cnt); val.encode($dst) })
+ $($rest)*
+ )
+ );
+
+ (@expr $e:expr) => ($e);
+}
+
+macro_rules! encode_api {
+ () => ();
+ (struct $name:ident<'a> { $($fields:tt)* } $($rest:tt)*) => (
+ encode_struct!($name (<'a>) $($fields)*);
+ encode_api!($($rest)*);
+ );
+ (struct $name:ident { $($fields:tt)* } $($rest:tt)*) => (
+ encode_struct!($name () $($fields)*);
+ encode_api!($($rest)*);
+ );
+ (enum $name:ident<'a> { $($variants:tt)* } $($rest:tt)*) => (
+ encode_enum!($name (<'a>) $($variants)*);
+ encode_api!($($rest)*);
+ );
+ (enum $name:ident { $($variants:tt)* } $($rest:tt)*) => (
+ encode_enum!($name () $($variants)*);
+ encode_api!($($rest)*);
+ );
+}
+wasm_bindgen_shared::shared_api!(encode_api);
+
+fn from_ast_method_kind<'a>(
+ function: &'a ast::Function,
+ intern: &'a Interner,
+ method_kind: &'a ast::MethodKind,
+) -> Result<MethodKind<'a>, Diagnostic> {
+ Ok(match method_kind {
+ ast::MethodKind::Constructor => MethodKind::Constructor,
+ ast::MethodKind::Operation(ast::Operation { is_static, kind }) => {
+ let is_static = *is_static;
+ let kind = match kind {
+ ast::OperationKind::Getter(g) => {
+ let g = g.as_ref().map(|g| intern.intern(g));
+ OperationKind::Getter(g.unwrap_or_else(|| function.infer_getter_property()))
+ }
+ ast::OperationKind::Regular => OperationKind::Regular,
+ ast::OperationKind::Setter(s) => {
+ let s = s.as_ref().map(|s| intern.intern(s));
+ OperationKind::Setter(match s {
+ Some(s) => s,
+ None => intern.intern_str(&function.infer_setter_property()?),
+ })
+ }
+ ast::OperationKind::IndexingGetter => OperationKind::IndexingGetter,
+ ast::OperationKind::IndexingSetter => OperationKind::IndexingSetter,
+ ast::OperationKind::IndexingDeleter => OperationKind::IndexingDeleter,
+ };
+ MethodKind::Operation(Operation { is_static, kind })
+ }
+ })
+}
diff --git a/vendor/wasm-bindgen-backend/src/error.rs b/vendor/wasm-bindgen-backend/src/error.rs
new file mode 100644
index 000000000..3e65cd745
--- /dev/null
+++ b/vendor/wasm-bindgen-backend/src/error.rs
@@ -0,0 +1,134 @@
+use proc_macro2::*;
+use quote::{ToTokens, TokenStreamExt};
+use syn::parse::Error;
+
+/// Provide a Diagnostic with the given span and message
+#[macro_export]
+macro_rules! err_span {
+ ($span:expr, $($msg:tt)*) => (
+ $crate::Diagnostic::spanned_error(&$span, format!($($msg)*))
+ )
+}
+
+/// Immediately fail and return an Err, with the arguments passed to err_span!
+#[macro_export]
+macro_rules! bail_span {
+ ($($t:tt)*) => (
+ return Err(err_span!($($t)*).into())
+ )
+}
+
+/// A struct representing a diagnostic to emit to the end-user as an error.
+#[derive(Debug)]
+pub struct Diagnostic {
+ inner: Repr,
+}
+
+#[derive(Debug)]
+enum Repr {
+ Single {
+ text: String,
+ span: Option<(Span, Span)>,
+ },
+ SynError(Error),
+ Multi {
+ diagnostics: Vec<Diagnostic>,
+ },
+}
+
+impl Diagnostic {
+ /// Generate a `Diagnostic` from an informational message with no Span
+ pub fn error<T: Into<String>>(text: T) -> Diagnostic {
+ Diagnostic {
+ inner: Repr::Single {
+ text: text.into(),
+ span: None,
+ },
+ }
+ }
+
+ /// Generate a `Diagnostic` from a Span and an informational message
+ pub fn span_error<T: Into<String>>(span: Span, text: T) -> Diagnostic {
+ Diagnostic {
+ inner: Repr::Single {
+ text: text.into(),
+ span: Some((span, span)),
+ },
+ }
+ }
+
+ /// Generate a `Diagnostic` from the span of any tokenizable object and a message
+ pub fn spanned_error<T: Into<String>>(node: &dyn ToTokens, text: T) -> Diagnostic {
+ Diagnostic {
+ inner: Repr::Single {
+ text: text.into(),
+ span: extract_spans(node),
+ },
+ }
+ }
+
+ /// Attempt to generate a `Diagnostic` from a vector of other `Diagnostic` instances.
+ /// If the `Vec` is empty, returns `Ok(())`, otherwise returns the new `Diagnostic`
+ pub fn from_vec(diagnostics: Vec<Diagnostic>) -> Result<(), Diagnostic> {
+ if diagnostics.len() == 0 {
+ Ok(())
+ } else {
+ Err(Diagnostic {
+ inner: Repr::Multi { diagnostics },
+ })
+ }
+ }
+
+ /// Immediately trigger a panic from this `Diagnostic`
+ #[allow(unconditional_recursion)]
+ pub fn panic(&self) -> ! {
+ match &self.inner {
+ Repr::Single { text, .. } => panic!("{}", text),
+ Repr::SynError(error) => panic!("{}", error),
+ Repr::Multi { diagnostics } => diagnostics[0].panic(),
+ }
+ }
+}
+
+impl From<Error> for Diagnostic {
+ fn from(err: Error) -> Diagnostic {
+ Diagnostic {
+ inner: Repr::SynError(err),
+ }
+ }
+}
+
+fn extract_spans(node: &dyn ToTokens) -> Option<(Span, Span)> {
+ let mut t = TokenStream::new();
+ node.to_tokens(&mut t);
+ let mut tokens = t.into_iter();
+ let start = tokens.next().map(|t| t.span());
+ let end = tokens.last().map(|t| t.span());
+ start.map(|start| (start, end.unwrap_or(start)))
+}
+
+impl ToTokens for Diagnostic {
+ fn to_tokens(&self, dst: &mut TokenStream) {
+ match &self.inner {
+ Repr::Single { text, span } => {
+ let cs2 = (Span::call_site(), Span::call_site());
+ let (start, end) = span.unwrap_or(cs2);
+ dst.append(Ident::new("compile_error", start));
+ dst.append(Punct::new('!', Spacing::Alone));
+ let mut message = TokenStream::new();
+ message.append(Literal::string(text));
+ let mut group = Group::new(Delimiter::Brace, message);
+ group.set_span(end);
+ dst.append(group);
+ }
+ Repr::Multi { diagnostics } => {
+ for diagnostic in diagnostics {
+ diagnostic.to_tokens(dst);
+ }
+ }
+ Repr::SynError(err) => {
+ err.to_compile_error().to_tokens(dst);
+ }
+ }
+ }
+}
diff --git a/vendor/wasm-bindgen-backend/src/lib.rs b/vendor/wasm-bindgen-backend/src/lib.rs
new file mode 100644
index 000000000..d9262e857
--- /dev/null
+++ b/vendor/wasm-bindgen-backend/src/lib.rs
@@ -0,0 +1,40 @@
+//! A common backend for bindgen crates.
+//!
+//! This (internal) crate provides functionality common to multiple bindgen
+//! dependency crates. There are 4 main things exported from this crate:
+//!
+//! 1. [**`TryToTokens`**](./trait.TryToTokens.html)
+//!
+//! Provides the ability to attempt conversion from an AST struct
+//! into a TokenStream
+//!
+//! 2. [**`Diagnostic`**](./struct.Diagnostic.html)
+//!
+//! A struct used to provide diagnostic responses for failures of said
+//! tokenization
+//!
+//! 3. [**`ast`**](./ast/index.html)
+//!
+//! Abstract Syntax Tree types used to represent a Rust program, with
+//! the necessary metadata to generate bindings for it
+//!
+//! 4. [**`util`**](./util/index.html)
+//!
+//! Common utilities for manipulating parsed types from syn
+//!
+
+#![recursion_limit = "256"]
+#![cfg_attr(feature = "extra-traits", deny(missing_debug_implementations))]
+#![deny(missing_docs)]
+#![doc(html_root_url = "https://docs.rs/wasm-bindgen-backend/0.2")]
+
+pub use crate::codegen::TryToTokens;
+pub use crate::error::Diagnostic;
+
+#[macro_use]
+mod error;
+
+pub mod ast;
+mod codegen;
+mod encode;
+pub mod util;
diff --git a/vendor/wasm-bindgen-backend/src/util.rs b/vendor/wasm-bindgen-backend/src/util.rs
new file mode 100644
index 000000000..1a2b07dce
--- /dev/null
+++ b/vendor/wasm-bindgen-backend/src/util.rs
@@ -0,0 +1,161 @@
+//! Common utility function for manipulating syn types and
+//! handling parsed values
+
+use std::collections::hash_map::DefaultHasher;
+use std::env;
+use std::fmt;
+use std::hash::{Hash, Hasher};
+use std::iter::FromIterator;
+use std::sync::atomic::AtomicBool;
+use std::sync::atomic::AtomicUsize;
+use std::sync::atomic::Ordering::SeqCst;
+
+use crate::ast;
+use proc_macro2::{self, Ident};
+
+/// Check whether a given `&str` is a Rust keyword
+fn is_rust_keyword(name: &str) -> bool {
+ match name {
+ "abstract" | "alignof" | "as" | "become" | "box" | "break" | "const" | "continue"
+ | "crate" | "do" | "else" | "enum" | "extern" | "false" | "final" | "fn" | "for" | "if"
+ | "impl" | "in" | "let" | "loop" | "macro" | "match" | "mod" | "move" | "mut"
+ | "offsetof" | "override" | "priv" | "proc" | "pub" | "pure" | "ref" | "return"
+ | "Self" | "self" | "sizeof" | "static" | "struct" | "super" | "trait" | "true"
+ | "type" | "typeof" | "unsafe" | "unsized" | "use" | "virtual" | "where" | "while"
+ | "yield" | "bool" | "_" => true,
+ _ => false,
+ }
+}
+
+/// Create an `Ident`, possibly mangling it if it conflicts with a Rust keyword.
+pub fn rust_ident(name: &str) -> Ident {
+ if name == "" {
+ panic!("tried to create empty Ident (from \"\")");
+ } else if is_rust_keyword(name) {
+ Ident::new(&format!("{}_", name), proc_macro2::Span::call_site())
+
+ // we didn't historically have `async` in the `is_rust_keyword` list above,
+ // so for backwards compatibility reasons we need to generate an `async`
+ // identifier as well, but we'll be sure to use a raw identifier to ease
+ // compatibility with the 2018 edition.
+ //
+ // Note, though, that `proc-macro` doesn't support a normal way to create a
+ // raw identifier. To get around that we do some wonky parsing to
+ // roundaboutly create one.
+ } else if name == "async" {
+ let ident = "r#async"
+ .parse::<proc_macro2::TokenStream>()
+ .unwrap()
+ .into_iter()
+ .next()
+ .unwrap();
+ match ident {
+ proc_macro2::TokenTree::Ident(i) => i,
+ _ => unreachable!(),
+ }
+ } else if name.chars().next().unwrap().is_ascii_digit() {
+ Ident::new(&format!("N{}", name), proc_macro2::Span::call_site())
+ } else {
+ raw_ident(name)
+ }
+}
+
+/// Create an `Ident` without checking to see if it conflicts with a Rust
+/// keyword.
+pub fn raw_ident(name: &str) -> Ident {
+ Ident::new(name, proc_macro2::Span::call_site())
+}
+
+/// Create a path type from the given segments. For example an iterator yielding
+/// the idents `[foo, bar, baz]` will result in the path type `foo::bar::baz`.
+pub fn simple_path_ty<I>(segments: I) -> syn::Type
+where
+ I: IntoIterator<Item = Ident>,
+{
+ path_ty(false, segments)
+}
+
+/// Create a global path type from the given segments. For example an iterator
+/// yielding the idents `[foo, bar, baz]` will result in the path type
+/// `::foo::bar::baz`.
+pub fn leading_colon_path_ty<I>(segments: I) -> syn::Type
+where
+ I: IntoIterator<Item = Ident>,
+{
+ path_ty(true, segments)
+}
+
+fn path_ty<I>(leading_colon: bool, segments: I) -> syn::Type
+where
+ I: IntoIterator<Item = Ident>,
+{
+ let segments: Vec<_> = segments
+ .into_iter()
+ .map(|i| syn::PathSegment {
+ ident: i,
+ arguments: syn::PathArguments::None,
+ })
+ .collect();
+
+ syn::TypePath {
+ qself: None,
+ path: syn::Path {
+ leading_colon: if leading_colon {
+ Some(Default::default())
+ } else {
+ None
+ },
+ segments: syn::punctuated::Punctuated::from_iter(segments),
+ },
+ }
+ .into()
+}
+
+/// Create a path type with a single segment from a given Identifier
+pub fn ident_ty(ident: Ident) -> syn::Type {
+ simple_path_ty(Some(ident))
+}
+
+/// Convert an ImportFunction into the more generic Import type, wrapping the provided function
+pub fn wrap_import_function(function: ast::ImportFunction) -> ast::Import {
+ ast::Import {
+ module: None,
+ js_namespace: None,
+ kind: ast::ImportKind::Function(function),
+ }
+}
+
+/// Small utility used when generating symbol names.
+///
+/// Hashes the public field here along with a few cargo-set env vars to
+/// distinguish between runs of the procedural macro.
+#[derive(Debug)]
+pub struct ShortHash<T>(pub T);
+
+impl<T: Hash> fmt::Display for ShortHash<T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ static HASHED: AtomicBool = AtomicBool::new(false);
+ static HASH: AtomicUsize = AtomicUsize::new(0);
+
+ // Try to amortize the cost of loading env vars a lot as we're gonna be
+ // hashing for a lot of symbols.
+ if !HASHED.load(SeqCst) {
+ let mut h = DefaultHasher::new();
+ env::var("CARGO_PKG_NAME")
+ .expect("should have CARGO_PKG_NAME env var")
+ .hash(&mut h);
+ env::var("CARGO_PKG_VERSION")
+ .expect("should have CARGO_PKG_VERSION env var")
+ .hash(&mut h);
+ // This may chop off 32 bits on 32-bit platforms, but that's ok, we
+ // just want something to mix in below anyway.
+ HASH.store(h.finish() as usize, SeqCst);
+ HASHED.store(true, SeqCst);
+ }
+
+ let mut h = DefaultHasher::new();
+ HASH.load(SeqCst).hash(&mut h);
+ self.0.hash(&mut h);
+ write!(f, "{:016x}", h.finish())
+ }
+}