Skip to main content

wasm_bindgen_macro_support/
ast.rs

1//! A representation of the Abstract Syntax Tree of a Rust program,
2//! with all the added metadata necessary to generate Wasm bindings
3//! for it.
4
5use crate::{hash::ShortHash, Diagnostic};
6use proc_macro2::{Ident, Span};
7use std::hash::{Hash, Hasher};
8use syn::Path;
9use wasm_bindgen_shared as shared;
10
11pub fn use_js_sys_futures() -> bool {
12    // Honor either the build-time cfg or an expansion-time environment variable.
13    // The env-var form is necessary because `cfg!(...)` is resolved when this
14    // proc-macro crate is itself compiled (on the host), and Cargo does not pass
15    // `--cfg`/`RUSTFLAGS` to host proc-macros when `--target` is used. Reading
16    // an env var at expansion time provides a stable workflow that works
17    // regardless of how the consumer configures Cargo.
18    cfg!(wasm_bindgen_use_js_sys) || std::env::var_os("WASM_BINDGEN_USE_JS_SYS").is_some()
19}
20
21/// Whether a function is a start function, and if so, whether it
22/// should be exported to JS.
23#[cfg_attr(feature = "extra-traits", derive(Debug))]
24#[derive(Clone, Copy, PartialEq, Eq)]
25pub enum StartKind {
26    None,
27    Public,
28    Private,
29}
30
31impl StartKind {
32    pub fn is_start(self) -> bool {
33        matches!(self, StartKind::Public | StartKind::Private)
34    }
35}
36
37/// An abstract syntax tree representing a rust program. Contains
38/// extra information for joining up this rust code with javascript.
39#[cfg_attr(feature = "extra-traits", derive(Debug))]
40#[derive(Clone)]
41pub struct Program {
42    /// rust -> js interfaces
43    pub exports: Vec<Export>,
44    /// js -> rust interfaces
45    pub imports: Vec<Import>,
46    /// linked-to modules
47    pub linked_modules: Vec<ImportModule>,
48    /// rust enums
49    pub enums: Vec<Enum>,
50    /// rust structs
51    pub structs: Vec<Struct>,
52    /// custom typescript sections to be included in the definition file
53    pub typescript_custom_sections: Vec<LitOrExpr>,
54    /// Inline JS snippets
55    pub inline_js: Vec<String>,
56    /// Path to wasm_bindgen
57    pub wasm_bindgen: Path,
58    /// Path to js_sys
59    pub js_sys: Path,
60    /// Path to wasm_bindgen_futures
61    pub wasm_bindgen_futures: Path,
62}
63
64impl Default for Program {
65    fn default() -> Self {
66        Self {
67            exports: Default::default(),
68            imports: Default::default(),
69            linked_modules: Default::default(),
70            enums: Default::default(),
71            structs: Default::default(),
72            typescript_custom_sections: Default::default(),
73            inline_js: Default::default(),
74            wasm_bindgen: syn::parse_quote! { wasm_bindgen },
75            js_sys: syn::parse_quote! { js_sys },
76            wasm_bindgen_futures: syn::parse_quote! { wasm_bindgen_futures },
77        }
78    }
79}
80
81impl Program {
82    /// Name of the link function for a specific linked module
83    pub fn link_function_name(&self, idx: usize) -> String {
84        let hash = match &self.linked_modules[idx] {
85            ImportModule::Inline(idx) => ShortHash((1, &self.inline_js[*idx])).to_string(),
86            other => ShortHash((0, other)).to_string(),
87        };
88        format!("__wbindgen_link_{hash}")
89    }
90}
91
92/// An abstract syntax tree representing a link to a module in Rust.
93/// In contrast to Program, LinkToModule must expand to an expression.
94/// linked_modules of the inner Program must contain exactly one element
95/// whose link is produced by the expression.
96#[cfg_attr(feature = "extra-traits", derive(Debug))]
97#[derive(Clone)]
98pub struct LinkToModule(pub Program);
99
100/// A rust to js interface. Allows interaction with rust objects/functions
101/// from javascript.
102#[cfg_attr(feature = "extra-traits", derive(Debug))]
103#[derive(Clone)]
104pub struct Export {
105    /// Comments extracted from the rust source.
106    pub comments: Vec<String>,
107    /// The rust function
108    pub function: Function,
109    /// The class name in JS this is attached to
110    pub js_class: Option<String>,
111    /// The namespace to export the item through, if any
112    pub js_namespace: Option<Vec<String>>,
113    /// The kind (static, named, regular)
114    pub method_kind: MethodKind,
115    /// The type of `self` (either `self`, `&self`, or `&mut self`)
116    pub method_self: Option<MethodSelf>,
117    /// The struct name, in Rust, this is attached to
118    pub rust_class: Option<Ident>,
119    /// The name of the rust function/method on the rust side.
120    pub rust_name: Ident,
121    /// Whether or not this function should be flagged as the Wasm start
122    /// function.
123    pub start: StartKind,
124    /// Path to wasm_bindgen
125    pub wasm_bindgen: Path,
126    /// Path to wasm_bindgen_futures
127    pub wasm_bindgen_futures: Path,
128    /// Path to js_sys
129    pub js_sys: Path,
130}
131
132/// The 3 types variations of `self`.
133#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
134#[derive(Copy, Clone)]
135pub enum MethodSelf {
136    /// `self`
137    ByValue,
138    /// `&mut self`
139    RefMutable,
140    /// `&self`
141    RefShared,
142}
143
144/// Things imported from a JS module (in an `extern` block)
145#[cfg_attr(feature = "extra-traits", derive(Debug))]
146#[derive(Clone)]
147pub struct Import {
148    /// The type of module being imported from, if any
149    pub module: Option<ImportModule>,
150    /// The namespace to access the item through, if any
151    pub js_namespace: Option<Vec<String>>,
152    /// If Some, this import should be re-exported with the optional given name
153    pub reexport: Option<Option<String>>,
154    /// The type of item being imported
155    pub kind: ImportKind,
156}
157
158/// The possible types of module to import from
159#[cfg_attr(feature = "extra-traits", derive(Debug))]
160#[derive(Clone)]
161pub enum ImportModule {
162    /// Import from the named module, with relative paths interpreted
163    Named(String, Span),
164    /// Import from the named module, without interpreting paths
165    RawNamed(String, Span),
166    /// Import from an inline JS snippet
167    Inline(usize),
168}
169
170impl Hash for ImportModule {
171    fn hash<H: Hasher>(&self, h: &mut H) {
172        match self {
173            ImportModule::Named(name, _) => (1u8, name).hash(h),
174            ImportModule::Inline(idx) => (2u8, idx).hash(h),
175            ImportModule::RawNamed(name, _) => (3u8, name).hash(h),
176        }
177    }
178}
179
180/// The type of item being imported
181#[cfg_attr(feature = "extra-traits", derive(Debug))]
182#[derive(Clone)]
183pub enum ImportKind {
184    /// Importing a function
185    Function(ImportFunction),
186    /// Importing a static value
187    Static(ImportStatic),
188    /// Importing a static string
189    String(ImportString),
190    /// Importing a type/class
191    Type(ImportType),
192    /// Importing a JS string enum
193    Enum(StringEnum),
194    /// Importing a dynamic union (with fallback variant support)
195    DynamicUnion(DynamicUnion),
196}
197
198/// A function being imported from JS
199#[cfg_attr(feature = "extra-traits", derive(Debug))]
200#[derive(Clone)]
201pub struct ImportFunction {
202    /// The full signature of the function
203    pub function: Function,
204    /// The name rust code will use
205    pub rust_name: Ident,
206    /// The type being returned
207    pub js_ret: Option<syn::Type>,
208    /// Whether to catch JS exceptions
209    pub catch: bool,
210    /// Whether the function is variadic on the JS side
211    pub variadic: bool,
212    /// Whether the function should use structural type checking
213    pub structural: bool,
214    /// Causes the Builder (See cli-support::js::binding::Builder) to error out if
215    /// it finds itself generating code for a function with this signature
216    pub assert_no_shim: bool,
217    /// The kind of function being imported
218    pub kind: ImportFunctionKind,
219    /// The shim name to use in the generated code. The 'shim' is a function that appears in
220    /// the generated JS as a wrapper around the actual function to import, performing any
221    /// necessary conversions (EG adding a try/catch to change a thrown error into a Result)
222    pub shim: Ident,
223    /// The doc comment on this import, if one is provided
224    pub doc_comment: String,
225    /// Path to wasm_bindgen
226    pub wasm_bindgen: Path,
227    /// Path to wasm_bindgen_futures
228    pub wasm_bindgen_futures: Path,
229    /// Path to js_sys
230    pub js_sys: Path,
231    /// Generic parameters as validated simple type parameters for this function
232    pub generics: syn::Generics,
233}
234
235/// The type of a function being imported
236#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
237#[derive(Clone)]
238pub enum ImportFunctionKind {
239    /// A class method
240    Method {
241        /// The name of the class for this method, in JS
242        class: String,
243        /// The type of the class for this method, in Rust
244        ty: syn::Type,
245        /// The kind of method this is
246        kind: MethodKind,
247    },
248    /// A standard function
249    Normal,
250}
251
252/// The type of a method
253#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
254#[derive(Clone)]
255pub enum MethodKind {
256    /// A class constructor
257    Constructor,
258    /// Any other kind of method
259    Operation(Operation),
260}
261
262/// The operation performed by a class method
263#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
264#[derive(Clone)]
265pub struct Operation {
266    /// Whether this method is static
267    pub is_static: bool,
268    /// The internal kind of this Operation
269    pub kind: OperationKind,
270}
271
272/// The kind of operation performed by a method
273#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
274#[derive(Clone)]
275pub enum OperationKind {
276    /// A standard method, nothing special
277    Regular,
278    /// A free function that receives JS `this` as its first parameter
279    RegularThis,
280    /// A method for getting the value of the provided Ident or String
281    Getter(Option<String>),
282    /// A method for setting the value of the provided Ident or String
283    Setter(Option<String>),
284    /// A dynamically intercepted getter
285    IndexingGetter,
286    /// A dynamically intercepted setter
287    IndexingSetter,
288    /// A dynamically intercepted deleter
289    IndexingDeleter,
290}
291
292/// The type of a static being imported
293#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
294#[derive(Clone)]
295pub struct ImportStatic {
296    /// The visibility of this static in Rust
297    pub vis: syn::Visibility,
298    /// The type of static being imported
299    pub ty: syn::Type,
300    /// The name of the shim function used to access this static
301    pub shim: Ident,
302    /// The name of this static on the Rust side
303    pub rust_name: Ident,
304    /// The name of this static on the JS side
305    pub js_name: String,
306    /// Path to wasm_bindgen
307    pub wasm_bindgen: Path,
308    /// Version of `thread_local`, if any.
309    pub thread_local: Option<ThreadLocal>,
310}
311
312/// Which version of the `thread_local` attribute is enabled.
313#[derive(Copy, Clone, Debug, PartialEq, Eq)]
314pub enum ThreadLocal {
315    /// V1.
316    V1,
317    /// V2.
318    V2,
319}
320
321/// The type of a static string being imported
322#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
323#[derive(Clone)]
324pub struct ImportString {
325    /// The visibility of this static string in Rust
326    pub vis: syn::Visibility,
327    /// The type specified by the user, which we only use to show an error if the wrong type is used.
328    pub ty: syn::Type,
329    /// The name of the shim function used to access this static
330    pub shim: Ident,
331    /// The name of this static on the Rust side
332    pub rust_name: Ident,
333    /// Path to wasm_bindgen
334    pub wasm_bindgen: Path,
335    /// Path to js_sys
336    pub js_sys: Path,
337    /// The string to export.
338    pub string: String,
339    /// Version of `thread_local`.
340    pub thread_local: ThreadLocal,
341}
342
343/// The metadata for a type being imported
344#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
345#[derive(Clone)]
346pub struct ImportType {
347    /// The visibility of this type in Rust
348    pub vis: syn::Visibility,
349    /// The name of this type on the Rust side
350    pub rust_name: Ident,
351    /// The name of this type on the JS side
352    pub js_name: String,
353    /// The custom attributes to apply to this type
354    pub attrs: Vec<syn::Attribute>,
355    /// The TS definition to generate for this type
356    pub typescript_type: Option<String>,
357    /// The doc comment applied to this type, if one exists
358    pub doc_comment: Option<String>,
359    /// The name of the shim to check instanceof for this type
360    pub instanceof_shim: String,
361    /// The name of the remote function to use for the generated is_type_of
362    pub is_type_of: Option<syn::Expr>,
363    /// The list of classes this extends, if any
364    pub extends: Vec<syn::Path>,
365    /// A custom prefix to add and attempt to fall back to, if the type isn't found
366    pub vendor_prefixes: Vec<Ident>,
367    /// If present, don't generate a `Deref` impl
368    pub no_deref: bool,
369    /// If present, don't generate `Upcast` impls
370    pub no_upcast: bool,
371    /// If present, don't generate a `Promising` impl
372    pub no_promising: bool,
373    /// If present, don't generate an `IntoJsGeneric` impl
374    pub no_into_js_generic: bool,
375    /// Path to wasm_bindgen
376    pub wasm_bindgen: Path,
377    /// Validated generics
378    pub generics: syn::Generics,
379}
380
381/// The metadata for a String Enum
382#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
383#[derive(Clone)]
384pub struct StringEnum {
385    /// The Rust enum's visibility
386    pub vis: syn::Visibility,
387    /// The Rust enum's identifiers
388    pub name: Ident,
389    /// The export name of this string enum in JS/TS code
390    pub export_name: String,
391    /// The Rust identifiers for the variants
392    pub variants: Vec<Ident>,
393    /// The JS string values of the variants
394    pub variant_values: Vec<String>,
395    /// The doc comments on this enum, if any
396    pub comments: Vec<String>,
397    /// Attributes to apply to the Rust enum
398    pub rust_attrs: Vec<syn::Attribute>,
399    /// Whether to generate a typescript definition for this enum
400    pub generate_typescript: bool,
401    /// Whether to suppress the `export` keyword on the generated TS type
402    /// alias (matches the existing flag on c-style enums and structs).
403    pub private: bool,
404    /// The namespace to export the enum through, if any
405    pub js_namespace: Option<Vec<String>>,
406    /// Path to wasm_bindgen
407    pub wasm_bindgen: Path,
408}
409
410/// The metadata for a Dynamic Union (an untagged JS-side union of string
411/// literals and single-field tuple variants, dispatched at runtime).
412#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
413#[derive(Clone)]
414pub struct DynamicUnion {
415    /// The Rust enum's visibility
416    pub vis: syn::Visibility,
417    /// The Rust enum's identifiers
418    pub name: Ident,
419    /// The name of this enum in JS/TS code
420    pub js_name: String,
421    /// The Rust identifiers for the variants
422    pub variants: Vec<Ident>,
423    /// The JS string values of the known string variants
424    pub variant_values: Vec<String>,
425    /// The field types for each variant (empty for known string variants, one element for fallback variant)
426    pub variant_fields: Vec<Vec<syn::Type>>,
427    /// The doc comments on this enum, if any
428    pub comments: Vec<String>,
429    /// Attributes to apply to the Rust enum
430    pub rust_attrs: Vec<syn::Attribute>,
431    /// Whether to generate a typescript definition for this enum
432    pub generate_typescript: bool,
433    /// Whether to suppress the `export` keyword on the generated TS type alias.
434    pub private: bool,
435    /// Whether the last tuple variant should act as an unconditional
436    /// fallback rather than a runtime-checked variant. Set via the
437    /// `#[wasm_bindgen(fallback)]` attribute on the enum.
438    pub fallback: bool,
439    /// Path to wasm_bindgen
440    pub wasm_bindgen: Path,
441}
442
443/// Information about a function being imported or exported
444#[cfg_attr(feature = "extra-traits", derive(Debug))]
445#[derive(Clone)]
446pub struct Function {
447    /// The exported name of the function
448    pub name: String,
449    /// The span of the function's name in Rust code
450    pub name_span: Span,
451    /// The arguments to the function
452    pub arguments: Vec<FunctionArgumentData>,
453    /// The data of return type of the function
454    pub ret: Option<FunctionReturnData>,
455    /// Any custom attributes being applied to the function
456    pub rust_attrs: Vec<syn::Attribute>,
457    /// The visibility of this function in Rust
458    pub rust_vis: syn::Visibility,
459    /// Whether this is an `unsafe` function
460    pub r#unsafe: bool,
461    /// Whether this is an `async` function
462    pub r#async: bool,
463    /// Whether to generate a typescript definition for this function
464    pub generate_typescript: bool,
465    /// Whether to generate jsdoc documentation for this function
466    pub generate_jsdoc: bool,
467    /// Whether this is a function with a variadict parameter
468    pub variadic: bool,
469}
470
471/// Information about a function's return
472#[cfg_attr(feature = "extra-traits", derive(Debug))]
473#[derive(Clone)]
474pub struct FunctionReturnData {
475    /// Specifies the type of the function's return
476    pub r#type: syn::Type,
477    /// Specifies the JS return type override
478    pub js_type: Option<String>,
479    /// Specifies the return description
480    pub desc: Option<String>,
481}
482
483/// Information about a function's argument
484#[cfg_attr(feature = "extra-traits", derive(Debug))]
485#[derive(Clone)]
486pub struct FunctionArgumentData {
487    /// Specifies the type of the function's argument
488    pub pat_type: syn::PatType,
489    /// Specifies the JS argument name override
490    pub js_name: Option<String>,
491    /// Specifies the JS function argument type override
492    pub js_type: Option<String>,
493    /// Specifies whether the parameter is optional
494    pub optional: bool,
495    /// Specifies the argument description
496    pub desc: Option<String>,
497    /// When set, an `&[T]` (or `Option<&[T]>`) argument is converted to a
498    /// freshly-allocated buffer the JS side observes as a plain `Array`
499    /// rather than a typed array. Only meaningful for outgoing arguments
500    /// (Rust calling JS); ignored on exported functions.
501    pub slice_to_array: bool,
502}
503
504/// Information about a Struct being exported
505#[cfg_attr(feature = "extra-traits", derive(Debug))]
506#[derive(Clone)]
507pub struct Struct {
508    /// The name of the struct in Rust code
509    pub rust_name: Ident,
510    /// The export name of the struct in JS code
511    pub js_name: String,
512    /// The namespace-qualified internal name used for wasm symbol generation.
513    /// When a namespace is present, this is `ns1_ns2_JsName`; otherwise it equals `js_name`.
514    pub qualified_name: String,
515    /// All the fields of this struct to export
516    pub fields: Vec<StructField>,
517    /// The doc comments on this struct, if provided
518    pub comments: Vec<String>,
519    /// Whether this struct is inspectable (provides toJSON/toString properties to JS)
520    pub is_inspectable: bool,
521    /// Whether to generate a typescript definition for this struct
522    pub generate_typescript: bool,
523    /// Whether to skip exporting this struct from the module exports
524    pub private: bool,
525    /// The namespace to export the struct through, if any
526    pub js_namespace: Option<Vec<String>>,
527    /// The parent type this struct extends, if any. When set, the macro
528    /// auto-injects a `parent: wasm_bindgen::Parent<Parent>` field at the
529    /// head of the struct; that field is used as the upcast projection
530    /// target. Users must not declare a `Parent<T>` field themselves.
531    pub extends: Option<Path>,
532    /// The JS-side `js_name` of the parent class, declared on the child
533    /// via `extends_js_class = "..."`. Required when the parent struct
534    /// uses `js_name`: the child macro cannot see the parent struct's
535    /// attributes cross-invocation, so the parent's JS-side identity must
536    /// be redeclared here for `exported_classes` lookup to resolve.
537    /// Defaults to the last segment of the `extends` Rust path (matching
538    /// the no-rename case).
539    pub extends_js_class: Option<String>,
540    /// The JS-side `js_namespace` of the parent class, declared on the
541    /// child via `extends_js_namespace = ...`. Required when the parent
542    /// struct uses `js_namespace`. Defaults to `None`.
543    pub extends_js_namespace: Option<Vec<String>>,
544    /// Path to wasm_bindgen
545    pub wasm_bindgen: Path,
546}
547
548/// The field of a struct
549#[cfg_attr(feature = "extra-traits", derive(Debug))]
550#[derive(Clone)]
551pub struct StructField {
552    /// The name of the field in Rust code
553    pub rust_name: syn::Member,
554    /// The name of the field in JS code
555    pub js_name: String,
556    /// The name of the struct this field is part of
557    pub struct_name: Ident,
558    /// Whether this value is read-only to JS
559    pub readonly: bool,
560    /// The type of this field
561    pub ty: syn::Type,
562    /// The name of the getter shim for this field
563    pub getter: Ident,
564    /// The name of the setter shim for this field
565    pub setter: Ident,
566    /// The doc comments on this field, if any
567    pub comments: Vec<String>,
568    /// Whether to generate a typescript definition for this field
569    pub generate_typescript: bool,
570    /// Whether to generate jsdoc documentation for this field
571    pub generate_jsdoc: bool,
572    /// The span of the `#[wasm_bindgen(getter_with_clone)]` attribute applied
573    /// to this field, if any.
574    ///
575    /// If this is `Some`, the auto-generated getter for this field must clone
576    /// the field instead of copying it.
577    pub getter_with_clone: Option<Span>,
578    /// Whether this field is the macro-injected parent field — i.e. has
579    /// type `wasm_bindgen::Parent<T>` — for an `extends` relationship.
580    /// Parent fields are not exposed to JS as getters/setters; they exist
581    /// only for Rust-side upcast projection.
582    pub is_parent: bool,
583    /// Path to wasm_bindgen
584    pub wasm_bindgen: Path,
585}
586
587/// The metadata for an Enum
588#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
589#[derive(Clone)]
590pub struct Enum {
591    /// The name of this enum in Rust code
592    pub rust_name: Ident,
593    /// The export name of this enum in JS code
594    pub js_name: String,
595    /// Whether the variant values and hole are signed, meaning that they
596    /// represent the bits of a `i32` value.
597    pub signed: bool,
598    /// The variants provided by this enum
599    pub variants: Vec<Variant>,
600    /// The doc comments on this enum, if any
601    pub comments: Vec<String>,
602    /// The value to use for a `none` variant of the enum
603    pub hole: u32,
604    /// Whether to generate a typescript definition for this enum
605    pub generate_typescript: bool,
606    /// Whether to hide this enum from the module exports
607    pub private: bool,
608    /// The namespace to export the enum through, if any
609    pub js_namespace: Option<Vec<String>>,
610    /// Path to wasm_bindgen
611    pub wasm_bindgen: Path,
612}
613
614/// The variant of an enum
615#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
616#[derive(Clone)]
617pub struct Variant {
618    /// The name of this variant in Rust
619    pub rust_name: Ident,
620    /// The name of this variant in JS
621    pub js_name: String,
622    /// The backing value of this variant
623    pub value: u32,
624    /// The doc comments on this variant, if any
625    pub comments: Vec<String>,
626}
627
628/// An enum representing either a literal value (`Lit`) or an expression (`syn::Expr`).
629#[cfg_attr(feature = "extra-traits", derive(Debug))]
630#[derive(Clone)]
631pub enum LitOrExpr {
632    /// Represents an expression that needs to be evaluated before it can be encoded
633    Expr(syn::Expr),
634    /// Represents a literal string that can be directly encoded.
635    Lit(String),
636}
637
638impl Export {
639    /// Mangles a rust -> javascript export, so that the created Ident will be unique over function
640    /// name and class name, if the function belongs to a javascript class.
641    pub fn rust_symbol(&self) -> Ident {
642        let mut generated_name = String::from("__wasm_bindgen_generated");
643        if let Some(class) = &self.js_class {
644            generated_name.push('_');
645            generated_name.push_str(class);
646        }
647        generated_name.push('_');
648        // The JS-side name may contain characters that aren't valid in a
649        // Rust identifier (notably the `[Symbol.<name>]` computed-key form
650        // accepted by `js_name`). Filter to a valid identifier suffix; this
651        // is a no-op for plain identifier names.
652        for c in self.function.name.chars() {
653            if c.is_ascii_alphanumeric() || c == '_' {
654                generated_name.push(c);
655            }
656        }
657        Ident::new(&generated_name, Span::call_site())
658    }
659
660    /// This is the name of the shim function that gets exported and takes the raw
661    /// ABI form of its arguments and converts them back into their normal,
662    /// "high level" form before calling the actual function.
663    pub fn export_name(&self) -> String {
664        let fn_name = self.function.name.to_string();
665        let base_name = match &self.js_class {
666            Some(class) => shared::struct_function_export_name(class, &fn_name),
667            None => shared::free_function_export_name(&fn_name),
668        };
669
670        if let Some(ns) = &self.js_namespace {
671            format!("{}__{base_name}", ns.join("__"))
672        } else {
673            base_name
674        }
675    }
676}
677
678impl ImportKind {
679    /// Whether this type can be inside an `impl` block.
680    pub fn fits_on_impl(&self) -> bool {
681        match *self {
682            ImportKind::Function(_) => true,
683            ImportKind::Static(_) => false,
684            ImportKind::String(_) => false,
685            ImportKind::Type(_) => false,
686            ImportKind::Enum(_) => false,
687            ImportKind::DynamicUnion(_) => false,
688        }
689    }
690}
691
692impl Function {
693    /// If the rust object has a `fn xxx(&self) -> MyType` method, get the name for a getter in
694    /// javascript (in this case `xxx`, so you can write `val = obj.xxx`)
695    pub fn infer_getter_property(&self) -> &str {
696        &self.name
697    }
698
699    /// If the rust object has a `fn set_xxx(&mut self, MyType)` style method, get the name
700    /// for a setter in javascript (in this case `xxx`, so you can write `obj.xxx = val`)
701    pub fn infer_setter_property(&self) -> Result<String, Diagnostic> {
702        let name = self.name.to_string();
703
704        // Otherwise we infer names based on the Rust function name.
705        if !name.starts_with("set_") {
706            bail_span!(
707                syn::token::Pub(self.name_span),
708                "setters must start with `set_`, found: {}",
709                name,
710            );
711        }
712        Ok(name[4..].to_string())
713    }
714}