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 OptionIntoWasmAbi for &JsValue {
476 #[inline]
477 fn none() -> u32 {
478 crate::__rt::JSIDX_UNDEFINED
479 }
480}
481
482impl OptionFromWasmAbi for JsValue {
483 #[inline]
484 fn is_none(js: &u32) -> bool {
485 unsafe { __wbindgen_object_is_undefined(*js) }
486 }
487}
488
489impl<T: OptionIntoWasmAbi> IntoWasmAbi for Option<T> {
490 type Abi = T::Abi;
491
492 #[inline]
493 fn into_abi(self) -> T::Abi {
494 match self {
495 None => T::none(),
496 Some(me) => me.into_abi(),
497 }
498 }
499}
500
501impl<T: OptionFromWasmAbi> FromWasmAbi for Option<T> {
502 type Abi = T::Abi;
503
504 #[inline]
505 unsafe fn from_abi(js: T::Abi) -> Self {
506 if T::is_none(&js) {
507 None
508 } else {
509 Some(T::from_abi(js))
510 }
511 }
512}
513
514impl<T: IntoWasmAbi> IntoWasmAbi for Clamped<T> {
515 type Abi = T::Abi;
516
517 #[inline]
518 fn into_abi(self) -> Self::Abi {
519 self.0.into_abi()
520 }
521}
522
523impl<T: FromWasmAbi> FromWasmAbi for Clamped<T> {
524 type Abi = T::Abi;
525
526 #[inline]
527 unsafe fn from_abi(js: T::Abi) -> Self {
528 Clamped(T::from_abi(js))
529 }
530}
531
532impl IntoWasmAbi for () {
533 type Abi = ();
534
535 #[inline]
536 fn into_abi(self) {
537 self
538 }
539}
540
541impl<T: WasmAbi<Prim3 = (), Prim4 = ()>> WasmAbi for Result<T, u32> {
542 type Prim1 = T::Prim1;
543 type Prim2 = T::Prim2;
544 type Prim3 = u32;
549 type Prim4 = u32;
551
552 #[inline]
553 fn split(self) -> (T::Prim1, T::Prim2, u32, u32) {
554 match self {
555 Ok(value) => {
556 let (prim1, prim2, (), ()) = value.split();
557 (prim1, prim2, 0, 0)
558 }
559 Err(err) => (Default::default(), Default::default(), err, 1),
560 }
561 }
562
563 #[inline]
564 fn join(prim1: T::Prim1, prim2: T::Prim2, err: u32, is_err: u32) -> Self {
565 if is_err == 0 {
566 Ok(T::join(prim1, prim2, (), ()))
567 } else {
568 Err(err)
569 }
570 }
571}
572
573impl<T, E> ReturnWasmAbi for Result<T, E>
574where
575 T: IntoWasmAbi,
576 E: Into<JsValue>,
577 T::Abi: WasmAbi<Prim3 = (), Prim4 = ()>,
578{
579 type Abi = Result<T::Abi, u32>;
580
581 #[inline]
582 fn return_abi(self) -> Self::Abi {
583 match self {
584 Ok(v) => Ok(v.into_abi()),
585 Err(e) => {
586 let jsval = e.into();
587 Err(jsval.into_abi())
588 }
589 }
590 }
591}
592
593impl IntoWasmAbi for JsError {
594 type Abi = <JsValue as IntoWasmAbi>::Abi;
595
596 fn into_abi(self) -> Self::Abi {
597 self.value.into_abi()
598 }
599}
600
601pub fn js_value_vector_into_abi<T: Into<JsValue>>(
609 vector: Box<[T]>,
610) -> <Box<[JsValue]> as IntoWasmAbi>::Abi {
611 let js_vals: Box<[JsValue]> = vector.into_vec().into_iter().map(|x| x.into()).collect();
612
613 js_vals.into_abi()
614}
615
616pub unsafe fn js_value_vector_from_abi<T: TryFromJsValue>(
622 js: <Box<[JsValue]> as FromWasmAbi>::Abi,
623) -> Box<[T]> {
624 let js_vals = <Vec<JsValue> as FromWasmAbi>::from_abi(js);
625
626 let mut result = Vec::with_capacity(js_vals.len());
627 for value in js_vals {
628 result.push(
639 T::try_from_js_value(value).expect_throw("array contains a value of the wrong type"),
640 );
641 }
642 result.into_boxed_slice()
643}