wry_bindgen_runtime/wire/
registry.rs1use 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);