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.121";
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            rust_name: &'a str,
191            fields: Vec<StructField<'a>>,
192            comments: Vec<&'a str>,
193            is_inspectable: bool,
194            generate_typescript: bool,
195            js_namespace: Option<Vec<&'a str>>,
196            private: bool,
197            extends: Option<&'a str>,
198        }
199
200        struct StructField<'a> {
201            name: &'a str,
202            readonly: bool,
203            comments: Vec<&'a str>,
204            generate_typescript: bool,
205            generate_jsdoc: bool,
206        }
207
208        struct LocalModule<'a> {
209            identifier: &'a str,
210            contents: &'a str,
211            linked_module: bool,
212        }
213        }
214    }; // end of mac case
215} // end of mac definition
216
217/// Compute a "qualified name" by prepending the namespace (joined with `__`) to the js_name.
218/// When there is no namespace, this returns the js_name unchanged.
219/// This is used to disambiguate internal wasm symbols when the same js_name
220/// appears in different namespaces. `__` is used as the separator because
221/// double underscores are unlikely to appear in user-defined names.
222pub fn qualified_name(js_namespace: Option<&[impl AsRef<str>]>, js_name: &str) -> String {
223    match js_namespace {
224        Some(ns) if !ns.is_empty() => {
225            let mut name = ns
226                .iter()
227                .map(|s| s.as_ref())
228                .collect::<alloc::vec::Vec<_>>()
229                .join("__");
230            name.push_str("__");
231            name.push_str(js_name);
232            name
233        }
234        _ => js_name.to_string(),
235    }
236}
237
238pub fn new_function(struct_name: &str) -> String {
239    let mut name = "__wbg_".to_string();
240    name.extend(struct_name.chars().flat_map(|s| s.to_lowercase()));
241    name.push_str("_new");
242    name
243}
244
245pub fn free_function(struct_name: &str) -> String {
246    let mut name = "__wbg_".to_string();
247    name.extend(struct_name.chars().flat_map(|s| s.to_lowercase()));
248    name.push_str("_free");
249    name
250}
251
252pub fn unwrap_function(struct_name: &str) -> String {
253    let mut name = "__wbg_".to_string();
254    name.extend(struct_name.chars().flat_map(|s| s.to_lowercase()));
255    name.push_str("_unwrap");
256    name
257}
258
259/// Convert a JS-side name into a form suitable as a wasm-side export
260/// symbol suffix. Plain identifier names pass through unchanged. The
261/// bracket form `"[Symbol.<ident>]"` collapses to `Symbol_<ident>`. Any
262/// other non-alphanumeric characters are replaced with `_` so that the
263/// result is always a valid C identifier suffix.
264fn export_name_suffix(name: &str) -> alloc::borrow::Cow<'_, str> {
265    if name.bytes().all(|b| b.is_ascii_alphanumeric() || b == b'_') {
266        return alloc::borrow::Cow::Borrowed(name);
267    }
268    let mut out = String::with_capacity(name.len());
269    for c in name.chars() {
270        if c.is_ascii_alphanumeric() || c == '_' {
271            out.push(c);
272        } else if c == '.' || c == '[' || c == ']' {
273            // Bracket / dotted forms collapse cleanly; we represent
274            // `[Symbol.iterator]` as `Symbol_iterator` (the `[` and `]`
275            // drop, the `.` becomes `_`).
276            if c == '.' {
277                out.push('_');
278            }
279        } else {
280            out.push('_');
281        }
282    }
283    alloc::borrow::Cow::Owned(out)
284}
285
286/// Symbol name of the wasm export that upcasts a `*const WasmRefCell<Child>`
287/// pointer to a cloned `Rc<WasmRefCell<Parent>>` raw pointer. Used by the
288/// macro codegen and by cli-support's JS emission to call each other.
289pub fn upcast_function(child_struct: &str, parent_struct: &str) -> String {
290    let mut name = "__wbg_upcast_".to_string();
291    name.extend(child_struct.chars().flat_map(|s| s.to_lowercase()));
292    name.push_str("_to_");
293    name.extend(parent_struct.chars().flat_map(|s| s.to_lowercase()));
294    name
295}
296
297pub fn free_function_export_name(function_name: &str) -> String {
298    export_name_suffix(function_name).into_owned()
299}
300
301pub fn struct_function_export_name(struct_: &str, f: &str) -> String {
302    let mut name = struct_
303        .chars()
304        .flat_map(|s| s.to_lowercase())
305        .collect::<String>();
306    name.push('_');
307    name.push_str(&export_name_suffix(f));
308    name
309}
310
311pub fn struct_field_get(struct_: &str, f: &str) -> String {
312    let mut name = String::from("__wbg_get_");
313    name.extend(struct_.chars().flat_map(|s| s.to_lowercase()));
314    name.push('_');
315    name.push_str(&export_name_suffix(f));
316    name
317}
318
319pub fn struct_field_set(struct_: &str, f: &str) -> String {
320    let mut name = String::from("__wbg_set_");
321    name.extend(struct_.chars().flat_map(|s| s.to_lowercase()));
322    name.push('_');
323    name.push_str(&export_name_suffix(f));
324    name
325}
326
327pub fn dynamic_union_variant(union_name: &str, variant_idx: u32) -> String {
328    let mut name = String::from("__wbg_dynamic_union_");
329    name.extend(union_name.chars().flat_map(|s| s.to_lowercase()));
330    name.push('_');
331    name.push_str(&variant_idx.to_string());
332    name
333}
334
335pub fn version() -> String {
336    let mut v = env!("CARGO_PKG_VERSION").to_string();
337    if let Some(s) = option_env!("WBG_VERSION") {
338        v.push_str(" (");
339        v.push_str(s);
340        v.push(')');
341    }
342    v
343}
344
345pub fn escape_string(s: &str) -> String {
346    let mut result = String::with_capacity(s.len());
347    for c in s.chars() {
348        match c {
349            '\\' => result.push_str("\\\\"),
350            '\n' => result.push_str("\\n"),
351            '\r' => result.push_str("\\r"),
352            '\'' => result.push_str("\\'"),
353            '"' => result.push_str("\\\""),
354            _ => result.push(c),
355        }
356    }
357    result
358}