wasm_bindgen/convert/
impls.rs1use alloc::boxed::Box;
2use alloc::vec::Vec;
3use core::char;
4use core::fmt::Debug;
5use core::mem::{self, ManuallyDrop};
6use core::ptr::NonNull;
7
8use crate::convert::traits::{WasmAbi, WasmPrimitive};
9use crate::convert::TryFromJsValue;
10use crate::convert::{FromWasmAbi, IntoWasmAbi, LongRefFromWasmAbi, RefFromWasmAbi};
11use crate::convert::{OptionFromWasmAbi, OptionIntoWasmAbi, ReturnWasmAbi};
12use crate::{Clamped, JsError, JsValue, UnwrapThrowExt};
13
14impl<T: WasmPrimitive> WasmAbi for T {
16 type Prim1 = Self;
17 type Prim2 = ();
18 type Prim3 = ();
19 type Prim4 = ();
20
21 #[inline]
22 fn split(self) -> (Self, (), (), ()) {
23 (self, (), (), ())
24 }
25
26 #[inline]
27 fn join(prim: Self, _: (), _: (), _: ()) -> Self {
28 prim
29 }
30}
31
32impl<T: WasmAbi<Prim4 = ()>> WasmAbi for Option<T> {
33 type Prim1 = u32;
35 type Prim2 = T::Prim1;
36 type Prim3 = T::Prim2;
37 type Prim4 = T::Prim3;
38
39 #[inline]
40 fn split(self) -> (u32, T::Prim1, T::Prim2, T::Prim3) {
41 match self {
42 None => (
43 0,
44 Default::default(),
45 Default::default(),
46 Default::default(),
47 ),
48 Some(value) => {
49 let (prim1, prim2, prim3, ()) = value.split();
50 (1, prim1, prim2, prim3)
51 }
52 }
53 }
54
55 #[inline]
56 fn join(is_some: u32, prim1: T::Prim1, prim2: T::Prim2, prim3: T::Prim3) -> Self {
57 if is_some == 0 {
58 None
59 } else {
60 Some(T::join(prim1, prim2, prim3, ()))
61 }
62 }
63}
64
65macro_rules! type_wasm_native {
66 ($($t:tt as $c:tt)*) => ($(
67 impl IntoWasmAbi for $t {
68 type Abi = $c;
69
70 #[inline]
71 fn into_abi(self) -> $c { self as $c }
72 }
73
74 impl FromWasmAbi for $t {
75 type Abi = $c;
76
77 #[inline]
78 unsafe fn from_abi(js: $c) -> Self { js as $t }
79 }
80
81 impl IntoWasmAbi for Option<$t> {
82 type Abi = Option<$c>;
83
84 #[inline]
85 fn into_abi(self) -> Self::Abi {
86 self.map(|v| v as $c)
87 }
88 }
89
90 impl FromWasmAbi for Option<$t> {
91 type Abi = Option<$c>;
92
93 #[inline]
94 unsafe fn from_abi(js: Self::Abi) -> Self {
95 js.map(|v: $c| v as $t)
96 }
97 }
98 )*)
99}
100
101type_wasm_native!(
102 i32 as i32
103 isize as i32
104 u32 as u32
105 usize as u32
106 i64 as i64
107 u64 as u64
108 f32 as f32
109 f64 as f64
110);
111
112macro_rules! type_abi_as_u32 {
113 ($($t:tt)*) => ($(
114 impl IntoWasmAbi for $t {
115 type Abi = u32;
116
117 #[inline]
118 fn into_abi(self) -> u32 { self as u32 }
119 }
120
121 impl FromWasmAbi for $t {
122 type Abi = u32;
123
124 #[inline]
125 unsafe fn from_abi(js: u32) -> Self { js as $t }
126 }
127
128 impl OptionIntoWasmAbi for $t {
129 #[inline]
130 fn none() -> u32 { 0x00FF_FFFFu32 }
131 }
132
133 impl OptionFromWasmAbi for $t {
134 #[inline]
135 fn is_none(js: &u32) -> bool { *js == 0x00FF_FFFFu32 }
136 }
137 )*)
138}
139
140type_abi_as_u32!(i8 u8 i16 u16);
141
142impl IntoWasmAbi for bool {
143 type Abi = u32;
144
145 #[inline]
146 fn into_abi(self) -> u32 {
147 self as u32
148 }
149}
150
151impl FromWasmAbi for bool {
152 type Abi = u32;
153
154 #[inline]
155 unsafe fn from_abi(js: u32) -> bool {
156 js != 0
157 }
158}
159
160impl OptionIntoWasmAbi for bool {
161 #[inline]
162 fn none() -> u32 {
163 0x00FF_FFFFu32
164 }
165}
166
167impl OptionFromWasmAbi for bool {
168 #[inline]
169 fn is_none(js: &u32) -> bool {
170 *js == 0x00FF_FFFFu32
171 }
172}
173
174impl IntoWasmAbi for char {
175 type Abi = u32;
176
177 #[inline]
178 fn into_abi(self) -> u32 {
179 self as u32
180 }
181}
182
183impl FromWasmAbi for char {
184 type Abi = u32;
185
186 #[inline]
187 unsafe fn from_abi(js: u32) -> char {
188 char::from_u32_unchecked(js)
190 }
191}
192
193impl OptionIntoWasmAbi for char {
194 #[inline]
195 fn none() -> u32 {
196 0x00FF_FFFFu32
197 }
198}
199
200impl OptionFromWasmAbi for char {
201 #[inline]
202 fn is_none(js: &u32) -> bool {
203 *js == 0x00FF_FFFFu32
204 }
205}
206
207impl<T> IntoWasmAbi for *const T {
208 type Abi = u32;
209
210 #[inline]
211 fn into_abi(self) -> u32 {
212 self as u32
213 }
214}
215
216impl<T> FromWasmAbi for *const T {
217 type Abi = u32;
218
219 #[inline]
220 unsafe fn from_abi(js: u32) -> *const T {
221 js as *const T
222 }
223}
224
225impl<T> IntoWasmAbi for Option<*const T> {
226 type Abi = Option<u32>;
227
228 #[inline]
229 fn into_abi(self) -> Option<u32> {
230 self.map(|ptr| ptr as u32)
231 }
232}
233
234impl<T> FromWasmAbi for Option<*const T> {
235 type Abi = Option<u32>;
236
237 #[inline]
238 unsafe fn from_abi(js: Option<u32>) -> Option<*const T> {
239 js.map(|ptr| ptr as *const T)
240 }
241}
242
243impl<T> IntoWasmAbi for *mut T {
244 type Abi = u32;
245
246 #[inline]
247 fn into_abi(self) -> u32 {
248 self as u32
249 }
250}
251
252impl<T> FromWasmAbi for *mut T {
253 type Abi = u32;
254
255 #[inline]
256 unsafe fn from_abi(js: u32) -> *mut T {
257 js as *mut T
258 }
259}
260
261impl<T> IntoWasmAbi for Option<*mut T> {
262 type Abi = Option<u32>;
263
264 #[inline]
265 fn into_abi(self) -> Option<u32> {
266 self.map(|ptr| ptr as u32)
267 }
268}
269
270impl<T> FromWasmAbi for Option<*mut T> {
271 type Abi = Option<u32>;
272
273 #[inline]
274 unsafe fn from_abi(js: Option<u32>) -> Option<*mut T> {
275 js.map(|ptr| ptr as *mut T)
276 }
277}
278
279impl<T> IntoWasmAbi for NonNull<T> {
280 type Abi = u32;
281
282 #[inline]
283 fn into_abi(self) -> u32 {
284 self.as_ptr() as u32
285 }
286}
287
288impl<T> OptionIntoWasmAbi for NonNull<T> {
289 #[inline]
290 fn none() -> u32 {
291 0
292 }
293}
294
295impl<T> FromWasmAbi for NonNull<T> {
296 type Abi = u32;
297
298 #[inline]
299 unsafe fn from_abi(js: Self::Abi) -> Self {
300 NonNull::new_unchecked(js as *mut T)
302 }
303}
304
305impl<T> OptionFromWasmAbi for NonNull<T> {
306 #[inline]
307 fn is_none(js: &u32) -> bool {
308 *js == 0
309 }
310}
311
312impl IntoWasmAbi for JsValue {
313 type Abi = u32;
314
315 #[inline]
316 fn into_abi(self) -> u32 {
317 let ret = self.idx;
318 mem::forget(self);
319 ret
320 }
321}
322
323impl FromWasmAbi for JsValue {
324 type Abi = u32;
325
326 #[inline]
327 unsafe fn from_abi(js: u32) -> JsValue {
328 JsValue::_new(js)
329 }
330}
331
332impl<'a> IntoWasmAbi for &'a JsValue {
333 type Abi = u32;
334
335 #[inline]
336 fn into_abi(self) -> u32 {
337 self.idx
338 }
339}
340
341impl RefFromWasmAbi for JsValue {
342 type Abi = u32;
343 type Anchor = ManuallyDrop<JsValue>;
344
345 #[inline]
346 unsafe fn ref_from_abi(js: u32) -> Self::Anchor {
347 ManuallyDrop::new(JsValue::_new(js))
348 }
349}
350
351impl LongRefFromWasmAbi for JsValue {
352 type Abi = u32;
353 type Anchor = JsValue;
354
355 #[inline]
356 unsafe fn long_ref_from_abi(js: u32) -> Self::Anchor {
357 Self::from_abi(js)
358 }
359}
360
361impl<T: OptionIntoWasmAbi> IntoWasmAbi for Option<T> {
362 type Abi = T::Abi;
363
364 #[inline]
365 fn into_abi(self) -> T::Abi {
366 match self {
367 None => T::none(),
368 Some(me) => me.into_abi(),
369 }
370 }
371}
372
373impl<T: OptionFromWasmAbi> FromWasmAbi for Option<T> {
374 type Abi = T::Abi;
375
376 #[inline]
377 unsafe fn from_abi(js: T::Abi) -> Self {
378 if T::is_none(&js) {
379 None
380 } else {
381 Some(T::from_abi(js))
382 }
383 }
384}
385
386impl<T: IntoWasmAbi> IntoWasmAbi for Clamped<T> {
387 type Abi = T::Abi;
388
389 #[inline]
390 fn into_abi(self) -> Self::Abi {
391 self.0.into_abi()
392 }
393}
394
395impl<T: FromWasmAbi> FromWasmAbi for Clamped<T> {
396 type Abi = T::Abi;
397
398 #[inline]
399 unsafe fn from_abi(js: T::Abi) -> Self {
400 Clamped(T::from_abi(js))
401 }
402}
403
404impl IntoWasmAbi for () {
405 type Abi = ();
406
407 #[inline]
408 fn into_abi(self) {
409 self
410 }
411}
412
413impl<T: WasmAbi<Prim3 = (), Prim4 = ()>> WasmAbi for Result<T, u32> {
414 type Prim1 = T::Prim1;
415 type Prim2 = T::Prim2;
416 type Prim3 = u32;
421 type Prim4 = u32;
423
424 #[inline]
425 fn split(self) -> (T::Prim1, T::Prim2, u32, u32) {
426 match self {
427 Ok(value) => {
428 let (prim1, prim2, (), ()) = value.split();
429 (prim1, prim2, 0, 0)
430 }
431 Err(err) => (Default::default(), Default::default(), err, 1),
432 }
433 }
434
435 #[inline]
436 fn join(prim1: T::Prim1, prim2: T::Prim2, err: u32, is_err: u32) -> Self {
437 if is_err == 0 {
438 Ok(T::join(prim1, prim2, (), ()))
439 } else {
440 Err(err)
441 }
442 }
443}
444
445impl<T, E> ReturnWasmAbi for Result<T, E>
446where
447 T: IntoWasmAbi,
448 E: Into<JsValue>,
449 T::Abi: WasmAbi<Prim3 = (), Prim4 = ()>,
450{
451 type Abi = Result<T::Abi, u32>;
452
453 #[inline]
454 fn return_abi(self) -> Self::Abi {
455 match self {
456 Ok(v) => Ok(v.into_abi()),
457 Err(e) => {
458 let jsval = e.into();
459 Err(jsval.into_abi())
460 }
461 }
462 }
463}
464
465impl IntoWasmAbi for JsError {
466 type Abi = <JsValue as IntoWasmAbi>::Abi;
467
468 fn into_abi(self) -> Self::Abi {
469 self.value.into_abi()
470 }
471}
472
473pub fn js_value_vector_into_abi<T: Into<JsValue>>(
481 vector: Box<[T]>,
482) -> <Box<[JsValue]> as IntoWasmAbi>::Abi {
483 let js_vals: Box<[JsValue]> = vector.into_vec().into_iter().map(|x| x.into()).collect();
484
485 js_vals.into_abi()
486}
487
488pub unsafe fn js_value_vector_from_abi<T: TryFromJsValue>(
494 js: <Box<[JsValue]> as FromWasmAbi>::Abi,
495) -> Box<[T]>
496where
497 T::Error: Debug,
498{
499 let js_vals = <Vec<JsValue> as FromWasmAbi>::from_abi(js);
500
501 let mut result = Vec::with_capacity(js_vals.len());
502 for value in js_vals {
503 result.push(
514 T::try_from_js_value(value).expect_throw("array contains a value of the wrong type"),
515 );
516 }
517 result.into_boxed_slice()
518}