Vendor dependencies
Let's see how I like this workflow.
This commit is contained in:
parent
34d1830413
commit
9c435dc440
7500 changed files with 1665121 additions and 99 deletions
453
vendor/wasm-bindgen-backend/src/ast.rs
vendored
Normal file
453
vendor/wasm-bindgen-backend/src/ast.rs
vendored
Normal file
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
1389
vendor/wasm-bindgen-backend/src/codegen.rs
vendored
Normal file
1389
vendor/wasm-bindgen-backend/src/codegen.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
536
vendor/wasm-bindgen-backend/src/encode.rs
vendored
Normal file
536
vendor/wasm-bindgen-backend/src/encode.rs
vendored
Normal file
|
|
@ -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 })
|
||||
}
|
||||
})
|
||||
}
|
||||
134
vendor/wasm-bindgen-backend/src/error.rs
vendored
Normal file
134
vendor/wasm-bindgen-backend/src/error.rs
vendored
Normal 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.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
40
vendor/wasm-bindgen-backend/src/lib.rs
vendored
Normal file
40
vendor/wasm-bindgen-backend/src/lib.rs
vendored
Normal 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
161
vendor/wasm-bindgen-backend/src/util.rs
vendored
Normal 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
|
||||
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())
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue