Skip to main content

wry_bindgen_runtime/wire/
registry.rs

1use alloc::string::String;
2use alloc::vec::Vec;
3
4use super::TypeDef;
5
6#[derive(Clone, Copy)]
7pub struct JsFunctionSpec {
8    code: JsFunctionCode,
9}
10
11impl JsFunctionSpec {
12    pub const fn new(js_code: fn() -> String) -> Self {
13        Self {
14            code: JsFunctionCode::Global(js_code),
15        }
16    }
17
18    pub const fn with_module(module: &'static JsModuleSpec, js_code: fn(&str) -> String) -> Self {
19        Self {
20            code: JsFunctionCode::Module { module, js_code },
21        }
22    }
23}
24
25#[derive(Clone, Copy)]
26enum JsFunctionCode {
27    Global(fn() -> String),
28    Module {
29        module: &'static JsModuleSpec,
30        js_code: fn(&str) -> String,
31    },
32}
33
34inventory::collect!(JsFunctionSpec);
35
36#[derive(Clone, Copy)]
37pub struct JsModuleSpec {
38    content: &'static str,
39}
40
41impl JsModuleSpec {
42    pub const fn new(content: &'static str) -> Self {
43        Self { content }
44    }
45
46    pub const fn const_hash(&self) -> u64 {
47        const FNV_OFFSET_BASIS: u64 = 0xcbf29ce484222325;
48        const FNV_PRIME: u64 = 0x100000001b3;
49
50        let mut hash = FNV_OFFSET_BASIS;
51        let mut i = 0;
52        let bytes = self.content.as_bytes();
53        while i < bytes.len() {
54            hash ^= bytes[i] as u64;
55            hash = hash.wrapping_mul(FNV_PRIME);
56            i += 1;
57        }
58        hash
59    }
60}
61
62impl JsFunctionSpec {
63    pub(crate) fn module(&self) -> Option<&'static JsModuleSpec> {
64        match self.code {
65            JsFunctionCode::Global(_) => None,
66            JsFunctionCode::Module { module, .. } => Some(module),
67        }
68    }
69
70    pub(crate) fn render_js_code(&self) -> String {
71        match self.code {
72            JsFunctionCode::Global(js_code) => js_code(),
73            JsFunctionCode::Module { module, js_code } => {
74                let module_binding = alloc::format!("module_{:x}", module.const_hash());
75                js_code(&module_binding)
76            }
77        }
78    }
79
80    pub(crate) fn identity_eq(&self, other: &JsFunctionSpec) -> bool {
81        match (self.code, other.code) {
82            (JsFunctionCode::Global(a), JsFunctionCode::Global(b)) => a as usize == b as usize,
83            (
84                JsFunctionCode::Module {
85                    module: module_a,
86                    js_code: js_code_a,
87                },
88                JsFunctionCode::Module {
89                    module: module_b,
90                    js_code: js_code_b,
91                },
92            ) => core::ptr::eq(module_a, module_b) && js_code_a as usize == js_code_b as usize,
93            _ => false,
94        }
95    }
96}
97
98impl JsModuleSpec {
99    pub(crate) fn content(&self) -> &'static str {
100        self.content
101    }
102}
103
104#[derive(Clone, Copy)]
105#[non_exhaustive]
106pub enum JsClassMemberKind {
107    Constructor,
108    Method,
109    StaticMethod,
110    Getter,
111    Setter,
112}
113
114#[derive(Clone, Copy)]
115pub struct JsClassMemberSpec {
116    class_name: &'static str,
117    member_name: &'static str,
118    export_name: &'static str,
119    arg_count: usize,
120    arg_types: fn() -> Vec<TypeDef>,
121    return_type: fn() -> Option<TypeDef>,
122    kind: JsClassMemberKind,
123}
124
125impl JsClassMemberSpec {
126    pub const fn new(
127        class_name: &'static str,
128        member_name: &'static str,
129        export_name: &'static str,
130        arg_count: usize,
131        arg_types: fn() -> Vec<TypeDef>,
132        return_type: fn() -> Option<TypeDef>,
133        kind: JsClassMemberKind,
134    ) -> Self {
135        Self {
136            class_name,
137            member_name,
138            export_name,
139            arg_count,
140            arg_types,
141            return_type,
142            kind,
143        }
144    }
145}
146
147pub(super) type JsClassMemberParts = (
148    &'static str,
149    &'static str,
150    &'static str,
151    usize,
152    Vec<TypeDef>,
153    Option<TypeDef>,
154    JsClassMemberKind,
155);
156
157impl JsClassMemberSpec {
158    pub(crate) fn parts(&self) -> JsClassMemberParts {
159        (
160            self.class_name,
161            self.member_name,
162            self.export_name,
163            self.arg_count,
164            (self.arg_types)(),
165            (self.return_type)(),
166            self.kind,
167        )
168    }
169}
170
171inventory::collect!(JsClassMemberSpec);
172
173#[derive(Clone, Copy)]
174pub struct JsExportSpec {
175    name: &'static str,
176    handler: fn(&mut super::DecodedData) -> Result<super::EncodedData, String>,
177}
178
179impl JsExportSpec {
180    pub const fn new(
181        name: &'static str,
182        handler: fn(&mut super::DecodedData) -> Result<super::EncodedData, String>,
183    ) -> Self {
184        Self { name, handler }
185    }
186
187    pub(crate) fn call_if_name(
188        &self,
189        name: &str,
190        data: &mut super::DecodedData<'_>,
191    ) -> Option<Result<super::EncodedData, String>> {
192        (self.name == name).then(|| (self.handler)(data))
193    }
194}
195
196inventory::collect!(JsExportSpec);