Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

607
vendor/wasm-bindgen-backend/src/ast.rs vendored Normal file
View File

@@ -0,0 +1,607 @@
//! 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::{util::ShortHash, Diagnostic};
use proc_macro2::{Ident, Span};
use std::hash::{Hash, Hasher};
use syn::Path;
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(Clone)]
pub struct Program {
/// rust -> js interfaces
pub exports: Vec<Export>,
/// js -> rust interfaces
pub imports: Vec<Import>,
/// linked-to modules
pub linked_modules: Vec<ImportModule>,
/// 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<LitOrExpr>,
/// Inline JS snippets
pub inline_js: Vec<String>,
/// Path to wasm_bindgen
pub wasm_bindgen: Path,
/// Path to js_sys
pub js_sys: Path,
/// Path to wasm_bindgen_futures
pub wasm_bindgen_futures: Path,
}
impl Default for Program {
fn default() -> Self {
Self {
exports: Default::default(),
imports: Default::default(),
linked_modules: Default::default(),
enums: Default::default(),
structs: Default::default(),
typescript_custom_sections: Default::default(),
inline_js: Default::default(),
wasm_bindgen: syn::parse_quote! { wasm_bindgen },
js_sys: syn::parse_quote! { js_sys },
wasm_bindgen_futures: syn::parse_quote! { wasm_bindgen_futures },
}
}
}
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()
}
/// Name of the link function for a specific linked module
pub fn link_function_name(&self, idx: usize) -> String {
let hash = match &self.linked_modules[idx] {
ImportModule::Inline(idx, _) => ShortHash((1, &self.inline_js[*idx])).to_string(),
other => ShortHash((0, other)).to_string(),
};
format!("__wbindgen_link_{}", hash)
}
}
/// An abstract syntax tree representing a link to a module in Rust.
/// In contrast to Program, LinkToModule must expand to an expression.
/// linked_modules of the inner Program must contain exactly one element
/// whose link is produced by the expression.
#[cfg_attr(feature = "extra-traits", derive(Debug))]
#[derive(Clone)]
pub struct LinkToModule(pub Program);
/// 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,
/// Path to wasm_bindgen
pub wasm_bindgen: Path,
/// Path to wasm_bindgen_futures
pub wasm_bindgen_futures: Path,
}
/// The 3 types variations of `self`.
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
#[derive(Copy, 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 static string
String(ImportString),
/// Importing a type/class
Type(ImportType),
/// Importing a JS enum
Enum(StringEnum),
}
/// 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,
/// Path to wasm_bindgen
pub wasm_bindgen: Path,
/// Path to wasm_bindgen_futures
pub wasm_bindgen_futures: Path,
}
/// 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 or String
Getter(Option<String>),
/// A method for setting the value of the provided Ident or String
Setter(Option<String>),
/// 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,
/// Path to wasm_bindgen
pub wasm_bindgen: Path,
/// Version of `thread_local`, if any.
pub thread_local: Option<ThreadLocal>,
}
/// Which version of the `thread_local` attribute is enabled.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum ThreadLocal {
/// V1.
V1,
/// V2.
V2,
}
/// The type of a static string being imported
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
#[derive(Clone)]
pub struct ImportString {
/// The visibility of this static string in Rust
pub vis: syn::Visibility,
/// The type specified by the user, which we only use to show an error if the wrong type is used.
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,
/// Path to wasm_bindgen
pub wasm_bindgen: Path,
/// Path to js_sys
pub js_sys: Path,
/// The string to export.
pub string: String,
/// Version of `thread_local`.
pub thread_local: ThreadLocal,
}
/// 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,
/// Path to wasm_bindgen
pub wasm_bindgen: Path,
}
/// The metadata for a String Enum
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
#[derive(Clone)]
pub struct StringEnum {
/// The Rust enum's visibility
pub vis: syn::Visibility,
/// The Rust enum's identifiers
pub name: Ident,
/// The name of this string enum in JS/TS code
pub js_name: String,
/// The Rust identifiers for the variants
pub variants: Vec<Ident>,
/// The JS string values of the variants
pub variant_values: Vec<String>,
/// The doc comments on this enum, if any
pub comments: Vec<String>,
/// Attributes to apply to the Rust enum
pub rust_attrs: Vec<syn::Attribute>,
/// Whether to generate a typescript definition for this enum
pub generate_typescript: bool,
/// Path to wasm_bindgen
pub wasm_bindgen: Path,
}
/// 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<FunctionArgumentData>,
/// The data of return type of the function
pub ret: Option<FunctionReturnData>,
/// 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 `unsafe` function
pub r#unsafe: bool,
/// Whether this is an `async` function
pub r#async: bool,
/// Whether to generate a typescript definition for this function
pub generate_typescript: bool,
/// Whether to generate jsdoc documentation for this function
pub generate_jsdoc: bool,
/// Whether this is a function with a variadict parameter
pub variadic: bool,
}
/// Information about a function's return
#[cfg_attr(feature = "extra-traits", derive(Debug))]
#[derive(Clone)]
pub struct FunctionReturnData {
/// Specifies the type of the function's return
pub r#type: syn::Type,
/// Specifies the JS return type override
pub js_type: Option<String>,
/// Specifies the return description
pub desc: Option<String>,
}
/// Information about a function's argument
#[cfg_attr(feature = "extra-traits", derive(Debug))]
#[derive(Clone)]
pub struct FunctionArgumentData {
/// Specifies the type of the function's argument
pub pat_type: syn::PatType,
/// Specifies the JS argument name override
pub js_name: Option<String>,
/// Specifies the JS function argument type override
pub js_type: Option<String>,
/// Specifies the argument description
pub desc: Option<String>,
}
/// Information about a Struct being exported
#[cfg_attr(feature = "extra-traits", derive(Debug))]
#[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,
/// Path to wasm_bindgen
pub wasm_bindgen: Path,
}
/// The field of a struct
#[cfg_attr(feature = "extra-traits", derive(Debug))]
#[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 generate jsdoc documentation for this field
pub generate_jsdoc: bool,
/// The span of the `#[wasm_bindgen(getter_with_clone)]` attribute applied
/// to this field, if any.
///
/// If this is `Some`, the auto-generated getter for this field must clone
/// the field instead of copying it.
pub getter_with_clone: Option<Span>,
/// Path to wasm_bindgen
pub wasm_bindgen: Path,
}
/// The metadata for an Enum
#[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,
/// Whether the variant values and hole are signed, meaning that they
/// represent the bits of a `i32` value.
pub signed: bool,
/// 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,
/// Path to wasm_bindgen
pub wasm_bindgen: Path,
}
/// 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,
}
/// An enum representing either a literal value (`Lit`) or an expression (`syn::Expr`).
#[cfg_attr(feature = "extra-traits", derive(Debug))]
#[derive(Clone)]
pub enum LitOrExpr {
/// Represents an expression that needs to be evaluated before it can be encoded
Expr(syn::Expr),
/// Represents a literal string that can be directly encoded.
Lit(String),
}
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('_');
generated_name.push_str(class);
}
generated_name.push('_');
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::String(_) => 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())
}
}

