1use 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 WasmAbi for i128 {
33 type Prim1 = u64;
34 type Prim2 = u64;
35 type Prim3 = ();
36 type Prim4 = ();
37
38 #[inline]
39 fn split(self) -> (u64, u64, (), ()) {
40 let low = self as u64;
41 let high = (self >> 64) as u64;
42 (low, high, (), ())
43 }
44
45 #[inline]
46 fn join(low: u64, high: u64, _: (), _: ()) -> Self {
47 ((high as u128) << 64 | low as u128) as i128
48 }
49}
50impl WasmAbi for u128 {
51 type Prim1 = u64;
52 type Prim2 = u64;
53 type Prim3 = ();
54 type Prim4 = ();
55
56 #[inline]
57 fn split(self) -> (u64, u64, (), ()) {
58 let low = self as u64;
59 let high = (self >> 64) as u64;
60 (low, high, (), ())
61 }
62
63 #[inline]
64 fn join(low: u64, high: u64, _: (), _: ()) -> Self {
65 (high as u128) << 64 | low as u128
66 }
67}
68
69impl<T: WasmAbi<Prim4 = ()>> WasmAbi for Option<T> {
70 type Prim1 = u32;
72 type Prim2 = T::Prim1;
73 type Prim3 = T::Prim2;
74 type Prim4 = T::Prim3;
75
76 #[inline]
77 fn split(self) -> (u32, T::Prim1, T::Prim2, T::Prim3) {
78 match self {
79 None => (
80 0,
81 Default::default(),
82 Default::default(),
83 Default::default(),
84 ),
85 Some(value) => {
86 let (prim1, prim2, prim3, ()) = value.split();
87 (1, prim1, prim2, prim3)
88 }
89 }
90 }
91
92 #[inline]
93 fn join(is_some: u32, prim1: T::Prim1, prim2: T::Prim2, prim3: T::Prim3) -> Self {
94 if is_some == 0 {
95 None
96 } else {
97 Some(T::join(prim1, prim2, prim3, ()))
98 }
99 }
100}
101
102macro_rules! type_wasm_native {
103 ($($t:tt as $c:tt)*) => ($(
104 impl IntoWasmAbi for $t {
105 type Abi = $c;
106
107 #[inline]
108 fn into_abi(self) -> $c { self as $c }
109 }
110
111 impl FromWasmAbi for $t {
112 type Abi = $c;
113
114 #[inline]
115 unsafe fn from_abi(js: $c) -> Self { js as $t }
116 }
117
118 impl IntoWasmAbi for Option<$t> {
119 type Abi = Option<$c>;
120
121 #[inline]
122 fn into_abi(self) -> Self::Abi {
123 self.map(|v| v as $c)
124 }
125 }
126
127 impl FromWasmAbi for Option<$t> {
128 type Abi = Option<$c>;
129
130 #[inline]
131 unsafe fn from_abi(js: Self::Abi) -> Self {
132 js.map(|v: $c| v as $t)
133 }
134 }
135 )*)
136}
137
138type_wasm_native!(
139 i64 as i64
140 u64 as u64
141 i128 as i128
142 u128 as u128
143 f64 as f64
144);
145
146const F64_ABI_OPTION_SENTINEL: f64 = 4294967297_f64;
154
155macro_rules! type_wasm_native_f64_option {
156 ($($t:tt as $c:tt)*) => ($(
157 impl IntoWasmAbi for $t {
158 type Abi = $c;
159
160 #[inline]
161 fn into_abi(self) -> $c { self as $c }
162 }
163
164 impl FromWasmAbi for $t {
165 type Abi = $c;
166
167 #[inline]
168 unsafe fn from_abi(js: $c) -> Self { js as $t }
169 }
170
171 impl IntoWasmAbi for Option<$t> {
172 type Abi = f64;
173
174 #[inline]
175 fn into_abi(self) -> Self::Abi {
176 self.map(|v| v as $c as f64).unwrap_or(F64_ABI_OPTION_SENTINEL)
177 }
178 }
179
180 impl FromWasmAbi for Option<$t> {
181 type Abi = f64;
182
183 #[inline]
184 unsafe fn from_abi(js: Self::Abi) -> Self {
185 if js == F64_ABI_OPTION_SENTINEL {
186 None
187 } else {
188 Some(js as $c as $t)
189 }
190 }
191 }
192 )*)
193}
194
195type_wasm_native_f64_option!(
196 i32 as i32
197 isize as i32
198 u32 as u32
199 usize as u32
200 f32 as f32
201);
202
203const U32_ABI_OPTION_SENTINEL: u32 = 0x00FF_FFFFu32;
209
210macro_rules! type_abi_as_u32 {
211 ($($t:tt)*) => ($(
212 impl IntoWasmAbi for $t {
213 type Abi = u32;
214
215 #[inline]
216 fn into_abi(self) -> u32 { self as u32 }
217 }
218
219 impl FromWasmAbi for $t {
220 type Abi = u32;
221
222 #[inline]
223 unsafe fn from_abi(js: u32) -> Self { js as $t }
224 }
225
226 impl OptionIntoWasmAbi for $t {
227 #[inline]
228 fn none() -> u32 { U32_ABI_OPTION_SENTINEL }
229 }
230
231 impl OptionFromWasmAbi for $t {
232 #[inline]
233 fn is_none(js: &u32) -> bool { *js == U32_ABI_OPTION_SENTINEL }
234 }
235 )*)
236}
237
238type_abi_as_u32!(i8 u8 i16 u16);
239
240impl IntoWasmAbi for bool {
241 type Abi = u32;
242
243 #[inline]
244 fn into_abi(self) -> u32 {
245 self as u32
246 }
247}
248
249impl FromWasmAbi for bool {
250 type Abi = u32;
251
252 #[inline]
253 unsafe fn from_abi(js: u32) -> bool {
254 js != 0
255 }
256}
257
258impl OptionIntoWasmAbi for bool {
259 #[inline]
260 fn none() -> u32 {
261 U32_ABI_OPTION_SENTINEL
262 }
263}
264
265impl OptionFromWasmAbi for bool {
266 #[inline]
267 fn is_none(js: &u32) -> bool {
268 *js == U32_ABI_OPTION_SENTINEL
269 }
270}
271
272impl IntoWasmAbi for char {
273 type Abi = u32;
274
275 #[inline]
276 fn into_abi(self) -> u32 {
277 self as u32
278 }
279}
280
281impl FromWasmAbi for char {
282 type Abi = u32;
283
284 #[inline]
285 unsafe fn from_abi(js: u32) -> char {
286 char::from_u32_unchecked(js)
288 }
289}
290
291impl OptionIntoWasmAbi for char {
292 #[inline]
293 fn none() -> u32 {
294 U32_ABI_OPTION_SENTINEL
295 }
296}
297
298impl OptionFromWasmAbi for char {
299 #[inline]
300 fn is_none(js: &u32) -> bool {
301 *js == U32_ABI_OPTION_SENTINEL
302 }
303}
304
305impl<T> IntoWasmAbi for *const T {
306 type Abi = u32;
307
308 #[inline]
309 fn into_abi(self) -> u32 {
310 self as u32
311 }
312}
313
314impl<T> FromWasmAbi for *const T {
315 type Abi = u32;
316
317 #[inline]
318 unsafe fn from_abi(js: u32) -> *const T {
319 js as *const T
320 }
321}
322
323impl<T> IntoWasmAbi for Option<*const T> {
324 type Abi = f64;
325
326 #[inline]
327 fn into_abi(self) -> f64 {
328 self.map(|ptr| ptr as u32 as f64)
329 .unwrap_or(F64_ABI_OPTION_SENTINEL)
330 }
331}
332
333impl<T> FromWasmAbi for Option<*const T> {
334 type Abi = f64;
335
336 #[inline]
337 unsafe fn from_abi(js: f64) -> Option<*const T> {
338 if js == F64_ABI_OPTION_SENTINEL {
339 None
340 } else {
341 Some(js as u32 as *const T)
342 }
343 }
344}
345
346impl<T> IntoWasmAbi for *mut T {
347 type Abi = u32;
348
349 #[inline]
350 fn into_abi(self) -> u32 {
351 self as u32
352 }
353}
354
355impl<T> FromWasmAbi for *mut T {
356 type Abi = u32;
357
358 #[inline]
359 unsafe fn from_abi(js: u32) -> *mut T {
360 js as *mut T
361 }
362}
363
364impl<T> IntoWasmAbi for Option<*mut T> {
365 type Abi = f64;
366
367 #[inline]
368 fn into_abi(self) -> f64 {
369 self.map(|ptr| ptr as u32 as f64)
370 .unwrap_or(F64_ABI_OPTION_SENTINEL)
371 }
372}
373
374impl<T> FromWasmAbi for Option<*mut T> {
375 type Abi = f64;
376
377 #[inline]
378 unsafe fn from_abi(js: f64) -> Option<*mut T> {
379 if js == F64_ABI_OPTION_SENTINEL {
380 None
381 } else {
382 Some(js as u32 as *mut T)
383 }
384 }
385}
386
387impl<T> IntoWasmAbi for NonNull<T> {
388 type Abi = u32;
389
390 #[inline]
391 fn into_abi(self) -> u32 {
392 self.as_ptr() as u32
393 }
394}
395
396impl<T> OptionIntoWasmAbi for NonNull<T> {
397 #[inline]
398 fn none() -> u32 {
399 0
400 }
401}
402
403impl<T> FromWasmAbi for NonNull<T> {
404 type Abi = u32;
405
406 #[inline]
407 unsafe fn from_abi(js: Self::Abi) -> Self {
408 NonNull::new_unchecked(js as *mut T)
410 }
411}
412
413impl<T> OptionFromWasmAbi for NonNull<T> {
414 #[inline]
415 fn is_none(js: &u32) -> bool {
416 *js == 0
417 }
418}
419
420impl IntoWasmAbi for JsValue {
421 type Abi = u32;
422
423 #[inline]
424 fn into_abi(self) -> u32 {
425 let ret = self.idx;
426 mem::forget(self);
427 ret
428 }
429}
430
431impl FromWasmAbi for JsValue {
432 type Abi = u32;
433
434 #[inline]
435 unsafe fn from_abi(js: u32) -> JsValue {
436 JsValue::_new(js)
437 }
438}
439
440impl IntoWasmAbi for &JsValue {
441 type Abi = u32;
442
443 #[inline]
444 fn into_abi(self) -> u32 {
445 self.idx
446 }
447}
448
449impl RefFromWasmAbi for JsValue {
450 type Abi = u32;
451 type Anchor = ManuallyDrop<JsValue>;
452
453 #[inline]
454 unsafe fn ref_from_abi(js: u32) -> Self::Anchor {
455 ManuallyDrop::new(JsValue::_new(js))
456 }
457}
458
459impl LongRefFromWasmAbi for JsValue {
460 type Abi = u32;
461 type Anchor = JsValue;
462
463 #[inline]
464 unsafe fn long_ref_from_abi(js: u32) -> Self::Anchor {
465 Self::from_abi(js)
466 }
467}
468
469impl<T: OptionIntoWasmAbi> IntoWasmAbi for Option<T> {
470 type Abi = T::Abi;
471
472 #[inline]
473 fn into_abi(self) -> T::Abi {
474 match self {
475 None => T::none(),
476 Some(me) => me.into_abi(),
477 }
478 }
479}
480
481impl<T: OptionFromWasmAbi> FromWasmAbi for Option<T> {
482 type Abi = T::Abi;
483
484 #[inline]
485 unsafe fn from_abi(js: T::Abi) -> Self {
486 if T::is_none(&js) {
487 None
488 } else {
489 Some(T::from_abi(js))
490 }
491 }
492}
493
494impl<T: IntoWasmAbi> IntoWasmAbi for Clamped<T> {
495 type Abi = T::Abi;
496
497 #[inline]
498 fn into_abi(self) -> Self::Abi {
499 self.0.into_abi()
500 }
501}
502
503impl<T: FromWasmAbi> FromWasmAbi for Clamped<T> {
504 type Abi = T::Abi;
505
506 #[inline]
507 unsafe fn from_abi(js: T::Abi) -> Self {
508 Clamped(T::from_abi(js))
509 }
510}
511
512impl IntoWasmAbi for () {
513 type Abi = ();
514
515 #[inline]
516 fn into_abi(self) {
517 self
518 }
519}
520
521impl<T: WasmAbi<Prim3 = (), Prim4 = ()>> WasmAbi for Result<T, u32> {
522 type Prim1 = T::Prim1;
523 type Prim2 = T::Prim2;
524 type Prim3 = u32;
529 type Prim4 = u32;
531
532 #[inline]
533 fn split(self) -> (T::Prim1, T::Prim2, u32, u32) {
534 match self {
535 Ok(value) => {
536 let (prim1, prim2, (), ()) = value.split();
537 (prim1, prim2, 0, 0)
538 }
539 Err(err) => (Default::default(), Default::default(), err, 1),
540 }
541 }
542
543 #[inline]
544 fn join(prim1: T::Prim1, prim2: T::Prim2, err: u32, is_err: u32) -> Self {
545 if is_err == 0 {
546 Ok(T::join(prim1, prim2, (), ()))
547 } else {
548 Err(err)
549 }
550 }
551}
552
553impl<T, E> ReturnWasmAbi for Result<T, E>
554where
555 T: IntoWasmAbi,
556 E: Into<JsValue>,
557 T::Abi: WasmAbi<Prim3 = (), Prim4 = ()>,
558{
559 type Abi = Result<T::Abi, u32>;
560
561 #[inline]
562 fn return_abi(self) -> Self::Abi {
563 match self {
564 Ok(v) => Ok(v.into_abi()),
565 Err(e) => {
566 let jsval = e.into();
567 Err(jsval.into_abi())
568 }
569 }
570 }
571}
572
573impl IntoWasmAbi for JsError {
574 type Abi = <JsValue as IntoWasmAbi>::Abi;
575
576 fn into_abi(self) -> Self::Abi {
577 self.value.into_abi()
578 }
579}
580
581pub fn js_value_vector_into_abi<T: Into<JsValue>>(
589 vector: Box<[T]>,
590) -> <Box<[JsValue]> as IntoWasmAbi>::Abi {
591 let js_vals: Box<[JsValue]> = vector.into_vec().into_iter().map(|x| x.into()).collect();
592
593 js_vals.into_abi()
594}
595
596pub unsafe fn js_value_vector_from_abi<T: TryFromJsValue>(
602 js: <Box<[JsValue]> as FromWasmAbi>::Abi,
603) -> Box<[T]>
604where
605 T::Error: Debug,
606{
607 let js_vals = <Vec<JsValue> as FromWasmAbi>::from_abi(js);
608
609 let mut result = Vec::with_capacity(js_vals.len());
610 for value in js_vals {
611 result.push(
622 T::try_from_js_value(value).expect_throw("array contains a value of the wrong type"),
623 );
624 }
625 result.into_boxed_slice()
626}