1 | use alloc::boxed::Box; |
2 | use alloc::vec::Vec; |
3 | use core::char; |
4 | use core::fmt::Debug; |
5 | use core::mem::{self, ManuallyDrop}; |
6 | use core::ptr::NonNull; |
7 | |
8 | use crate::convert::traits::{WasmAbi, WasmPrimitive}; |
9 | use crate::convert::TryFromJsValue; |
10 | use crate::convert::{FromWasmAbi, IntoWasmAbi, LongRefFromWasmAbi, RefFromWasmAbi}; |
11 | use crate::convert::{OptionFromWasmAbi, OptionIntoWasmAbi, ReturnWasmAbi}; |
12 | use crate::{Clamped, JsError, JsValue, UnwrapThrowExt}; |
13 | |
14 | // Primitive types can always be passed over the ABI. |
15 | impl<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 | |
32 | impl 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: u64 = self as u64; |
41 | let high: u64 = (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 | } |
50 | impl 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: u64 = self as u64; |
59 | let high: u64 = (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 | |
69 | impl<T: WasmAbi<Prim4 = ()>> WasmAbi for Option<T> { |
70 | /// Whether this `Option` is a `Some` value. |
71 | 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 | |
102 | macro_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 | |
138 | type_wasm_native!( |
139 | i64 as i64 |
140 | u64 as u64 |
141 | i128 as i128 |
142 | u128 as u128 |
143 | f64 as f64 |
144 | ); |
145 | |
146 | /// The sentinel value is 2^32 + 1 for 32-bit primitive types. |
147 | /// |
148 | /// 2^32 + 1 is used, because it's the smallest positive integer that cannot be |
149 | /// represented by any 32-bit primitive. While any value >= 2^32 works as a |
150 | /// sentinel value for 32-bit integers, it's a bit more tricky for `f32`. `f32` |
151 | /// can represent all powers of 2 up to 2^127 exactly. And between 2^32 and 2^33, |
152 | /// `f32` can represent all integers 2^32+512*k exactly. |
153 | const F64_ABI_OPTION_SENTINEL: f64 = 4294967297_f64; |
154 | |
155 | macro_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 | |
195 | type_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 | |
203 | /// The sentinel value is 0xFF_FFFF for primitives with less than 32 bits. |
204 | /// |
205 | /// This value is used, so all small primitive types (`bool`, `i8`, `u8`, |
206 | /// `i16`, `u16`, `char`) can use the same JS glue code. `char::MAX` is |
207 | /// 0x10_FFFF btw. |
208 | const U32_ABI_OPTION_SENTINEL: u32 = 0x00FF_FFFFu32; |
209 | |
210 | macro_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 | |
238 | type_abi_as_u32!(i8 u8 i16 u16); |
239 | |
240 | impl IntoWasmAbi for bool { |
241 | type Abi = u32; |
242 | |
243 | #[inline ] |
244 | fn into_abi(self) -> u32 { |
245 | self as u32 |
246 | } |
247 | } |
248 | |
249 | impl FromWasmAbi for bool { |
250 | type Abi = u32; |
251 | |
252 | #[inline ] |
253 | unsafe fn from_abi(js: u32) -> bool { |
254 | js != 0 |
255 | } |
256 | } |
257 | |
258 | impl OptionIntoWasmAbi for bool { |
259 | #[inline ] |
260 | fn none() -> u32 { |
261 | U32_ABI_OPTION_SENTINEL |
262 | } |
263 | } |
264 | |
265 | impl OptionFromWasmAbi for bool { |
266 | #[inline ] |
267 | fn is_none(js: &u32) -> bool { |
268 | *js == U32_ABI_OPTION_SENTINEL |
269 | } |
270 | } |
271 | |
272 | impl IntoWasmAbi for char { |
273 | type Abi = u32; |
274 | |
275 | #[inline ] |
276 | fn into_abi(self) -> u32 { |
277 | self as u32 |
278 | } |
279 | } |
280 | |
281 | impl FromWasmAbi for char { |
282 | type Abi = u32; |
283 | |
284 | #[inline ] |
285 | unsafe fn from_abi(js: u32) -> char { |
286 | // SAFETY: Checked in bindings. |
287 | char::from_u32_unchecked(js) |
288 | } |
289 | } |
290 | |
291 | impl OptionIntoWasmAbi for char { |
292 | #[inline ] |
293 | fn none() -> u32 { |
294 | U32_ABI_OPTION_SENTINEL |
295 | } |
296 | } |
297 | |
298 | impl OptionFromWasmAbi for char { |
299 | #[inline ] |
300 | fn is_none(js: &u32) -> bool { |
301 | *js == U32_ABI_OPTION_SENTINEL |
302 | } |
303 | } |
304 | |
305 | impl<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 | |
314 | impl<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 | |
323 | impl<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 | |
333 | impl<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 | |
346 | impl<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 | |
355 | impl<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 | |
364 | impl<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 | |
374 | impl<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 | |
387 | impl<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 | |
396 | impl<T> OptionIntoWasmAbi for NonNull<T> { |
397 | #[inline ] |
398 | fn none() -> u32 { |
399 | 0 |
400 | } |
401 | } |
402 | |
403 | impl<T> FromWasmAbi for NonNull<T> { |
404 | type Abi = u32; |
405 | |
406 | #[inline ] |
407 | unsafe fn from_abi(js: Self::Abi) -> Self { |
408 | // SAFETY: Checked in bindings. |
409 | NonNull::new_unchecked(ptr:js as *mut T) |
410 | } |
411 | } |
412 | |
413 | impl<T> OptionFromWasmAbi for NonNull<T> { |
414 | #[inline ] |
415 | fn is_none(js: &u32) -> bool { |
416 | *js == 0 |
417 | } |
418 | } |
419 | |
420 | impl IntoWasmAbi for JsValue { |
421 | type Abi = u32; |
422 | |
423 | #[inline ] |
424 | fn into_abi(self) -> u32 { |
425 | let ret: u32 = self.idx; |
426 | mem::forget(self); |
427 | ret |
428 | } |
429 | } |
430 | |
431 | impl FromWasmAbi for JsValue { |
432 | type Abi = u32; |
433 | |
434 | #[inline ] |
435 | unsafe fn from_abi(js: u32) -> JsValue { |
436 | JsValue::_new(idx:js) |
437 | } |
438 | } |
439 | |
440 | impl IntoWasmAbi for &JsValue { |
441 | type Abi = u32; |
442 | |
443 | #[inline ] |
444 | fn into_abi(self) -> u32 { |
445 | self.idx |
446 | } |
447 | } |
448 | |
449 | impl 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(idx:js)) |
456 | } |
457 | } |
458 | |
459 | impl 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 | |
469 | impl<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: T) => me.into_abi(), |
477 | } |
478 | } |
479 | } |
480 | |
481 | impl<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 | |
494 | impl<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 | |
503 | impl<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 | |
512 | impl IntoWasmAbi for () { |
513 | type Abi = (); |
514 | |
515 | #[inline ] |
516 | fn into_abi(self) { |
517 | self |
518 | } |
519 | } |
520 | |
521 | impl<T: WasmAbi<Prim3 = (), Prim4 = ()>> WasmAbi for Result<T, u32> { |
522 | type Prim1 = T::Prim1; |
523 | type Prim2 = T::Prim2; |
524 | // The order of primitives here is such that we can pop() the possible error |
525 | // first, deal with it and move on. Later primitives are popped off the |
526 | // stack first. |
527 | /// If this `Result` is an `Err`, the error value. |
528 | type Prim3 = u32; |
529 | /// Whether this `Result` is an `Err`. |
530 | 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 | |
553 | impl<T, E> ReturnWasmAbi for Result<T, E> |
554 | where |
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: T) => Ok(v.into_abi()), |
565 | Err(e: E) => { |
566 | let jsval = e.into(); |
567 | Err(jsval.into_abi()) |
568 | } |
569 | } |
570 | } |
571 | } |
572 | |
573 | impl 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 | |
581 | /// # ⚠️ Unstable |
582 | /// |
583 | /// This is part of the internal [`convert`](crate::convert) module, **no |
584 | /// stability guarantees** are provided. Use at your own risk. See its |
585 | /// documentation for more details. |
586 | // Note: this can't take `&[T]` because the `Into<JsValue>` impl needs |
587 | // ownership of `T`. |
588 | pub 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: T| x.into()).collect(); |
592 | |
593 | js_vals.into_abi() |
594 | } |
595 | |
596 | /// # ⚠️ Unstable |
597 | /// |
598 | /// This is part of the internal [`convert`](crate::convert) module, **no |
599 | /// stability guarantees** are provided. Use at your own risk. See its |
600 | /// documentation for more details. |
601 | pub unsafe fn js_value_vector_from_abi<T: TryFromJsValue>( |
602 | js: <Box<[JsValue]> as FromWasmAbi>::Abi, |
603 | ) -> Box<[T]> |
604 | where |
605 | T::Error: Debug, |
606 | { |
607 | let js_vals: Vec = <Vec<JsValue> as FromWasmAbi>::from_abi(js); |
608 | |
609 | let mut result: Vec = Vec::with_capacity(js_vals.len()); |
610 | for value: JsValue in js_vals { |
611 | // We push elements one-by-one instead of using `collect` in order to improve |
612 | // error messages. When using `collect`, this `expect_throw` is buried in a |
613 | // giant chain of internal iterator functions, which results in the actual |
614 | // function that takes this `Vec` falling off the end of the call stack. |
615 | // So instead, make sure to call it directly within this function. |
616 | // |
617 | // This is only a problem in debug mode. Since this is the browser's error stack |
618 | // we're talking about, it can only see functions that actually make it to the |
619 | // final Wasm binary (i.e., not inlined functions). All of those internal |
620 | // iterator functions get inlined in release mode, and so they don't show up. |
621 | result.push( |
622 | T::try_from_js_value(value).expect_throw(message:"array contains a value of the wrong type" ), |
623 | ); |
624 | } |
625 | result.into_boxed_slice() |
626 | } |
627 | |