wasm_bridge_js/conversions/
to_js_value.rs1use js_sys::{
2 Array, BigInt64Array, BigUint64Array, Float32Array, Float64Array, Int16Array, Int32Array,
3 Int8Array, Object, Reflect, Uint16Array, Uint32Array, Uint8Array,
4};
5use wasm_bindgen::{
6 convert::{IntoWasmAbi, ReturnWasmAbi},
7 JsValue,
8};
9
10use crate::{helpers::static_str_to_js, Val};
11
12pub trait ToJsValue: Sized {
13 type ReturnAbi: ReturnWasmAbi + IntoWasmAbi;
14
15 fn to_js_value(&self) -> JsValue;
16
17 fn into_return_abi(self) -> Result<Self::ReturnAbi, JsValue>;
19
20 fn number_of_args() -> u32 {
22 1
23 }
24
25 fn to_function_args(&self) -> Array {
27 Array::of1(&self.to_js_value())
28 }
29
30 fn create_array_of_size(size: u32) -> JsValue {
32 Array::new_with_length(size).into()
33 }
34}
35
36impl ToJsValue for () {
37 type ReturnAbi = Self;
38
39 fn to_js_value(&self) -> JsValue {
40 JsValue::undefined()
41 }
42
43 fn into_return_abi(self) -> Result<Self::ReturnAbi, JsValue> {
44 Ok(())
45 }
46
47 fn number_of_args() -> u32 {
48 0
49 }
50
51 fn to_function_args(&self) -> Array {
52 Array::new()
53 }
54}
55
56macro_rules! to_js_value_single {
57 ($ty: ty, $array: ty) => {
58 impl ToJsValue for $ty {
59 type ReturnAbi = Self;
60
61 fn to_js_value(&self) -> JsValue {
62 (*self).into()
63 }
64
65 fn into_return_abi(self) -> Result<Self::ReturnAbi, JsValue> {
66 Ok(self)
67 }
68
69 fn create_array_of_size(size: u32) -> JsValue {
70 <$array>::new_with_length(size).into()
71 }
72 }
73 };
74}
75
76to_js_value_single!(bool, Array);
77
78to_js_value_single!(i8, Int8Array);
79to_js_value_single!(i16, Int16Array);
80to_js_value_single!(i32, Int32Array);
81to_js_value_single!(i64, BigInt64Array);
82
83to_js_value_single!(u8, Uint8Array);
84to_js_value_single!(u16, Uint16Array);
85to_js_value_single!(u32, Uint32Array);
86to_js_value_single!(u64, BigUint64Array);
87
88to_js_value_single!(f32, Float32Array);
89to_js_value_single!(f64, Float64Array);
90
91impl ToJsValue for char {
92 type ReturnAbi = Self;
93
94 fn to_js_value(&self) -> JsValue {
95 self.to_string().into()
97 }
98
99 fn into_return_abi(self) -> Result<Self::ReturnAbi, JsValue> {
100 Ok(self)
101 }
102}
103
104impl<'a> ToJsValue for &'a str {
105 type ReturnAbi = Self;
106
107 fn to_js_value(&self) -> JsValue {
108 (*self).into()
109 }
110
111 fn into_return_abi(self) -> Result<Self::ReturnAbi, JsValue> {
112 Ok(self)
113 }
114}
115
116impl ToJsValue for String {
117 type ReturnAbi = Self;
118
119 fn to_js_value(&self) -> JsValue {
120 self.into()
121 }
122
123 fn into_return_abi(self) -> Result<Self::ReturnAbi, JsValue> {
124 Ok(self)
125 }
126}
127
128impl<T: ToJsValue> ToJsValue for Option<T> {
130 type ReturnAbi = JsValue;
131
132 fn to_js_value(&self) -> JsValue {
133 match self {
134 Self::Some(value) => value.to_js_value(),
135 None => JsValue::undefined(),
136 }
137 }
138
139 fn into_return_abi(self) -> Result<Self::ReturnAbi, JsValue> {
140 Ok(self.to_js_value())
141 }
142}
143
144impl<T: ToJsValue, E: ToJsValue> ToJsValue for Result<T, E> {
145 type ReturnAbi = T::ReturnAbi;
146
147 fn to_js_value(&self) -> JsValue {
148 let result: JsValue = Object::new().into();
149 let (tag, val) = match self {
150 Ok(value) => ("ok", value.to_js_value()),
151 Err(err) => ("err", err.to_js_value()),
152 };
153 Reflect::set(&result, static_str_to_js("tag"), &tag.into()).unwrap();
154 Reflect::set(&result, static_str_to_js("val"), &val).unwrap();
155 result
156 }
157
158 fn into_return_abi(self) -> Result<Self::ReturnAbi, JsValue> {
159 match self {
160 Ok(value) => Ok(value.into_return_abi()?),
162 Err(err) => Err(err.to_js_value()),
163 }
164 }
165}
166
167impl<'a, T: ToJsValue> ToJsValue for &'a T {
168 type ReturnAbi = T::ReturnAbi;
169
170 fn to_js_value(&self) -> JsValue {
171 T::to_js_value(self)
172 }
173
174 fn into_return_abi(self) -> Result<Self::ReturnAbi, JsValue> {
175 unimplemented!("References should never be returned")
176 }
177}
178
179impl<'a, T: ToJsValue> ToJsValue for &'a [T] {
181 type ReturnAbi = JsValue;
182
183 fn to_js_value(&self) -> JsValue {
184 let array = T::create_array_of_size(self.len() as _);
185 self.iter().enumerate().for_each(|(index, item)| {
186 Reflect::set_u32(&array, index as _, &item.to_js_value()).expect("array is array");
188 });
189 array
190 }
191
192 fn into_return_abi(self) -> Result<Self::ReturnAbi, JsValue> {
193 Ok(self.to_js_value())
194 }
195}
196
197impl<T: ToJsValue> ToJsValue for Vec<T> {
198 type ReturnAbi = JsValue;
199
200 fn to_js_value(&self) -> JsValue {
201 let as_slice: &[T] = self;
202 as_slice.to_js_value()
203 }
204
205 fn into_return_abi(self) -> Result<Self::ReturnAbi, JsValue> {
206 Ok(self.to_js_value())
207 }
208}
209
210impl ToJsValue for JsValue {
211 type ReturnAbi = Self;
212
213 fn to_js_value(&self) -> JsValue {
214 self.clone()
215 }
216
217 fn into_return_abi(self) -> Result<Self::ReturnAbi, JsValue> {
218 Ok(self)
219 }
220}
221
222impl ToJsValue for Val {
223 type ReturnAbi = JsValue;
224
225 fn to_js_value(&self) -> JsValue {
226 match self {
227 Val::I32(val) => val.to_js_value(),
228 Val::I64(val) => val.to_js_value(),
229 Val::F32(bits) => f32::from_bits(*bits).to_js_value(),
230 Val::F64(bits) => f64::from_bits(*bits).to_js_value(),
231 }
232 }
233
234 fn into_return_abi(self) -> Result<Self::ReturnAbi, JsValue> {
235 Ok(self.to_js_value())
236 }
237}
238
239impl<T: ToJsValue> ToJsValue for (T,) {
240 type ReturnAbi = T::ReturnAbi;
241
242 fn to_js_value(&self) -> JsValue {
243 self.0.to_js_value()
244 }
245
246 fn into_return_abi(self) -> Result<Self::ReturnAbi, JsValue> {
247 self.0.into_return_abi()
248 }
249
250 fn number_of_args() -> u32 {
251 T::number_of_args()
252 }
253
254 fn to_function_args(&self) -> Array {
255 self.0.to_function_args()
256 }
257}
258
259macro_rules! to_js_value_many {
260 ($count: literal, $(($index: tt, $name: ident)),*) => {
261 impl<$($name: ToJsValue),*> ToJsValue for ($($name, )*) {
262 type ReturnAbi = JsValue;
263
264 fn to_js_value(&self) -> JsValue {
265 self.to_function_args().into()
266 }
267
268 fn into_return_abi(self) -> Result<Self::ReturnAbi, JsValue> {
269 Ok(self.to_js_value())
270 }
271
272 fn number_of_args() -> u32 {
273 $count
274 }
275
276 fn to_function_args(&self) -> Array {
277 [$( &self.$index.to_js_value(), )*].iter().collect()
278 }
279 }
280 };
281}
282
283#[rustfmt::skip]
284to_js_value_many!( 2, (0, T0), (1, T1));
285#[rustfmt::skip]
286to_js_value_many!( 3, (0, T0), (1, T1), (2, T2));
287#[rustfmt::skip]
288to_js_value_many!( 4, (0, T0), (1, T1), (2, T2), (3, T3));
289#[rustfmt::skip]
290to_js_value_many!( 5, (0, T0), (1, T1), (2, T2), (3, T3), (4, T4));
291#[rustfmt::skip]
292to_js_value_many!( 6, (0, T0), (1, T1), (2, T2), (3, T3), (4, T4), (5, T5));
293#[rustfmt::skip]
294to_js_value_many!( 7, (0, T0), (1, T1), (2, T2), (3, T3), (4, T4), (5, T5), (6, T6));
295#[rustfmt::skip]
296to_js_value_many!( 8, (0, T0), (1, T1), (2, T2), (3, T3), (4, T4), (5, T5), (6, T6), (7, T7));
297
298