use crate::{util::ShortHash, Diagnostic};
use proc_macro2::{Ident, Span};
use std::hash::{Hash, Hasher};
use syn::Path;
use wasm_bindgen_shared as shared;
#[cfg_attr(feature = "extra-traits", derive(Debug))]
#[derive(Clone)]
pub struct Program {
pub exports: Vec<Export>,
pub imports: Vec<Import>,
pub linked_modules: Vec<ImportModule>,
pub enums: Vec<Enum>,
pub structs: Vec<Struct>,
pub typescript_custom_sections: Vec<LitOrExpr>,
pub inline_js: Vec<String>,
pub wasm_bindgen: Path,
pub js_sys: Path,
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 {
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()
}
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)
}
}
#[cfg_attr(feature = "extra-traits", derive(Debug))]
#[derive(Clone)]
pub struct LinkToModule(pub Program);
#[cfg_attr(feature = "extra-traits", derive(Debug))]
#[derive(Clone)]
pub struct Export {
pub comments: Vec<String>,
pub function: Function,
pub js_class: Option<String>,
pub method_kind: MethodKind,
pub method_self: Option<MethodSelf>,
pub rust_class: Option<Ident>,
pub rust_name: Ident,
pub start: bool,
pub wasm_bindgen: Path,
pub wasm_bindgen_futures: Path,
}
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
#[derive(Copy, Clone)]
pub enum MethodSelf {
ByValue,
RefMutable,
RefShared,
}
#[cfg_attr(feature = "extra-traits", derive(Debug))]
#[derive(Clone)]
pub struct Import {
pub module: Option<ImportModule>,
pub js_namespace: Option<Vec<String>>,
pub kind: ImportKind,
}
#[cfg_attr(feature = "extra-traits", derive(Debug))]
#[derive(Clone)]
pub enum ImportModule {
Named(String, Span),
RawNamed(String, Span),
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),
}
}
}
#[cfg_attr(feature = "extra-traits", derive(Debug))]
#[derive(Clone)]
pub enum ImportKind {
Function(ImportFunction),
Static(ImportStatic),
String(ImportString),
Type(ImportType),
Enum(StringEnum),
}
#[cfg_attr(feature = "extra-traits", derive(Debug))]
#[derive(Clone)]
pub struct ImportFunction {
pub function: Function,
pub rust_name: Ident,
pub js_ret: Option<syn::Type>,
pub catch: bool,
pub variadic: bool,
pub structural: bool,
pub assert_no_shim: bool,
pub kind: ImportFunctionKind,
pub shim: Ident,
pub doc_comment: String,
pub wasm_bindgen: Path,
pub wasm_bindgen_futures: Path,
}
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
#[derive(Clone)]
pub enum ImportFunctionKind {
Method {
class: String,
ty: syn::Type,
kind: MethodKind,
},
Normal,
}
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
#[derive(Clone)]
pub enum MethodKind {
Constructor,
Operation(Operation),
}
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
#[derive(Clone)]
pub struct Operation {
pub is_static: bool,
pub kind: OperationKind,
}
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
#[derive(Clone)]
pub enum OperationKind {
Regular,
Getter(Option<String>),
Setter(Option<String>),
IndexingGetter,
IndexingSetter,
IndexingDeleter,
}
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
#[derive(Clone)]
pub struct ImportStatic {
pub vis: syn::Visibility,
pub ty: syn::Type,
pub shim: Ident,
pub rust_name: Ident,
pub js_name: String,
pub wasm_bindgen: Path,
pub thread_local: Option<ThreadLocal>,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum ThreadLocal {
V1,
V2,
}
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
#[derive(Clone)]
pub struct ImportString {
pub vis: syn::Visibility,
pub ty: syn::Type,
pub shim: Ident,
pub rust_name: Ident,
pub wasm_bindgen: Path,
pub js_sys: Path,
pub string: String,
pub thread_local: ThreadLocal,
}
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
#[derive(Clone)]
pub struct ImportType {
pub vis: syn::Visibility,
pub rust_name: Ident,
pub js_name: String,
pub attrs: Vec<syn::Attribute>,
pub typescript_type: Option<String>,
pub doc_comment: Option<String>,
pub instanceof_shim: String,
pub is_type_of: Option<syn::Expr>,
pub extends: Vec<syn::Path>,
pub vendor_prefixes: Vec<Ident>,
pub no_deref: bool,
pub wasm_bindgen: Path,
}
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
#[derive(Clone)]
pub struct StringEnum {
pub vis: syn::Visibility,
pub name: Ident,
pub js_name: String,
pub variants: Vec<Ident>,
pub variant_values: Vec<String>,
pub comments: Vec<String>,
pub rust_attrs: Vec<syn::Attribute>,
pub generate_typescript: bool,
pub wasm_bindgen: Path,
}
#[cfg_attr(feature = "extra-traits", derive(Debug))]
#[derive(Clone)]
pub struct Function {
pub name: String,
pub name_span: Span,
pub renamed_via_js_name: bool,
pub arguments: Vec<FunctionArgumentData>,
pub ret: Option<FunctionReturnData>,
pub rust_attrs: Vec<syn::Attribute>,
pub rust_vis: syn::Visibility,
pub r#unsafe: bool,
pub r#async: bool,
pub generate_typescript: bool,
pub generate_jsdoc: bool,
pub variadic: bool,
}
#[cfg_attr(feature = "extra-traits", derive(Debug))]
#[derive(Clone)]
pub struct FunctionReturnData {
pub r#type: syn::Type,
pub js_type: Option<String>,
pub desc: Option<String>,
}
#[cfg_attr(feature = "extra-traits", derive(Debug))]
#[derive(Clone)]
pub struct FunctionArgumentData {
pub pat_type: syn::PatType,
pub js_name: Option<String>,
pub js_type: Option<String>,
pub desc: Option<String>,
}
#[cfg_attr(feature = "extra-traits", derive(Debug))]
#[derive(Clone)]
pub struct Struct {
pub rust_name: Ident,
pub js_name: String,
pub fields: Vec<StructField>,
pub comments: Vec<String>,
pub is_inspectable: bool,
pub generate_typescript: bool,
pub wasm_bindgen: Path,
}
#[cfg_attr(feature = "extra-traits", derive(Debug))]
#[derive(Clone)]
pub struct StructField {
pub rust_name: syn::Member,
pub js_name: String,
pub struct_name: Ident,
pub readonly: bool,
pub ty: syn::Type,
pub getter: Ident,
pub setter: Ident,
pub comments: Vec<String>,
pub generate_typescript: bool,
pub generate_jsdoc: bool,
pub getter_with_clone: Option<Span>,
pub wasm_bindgen: Path,
}
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
#[derive(Clone)]
pub struct Enum {
pub rust_name: Ident,
pub js_name: String,
pub signed: bool,
pub variants: Vec<Variant>,
pub comments: Vec<String>,
pub hole: u32,
pub generate_typescript: bool,
pub wasm_bindgen: Path,
}
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
#[derive(Clone)]
pub struct Variant {
pub name: Ident,
pub value: u32,
pub comments: Vec<String>,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum TypeKind {
ByRef,
ByMutRef,
ByValue,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum TypeLocation {
ImportArgument,
ImportRet,
ExportArgument,
ExportRet,
}
#[cfg_attr(feature = "extra-traits", derive(Debug))]
#[derive(Clone)]
pub enum LitOrExpr {
Expr(syn::Expr),
Lit(String),
}
impl Export {
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())
}
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 {
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 {
pub fn infer_getter_property(&self) -> &str {
&self.name
}
pub fn infer_setter_property(&self) -> Result<String, Diagnostic> {
let name = self.name.to_string();
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())
}
}