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