1972
vendor/wasm-bindgen-backend/src/codegen.rs vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,626 @@
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 syn::ext::IdentExt;
use crate::ast;
use crate::Diagnostic;
#[derive(Clone)]
pub enum EncodeChunk {
EncodedBuf(Vec<u8>),
StrExpr(syn::Expr),
// TODO: support more expr type;
}
pub struct EncodeResult {
pub custom_section: Vec<EncodeChunk>,
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,
linked_module: bool,
}
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,
linked_module: bool,
) -> 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 let Some(id) = id.strip_prefix('/') {
self.root.join(id)
} 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,
linked_module,
};
files.insert(id.to_string(), file);
drop(files);
self.resolve_import_module(id, span, linked_module)
}
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| shared_lit_or_expr(x, intern))
.collect(),
linked_modules: prog
.linked_modules
.iter()
.enumerate()
.map(|(i, a)| shared_linked_module(&prog.link_function_name(i), a, intern))
.collect::<Result<Vec<_>, _>>()?,
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),
linked_module: file.linked_module,
})
.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 = matches!(export.method_self, Some(ast::MethodSelf::ByValue));
let method_kind = from_ast_method_kind(&export.function, intern, &export.method_kind)?;
Ok(Export {
class: export.js_class.as_deref(),
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 args =
func.arguments
.iter()
.enumerate()
.map(|(idx, arg)| FunctionArgumentData {
// use argument's "js_name" if it was provided via attributes
// if not use the original Rust argument ident
name: arg.js_name.clone().unwrap_or(
if let syn::Pat::Ident(x) = &*arg.pat_type.pat {
x.ident.unraw().to_string()
} else {
format!("arg{}", idx)
},
),
ty_override: arg.js_type.as_deref(),
desc: arg.desc.as_deref(),
})
.collect::<Vec<_>>();
Function {
args,
asyncness: func.r#async,
name: &func.name,
generate_typescript: func.generate_typescript,
generate_jsdoc: func.generate_jsdoc,
variadic: func.variadic,
ret_ty_override: func.ret.as_ref().and_then(|v| v.js_type.as_deref()),
ret_desc: func.ret.as_ref().and_then(|v| v.desc.as_deref()),
}
}
fn shared_enum<'a>(e: &'a ast::Enum, intern: &'a Interner) -> Enum<'a> {
Enum {
name: &e.js_name,
signed: e.signed,
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, false))
.transpose()?,
js_namespace: i.js_namespace.clone(),
kind: shared_import_kind(&i.kind, intern)?,
})
}
fn shared_lit_or_expr<'a>(i: &'a ast::LitOrExpr, _intern: &'a Interner) -> LitOrExpr<'a> {
match i {
ast::LitOrExpr::Lit(lit) => LitOrExpr::Lit(lit),
ast::LitOrExpr::Expr(expr) => LitOrExpr::Expr(expr),
}
}
fn shared_linked_module<'a>(
name: &str,
i: &'a ast::ImportModule,
intern: &'a Interner,
) -> Result<LinkedModule<'a>, Diagnostic> {
Ok(LinkedModule {
module: shared_module(i, intern, true)?,
link_function_name: intern.intern_str(name),
})
}
fn shared_module<'a>(
m: &'a ast::ImportModule,
intern: &'a Interner,
linked_module: bool,
) -> Result<ImportModule<'a>, Diagnostic> {
Ok(match m {
ast::ImportModule::Named(m, span) => {
intern.resolve_import_module(m, *span, linked_module)?
}
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::String(f) => ImportKind::String(shared_import_string(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_string<'a>(i: &'a ast::ImportString, intern: &'a Interner) -> ImportString<'a> {
ImportString {
shim: intern.intern(&i.shim),
string: &i.string,
}
}
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::StringEnum, _intern: &'a Interner) -> StringEnum<'a> {
StringEnum {
name: &i.js_name,
generate_typescript: i.generate_typescript,
variant_values: i.variant_values.iter().map(|x| &**x).collect(),
comments: i.comments.iter().map(|s| &**s).collect(),
}
}
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,
generate_jsdoc: s.generate_jsdoc,
}
}
trait Encode {
fn encode(&self, dst: &mut Encoder);
}
struct Encoder {
dst: Vec<EncodeChunk>,
}
enum LitOrExpr<'a> {
Expr(&'a syn::Expr),
Lit(&'a str),
}
impl Encode for LitOrExpr<'_> {
fn encode(&self, dst: &mut Encoder) {
match self {
LitOrExpr::Expr(expr) => {
dst.dst.push(EncodeChunk::StrExpr((*expr).clone()));
}
LitOrExpr::Lit(s) => s.encode(dst),
}
}
}
impl Encoder {
fn new() -> Encoder {
Encoder { dst: vec![] }
}
fn finish(self) -> Vec<EncodeChunk> {
self.dst
}
fn byte(&mut self, byte: u8) {
if let Some(EncodeChunk::EncodedBuf(buf)) = self.dst.last_mut() {
buf.push(byte);
} else {
self.dst.push(EncodeChunk::EncodedBuf(vec![byte]));
}
}
fn extend_from_slice(&mut self, slice: &[u8]) {
if let Some(EncodeChunk::EncodedBuf(buf)) = self.dst.last_mut() {
buf.extend_from_slice(slice);
} else {
self.dst.push(EncodeChunk::EncodedBuf(slice.to_owned()));
}
}
}
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 as usize);
(*self as u32).encode(dst);
}
}
impl Encode for &[u8] {
fn encode(&self, dst: &mut Encoder) {
self.len().encode(dst);
dst.extend_from_slice(self);
}
}
impl Encode for &str {
fn encode(&self, dst: &mut Encoder) {
self.as_bytes().encode(dst);
}
}
impl 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_str(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_str(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 })
}
})
}

134
vendor/wasm-bindgen-backend/src/error.rs vendored Normal file
View File

@@ -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.is_empty() {
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);
}
}
}
}

40
vendor/wasm-bindgen-backend/src/lib.rs vendored Normal file
View File

@@ -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;

161
vendor/wasm-bindgen-backend/src/util.rs vendored Normal file
View File

@@ -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
#[rustfmt::skip]
fn is_rust_keyword(name: &str) -> bool {
matches!(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" | "_"
)
}
/// Create an `Ident`, possibly mangling it if it conflicts with a Rust keyword.
pub fn rust_ident(name: &str) -> Ident {
if name.is_empty() {
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())
}
}