Skip to main content

wasm_bindgen_shared/
lib.rs

1#![doc(html_root_url = "https://docs.rs/wasm-bindgen-shared/0.2")]
2#![no_std]
3
4extern crate alloc;
5
6use alloc::string::{String, ToString};
7
8pub mod identifier;
9#[cfg(test)]
10mod schema_hash_approval;
11pub mod tys;
12
13// This gets changed whenever our schema changes.
14// At this time versions of wasm-bindgen and wasm-bindgen-cli are required to have the exact same
15// SCHEMA_VERSION in order to work together.
16pub const SCHEMA_VERSION: &str = "0.2.122";
17
18#[macro_export]
19macro_rules! shared_api {
20    ($mac:ident) => {
21        $mac! {
22        struct Program<'a> {
23            exports: Vec<Export<'a>>,
24            enums: Vec<Enum<'a>>,
25            imports: Vec<Import<'a>>,
26            structs: Vec<Struct<'a>>,
27            // NOTE: Originally typescript_custom_sections are just some strings
28            // But the expression type can only be parsed into a string during compilation
29            // So when encoding, LitOrExpr contains two types, one is that expressions are parsed into strings during compilation, and the other is can be parsed directly.
30            // When decoding, LitOrExpr can be decoded as a string.
31            typescript_custom_sections: Vec<LitOrExpr<'a>>,
32            local_modules: Vec<LocalModule<'a>>,
33            inline_js: Vec<&'a str>,
34            unique_crate_identifier: &'a str,
35            package_json: Option<&'a str>,
36            linked_modules: Vec<LinkedModule<'a>>,
37        }
38
39        struct Import<'a> {
40            module: Option<ImportModule<'a>>,
41            js_namespace: Option<Vec<String>>,
42            reexport: Option<String>,
43            generate_typescript: bool,
44            kind: ImportKind<'a>,
45        }
46
47        struct LinkedModule<'a> {
48            module: ImportModule<'a>,
49            link_function_name: &'a str,
50        }
51
52        enum ImportModule<'a> {
53            Named(&'a str),
54            RawNamed(&'a str),
55            Inline(u32),
56        }
57
58        enum ImportKind<'a> {
59            Function(ImportFunction<'a>),
60            Static(ImportStatic<'a>),
61            String(ImportString<'a>),
62            Type(ImportType<'a>),
63            Enum(StringEnum<'a>),
64            DynamicUnion(DynamicUnion<'a>),
65        }
66
67        struct ImportFunction<'a> {
68            shim: &'a str,
69            catch: bool,
70            variadic: bool,
71            assert_no_shim: bool,
72            method: Option<MethodData<'a>>,
73            structural: bool,
74            function: Function<'a>,
75        }
76
77        struct MethodData<'a> {
78            class: &'a str,
79            kind: MethodKind<'a>,
80        }
81
82        enum MethodKind<'a> {
83            Constructor,
84            Operation(Operation<'a>),
85        }
86
87        struct Operation<'a> {
88            is_static: bool,
89            kind: OperationKind<'a>,
90        }
91
92        enum OperationKind<'a> {
93            Regular,
94            RegularThis,
95            Getter(&'a str),
96            Setter(&'a str),
97            IndexingGetter,
98            IndexingSetter,
99            IndexingDeleter,
100        }
101
102        struct ImportStatic<'a> {
103            name: &'a str,
104            shim: &'a str,
105        }
106
107        struct ImportString<'a> {
108            shim: &'a str,
109            string: &'a str,
110        }
111
112        struct ImportType<'a> {
113            name: &'a str,
114            instanceof_shim: &'a str,
115            vendor_prefixes: Vec<&'a str>,
116        }
117
118        struct StringEnum<'a> {
119            name: &'a str,
120            variant_values: Vec<&'a str>,
121            comments: Vec<&'a str>,
122            generate_typescript: bool,
123            private: bool,
124            js_namespace: Option<Vec<&'a str>>,
125        }
126
127        enum StartKind {
128            None,
129            Public,
130            Private,
131        }
132
133        struct DynamicUnion<'a> {
134            name: &'a str,
135            variant_strings: Vec<&'a str>,
136            variant_type_cnt: u32,
137            comments: Vec<&'a str>,
138            generate_typescript: bool,
139            private: bool,
140            fallback: bool,
141        }
142
143
144        struct Export<'a> {
145            class: Option<&'a str>,
146            comments: Vec<&'a str>,
147            consumed: bool,
148            function: Function<'a>,
149            js_namespace: Option<Vec<&'a str>>,
150            method_kind: MethodKind<'a>,
151            start: StartKind,
152        }
153
154        struct Enum<'a> {
155            name: &'a str,
156            signed: bool,
157            variants: Vec<EnumVariant<'a>>,
158            comments: Vec<&'a str>,
159            generate_typescript: bool,
160            js_namespace: Option<Vec<&'a str>>,
161            private: bool,
162        }
163
164        struct EnumVariant<'a> {
165            name: &'a str,
166            value: u32,
167            comments: Vec<&'a str>,
168        }
169
170        struct Function<'a> {
171            args: Vec<FunctionArgumentData<'a>>,
172            asyncness: bool,
173            name: &'a str,
174            generate_typescript: bool,
175            generate_jsdoc: bool,
176            variadic: bool,
177            ret_ty_override: Option<&'a str>,
178            ret_desc: Option<&'a str>,
179        }
180
181        struct FunctionArgumentData<'a> {
182            name: String,
183            ty_override: Option<&'a str>,
184            optional: bool,
185            desc: Option<&'a str>,
186        }
187
188        struct Struct<'a> {
189            name: &'a str,
190            fields: Vec<StructField<'a>>,
191            comments: Vec<&'a str>,
192            is_inspectable: bool,
193            generate_typescript: bool,
194            js_namespace: Option<Vec<&'a str>>,
195            private: bool,
196            extends: Option<&'a str>,
197            extends_js_class: Option<&'a str>,
198            extends_js_namespace: Option<Vec<&'a str>>,
199        }
200
201        struct StructField<'a> {
202            name: &'a str,
203            readonly: bool,
204            comments: Vec<&'a str>,
205            generate_typescript: bool,
206            generate_jsdoc: bool,
207        }
208
209        struct LocalModule<'a> {
210            identifier: &'a str,
211            contents: &'a str,
212            linked_module: bool,
213        }
214        }
215    }; // end of mac case
216} // end of mac definition
217
218/// Compute a "qualified name" by prepending the namespace (joined with `__`) to the js_name.
219/// When there is no namespace, this returns the js_name unchanged.
220/// This is used to disambiguate internal wasm symbols when the same js_name
221/// appears in different namespaces. `__` is used as the separator because
222/// double underscores are unlikely to appear in user-defined names.
223pub fn qualified_name(js_namespace: Option<&[impl AsRef<str>]>, js_name: &str) -> String {
224    match js_namespace {
225        Some(ns) if !ns.is_empty() => {
226            let mut name = ns
227                .iter()
228                .map(|s| s.as_ref())
229                .collect::<alloc::vec::Vec<_>>()
230                .join("__");
231            name.push_str("__");
232            name.push_str(js_name);
233            name
234        }
235        _ => js_name.to_string(),
236    }
237}
238
239pub fn new_function(struct_name: &str) -> String {
240    let mut name = "__wbg_".to_string();
241    name.extend(struct_name.chars().flat_map(|s| s.to_lowercase()));
242    name.push_str("_new");
243    name
244}
245
246pub fn free_function(struct_name: &str) -> String {
247    let mut name = "__wbg_".to_string();
248    name.extend(struct_name.chars().flat_map(|s| s.to_lowercase()));
249    name.push_str("_free");
250    name
251}
252
253pub fn unwrap_function(struct_name: &str) -> String {
254    let mut name = "__wbg_".to_string();
255    name.extend(struct_name.chars().flat_map(|s| s.to_lowercase()));
256    name.push_str("_unwrap");
257    name
258}
259
260/// Convert a JS-side name into a form suitable as a wasm-side export
261/// symbol suffix. Plain identifier names pass through unchanged. The
262/// bracket form `"[Symbol.<ident>]"` collapses to `Symbol_<ident>`. Any
263/// other non-alphanumeric characters are replaced with `_` so that the
264/// result is always a valid C identifier suffix.
265fn export_name_suffix(name: &str) -> alloc::borrow::Cow<'_, str> {
266    if name.bytes().all(|b| b.is_ascii_alphanumeric() || b == b'_') {
267        return alloc::borrow::Cow::Borrowed(name);
268    }
269    let mut out = String::with_capacity(name.len());
270    for c in name.chars() {
271        if c.is_ascii_alphanumeric() || c == '_' {
272            out.push(c);
273        } else if c == '.' || c == '[' || c == ']' {
274            // Bracket / dotted forms collapse cleanly; we represent
275            // `[Symbol.iterator]` as `Symbol_iterator` (the `[` and `]`
276            // drop, the `.` becomes `_`).
277            if c == '.' {
278                out.push('_');
279            }
280        } else {
281            out.push('_');
282        }
283    }
284    alloc::borrow::Cow::Owned(out)
285}
286
287/// Symbol name of the wasm export that upcasts a `*const WasmRefCell<Child>`
288/// pointer to a cloned `Rc<WasmRefCell<Parent>>` raw pointer. Used by the
289/// macro codegen and by cli-support's JS emission to call each other.
290pub fn upcast_function(child_struct: &str, parent_struct: &str) -> String {
291    let mut name = "__wbg_upcast_".to_string();
292    name.extend(child_struct.chars().flat_map(|s| s.to_lowercase()));
293    name.push_str("_to_");
294    name.extend(parent_struct.chars().flat_map(|s| s.to_lowercase()));
295    name
296}
297
298pub fn free_function_export_name(function_name: &str) -> String {
299    export_name_suffix(function_name).into_owned()
300}
301
302pub fn struct_function_export_name(struct_: &str, f: &str) -> String {
303    let mut name = struct_
304        .chars()
305        .flat_map(|s| s.to_lowercase())
306        .collect::<String>();
307    name.push('_');
308    name.push_str(&export_name_suffix(f));
309    name
310}
311
312pub fn struct_field_get(struct_: &str, f: &str) -> String {
313    let mut name = String::from("__wbg_get_");
314    name.extend(struct_.chars().flat_map(|s| s.to_lowercase()));
315    name.push('_');
316    name.push_str(&export_name_suffix(f));
317    name
318}
319
320pub fn struct_field_set(struct_: &str, f: &str) -> String {
321    let mut name = String::from("__wbg_set_");
322    name.extend(struct_.chars().flat_map(|s| s.to_lowercase()));
323    name.push('_');
324    name.push_str(&export_name_suffix(f));
325    name
326}
327
328pub fn dynamic_union_variant(union_name: &str, variant_idx: u32) -> String {
329    let mut name = String::from("__wbg_dynamic_union_");
330    name.extend(union_name.chars().flat_map(|s| s.to_lowercase()));
331    name.push('_');
332    name.push_str(&variant_idx.to_string());
333    name
334}
335
336pub fn version() -> String {
337    let mut v = env!("CARGO_PKG_VERSION").to_string();
338    if let Some(s) = option_env!("WBG_VERSION") {
339        v.push_str(" (");
340        v.push_str(s);
341        v.push(')');
342    }
343    v
344}
345
346pub fn escape_string(s: &str) -> String {
347    let mut result = String::with_capacity(s.len());
348    for c in s.chars() {
349        match c {
350            '\\' => result.push_str("\\\\"),
351            '\n' => result.push_str("\\n"),
352            '\r' => result.push_str("\\r"),
353            '\'' => result.push_str("\\'"),
354            '"' => result.push_str("\\\""),
355            _ => result.push(c),
356        }
357    }
358    result
359}