diff options
Diffstat (limited to 'vendor/wasm-bindgen/src/convert')
-rw-r--r-- | vendor/wasm-bindgen/src/convert/closures.rs | 225 | ||||
-rw-r--r-- | vendor/wasm-bindgen/src/convert/impls.rs | 378 | ||||
-rw-r--r-- | vendor/wasm-bindgen/src/convert/mod.rs | 11 | ||||
-rw-r--r-- | vendor/wasm-bindgen/src/convert/slices.rs | 311 | ||||
-rw-r--r-- | vendor/wasm-bindgen/src/convert/traits.rs | 131 |
5 files changed, 1056 insertions, 0 deletions
diff --git a/vendor/wasm-bindgen/src/convert/closures.rs b/vendor/wasm-bindgen/src/convert/closures.rs new file mode 100644 index 000000000..97755b8ee --- /dev/null +++ b/vendor/wasm-bindgen/src/convert/closures.rs @@ -0,0 +1,225 @@ +use core::mem; + +use crate::convert::slices::WasmSlice; +use crate::convert::RefFromWasmAbi; +use crate::convert::{FromWasmAbi, IntoWasmAbi, ReturnWasmAbi}; +use crate::describe::{inform, WasmDescribe, FUNCTION}; +use crate::throw_str; + +macro_rules! stack_closures { + ($( ($cnt:tt $invoke:ident $invoke_mut:ident $($var:ident)*) )*) => ($( + impl<'a, 'b, $($var,)* R> IntoWasmAbi for &'a (dyn Fn($($var),*) -> R + 'b) + where $($var: FromWasmAbi,)* + R: ReturnWasmAbi + { + type Abi = WasmSlice; + + fn into_abi(self) -> WasmSlice { + unsafe { + let (a, b): (usize, usize) = mem::transmute(self); + WasmSlice { ptr: a as u32, len: b as u32 } + } + } + } + + #[allow(non_snake_case)] + unsafe extern "C" fn $invoke<$($var: FromWasmAbi,)* R: ReturnWasmAbi>( + a: usize, + b: usize, + $($var: <$var as FromWasmAbi>::Abi),* + ) -> <R as ReturnWasmAbi>::Abi { + if a == 0 { + throw_str("closure invoked recursively or destroyed already"); + } + // Scope all local variables before we call `return_abi` to + // ensure they're all destroyed as `return_abi` may throw + let ret = { + let f: &dyn Fn($($var),*) -> R = mem::transmute((a, b)); + $( + let $var = <$var as FromWasmAbi>::from_abi($var); + )* + f($($var),*) + }; + ret.return_abi() + } + + impl<'a, $($var,)* R> WasmDescribe for dyn Fn($($var),*) -> R + 'a + where $($var: FromWasmAbi,)* + R: ReturnWasmAbi + { + fn describe() { + inform(FUNCTION); + inform($invoke::<$($var,)* R> as u32); + inform($cnt); + $(<$var as WasmDescribe>::describe();)* + <R as WasmDescribe>::describe(); + <R as WasmDescribe>::describe(); + } + } + + impl<'a, 'b, $($var,)* R> IntoWasmAbi for &'a mut (dyn FnMut($($var),*) -> R + 'b) + where $($var: FromWasmAbi,)* + R: ReturnWasmAbi + { + type Abi = WasmSlice; + + fn into_abi(self) -> WasmSlice { + unsafe { + let (a, b): (usize, usize) = mem::transmute(self); + WasmSlice { ptr: a as u32, len: b as u32 } + } + } + } + + #[allow(non_snake_case)] + unsafe extern "C" fn $invoke_mut<$($var: FromWasmAbi,)* R: ReturnWasmAbi>( + a: usize, + b: usize, + $($var: <$var as FromWasmAbi>::Abi),* + ) -> <R as ReturnWasmAbi>::Abi { + if a == 0 { + throw_str("closure invoked recursively or destroyed already"); + } + // Scope all local variables before we call `return_abi` to + // ensure they're all destroyed as `return_abi` may throw + let ret = { + let f: &mut dyn FnMut($($var),*) -> R = mem::transmute((a, b)); + $( + let $var = <$var as FromWasmAbi>::from_abi($var); + )* + f($($var),*) + }; + ret.return_abi() + } + + impl<'a, $($var,)* R> WasmDescribe for dyn FnMut($($var),*) -> R + 'a + where $($var: FromWasmAbi,)* + R: ReturnWasmAbi + { + fn describe() { + inform(FUNCTION); + inform($invoke_mut::<$($var,)* R> as u32); + inform($cnt); + $(<$var as WasmDescribe>::describe();)* + <R as WasmDescribe>::describe(); + <R as WasmDescribe>::describe(); + } + } + )*) +} + +stack_closures! { + (0 invoke0 invoke0_mut) + (1 invoke1 invoke1_mut A) + (2 invoke2 invoke2_mut A B) + (3 invoke3 invoke3_mut A B C) + (4 invoke4 invoke4_mut A B C D) + (5 invoke5 invoke5_mut A B C D E) + (6 invoke6 invoke6_mut A B C D E F) + (7 invoke7 invoke7_mut A B C D E F G) + (8 invoke8 invoke8_mut A B C D E F G H) +} + +impl<'a, 'b, A, R> IntoWasmAbi for &'a (dyn Fn(&A) -> R + 'b) +where + A: RefFromWasmAbi, + R: ReturnWasmAbi, +{ + type Abi = WasmSlice; + + fn into_abi(self) -> WasmSlice { + unsafe { + let (a, b): (usize, usize) = mem::transmute(self); + WasmSlice { + ptr: a as u32, + len: b as u32, + } + } + } +} + +#[allow(non_snake_case)] +unsafe extern "C" fn invoke1_ref<A: RefFromWasmAbi, R: ReturnWasmAbi>( + a: usize, + b: usize, + arg: <A as RefFromWasmAbi>::Abi, +) -> <R as ReturnWasmAbi>::Abi { + if a == 0 { + throw_str("closure invoked recursively or destroyed already"); + } + // Scope all local variables before we call `return_abi` to + // ensure they're all destroyed as `return_abi` may throw + let ret = { + let f: &dyn Fn(&A) -> R = mem::transmute((a, b)); + let arg = <A as RefFromWasmAbi>::ref_from_abi(arg); + f(&*arg) + }; + ret.return_abi() +} + +impl<'a, A, R> WasmDescribe for dyn Fn(&A) -> R + 'a +where + A: RefFromWasmAbi, + R: ReturnWasmAbi, +{ + fn describe() { + inform(FUNCTION); + inform(invoke1_ref::<A, R> as u32); + inform(1); + <&A as WasmDescribe>::describe(); + <R as WasmDescribe>::describe(); + <R as WasmDescribe>::describe(); + } +} + +impl<'a, 'b, A, R> IntoWasmAbi for &'a mut (dyn FnMut(&A) -> R + 'b) +where + A: RefFromWasmAbi, + R: ReturnWasmAbi, +{ + type Abi = WasmSlice; + + fn into_abi(self) -> WasmSlice { + unsafe { + let (a, b): (usize, usize) = mem::transmute(self); + WasmSlice { + ptr: a as u32, + len: b as u32, + } + } + } +} + +#[allow(non_snake_case)] +unsafe extern "C" fn invoke1_mut_ref<A: RefFromWasmAbi, R: ReturnWasmAbi>( + a: usize, + b: usize, + arg: <A as RefFromWasmAbi>::Abi, +) -> <R as ReturnWasmAbi>::Abi { + if a == 0 { + throw_str("closure invoked recursively or destroyed already"); + } + // Scope all local variables before we call `return_abi` to + // ensure they're all destroyed as `return_abi` may throw + let ret = { + let f: &mut dyn FnMut(&A) -> R = mem::transmute((a, b)); + let arg = <A as RefFromWasmAbi>::ref_from_abi(arg); + f(&*arg) + }; + ret.return_abi() +} + +impl<'a, A, R> WasmDescribe for dyn FnMut(&A) -> R + 'a +where + A: RefFromWasmAbi, + R: ReturnWasmAbi, +{ + fn describe() { + inform(FUNCTION); + inform(invoke1_mut_ref::<A, R> as u32); + inform(1); + <&A as WasmDescribe>::describe(); + <R as WasmDescribe>::describe(); + <R as WasmDescribe>::describe(); + } +} diff --git a/vendor/wasm-bindgen/src/convert/impls.rs b/vendor/wasm-bindgen/src/convert/impls.rs new file mode 100644 index 000000000..79ccd67af --- /dev/null +++ b/vendor/wasm-bindgen/src/convert/impls.rs @@ -0,0 +1,378 @@ +use core::char; +use core::mem::{self, ManuallyDrop}; + +use crate::convert::traits::WasmAbi; +use crate::convert::{FromWasmAbi, IntoWasmAbi, RefFromWasmAbi}; +use crate::convert::{OptionFromWasmAbi, OptionIntoWasmAbi, ReturnWasmAbi}; +use crate::{Clamped, JsError, JsValue}; + +unsafe impl WasmAbi for () {} + +#[repr(C, u32)] +pub enum WasmOption<T: WasmAbi> { + None, + Some(T), +} + +unsafe impl<T: WasmAbi> WasmAbi for WasmOption<T> {} + +impl<Abi: WasmAbi> WasmOption<Abi> { + pub fn from_option<T: IntoWasmAbi<Abi = Abi>>(option: Option<T>) -> Self { + match option { + Some(v) => WasmOption::Some(v.into_abi()), + None => WasmOption::None, + } + } + + pub unsafe fn into_option<T: FromWasmAbi<Abi = Abi>>(v: Self) -> Option<T> { + match v { + WasmOption::Some(v) => Some(T::from_abi(v)), + WasmOption::None => None, + } + } +} + +macro_rules! type_wasm_native { + ($($t:tt as $c:tt)*) => ($( + impl IntoWasmAbi for $t { + type Abi = $c; + + #[inline] + fn into_abi(self) -> $c { self as $c } + } + + impl FromWasmAbi for $t { + type Abi = $c; + + #[inline] + unsafe fn from_abi(js: $c) -> Self { js as $t } + } + + impl IntoWasmAbi for Option<$t> { + type Abi = WasmOption<$c>; + + #[inline] + fn into_abi(self) -> Self::Abi { + WasmOption::from_option(self.map(|v| v as $c)) + } + } + + impl FromWasmAbi for Option<$t> { + type Abi = WasmOption<$c>; + + #[inline] + unsafe fn from_abi(js: Self::Abi) -> Self { + WasmOption::into_option(js).map(|v: $c| v as $t) + } + } + )*) +} + +type_wasm_native!( + i32 as i32 + isize as i32 + u32 as u32 + usize as u32 + i64 as i64 + u64 as u64 + f32 as f32 + f64 as f64 +); + +macro_rules! type_abi_as_u32 { + ($($t:tt)*) => ($( + impl IntoWasmAbi for $t { + type Abi = u32; + + #[inline] + fn into_abi(self) -> u32 { self as u32 } + } + + impl FromWasmAbi for $t { + type Abi = u32; + + #[inline] + unsafe fn from_abi(js: u32) -> Self { js as $t } + } + + impl OptionIntoWasmAbi for $t { + #[inline] + fn none() -> u32 { 0x00FF_FFFFu32 } + } + + impl OptionFromWasmAbi for $t { + #[inline] + fn is_none(js: &u32) -> bool { *js == 0x00FF_FFFFu32 } + } + )*) +} + +type_abi_as_u32!(i8 u8 i16 u16); + +impl IntoWasmAbi for bool { + type Abi = u32; + + #[inline] + fn into_abi(self) -> u32 { + self as u32 + } +} + +impl FromWasmAbi for bool { + type Abi = u32; + + #[inline] + unsafe fn from_abi(js: u32) -> bool { + js != 0 + } +} + +impl OptionIntoWasmAbi for bool { + #[inline] + fn none() -> u32 { + 0x00FF_FFFFu32 + } +} + +impl OptionFromWasmAbi for bool { + #[inline] + fn is_none(js: &u32) -> bool { + *js == 0x00FF_FFFFu32 + } +} + +impl IntoWasmAbi for char { + type Abi = u32; + + #[inline] + fn into_abi(self) -> u32 { + self as u32 + } +} + +impl FromWasmAbi for char { + type Abi = u32; + + #[inline] + unsafe fn from_abi(js: u32) -> char { + char::from_u32_unchecked(js) + } +} + +impl OptionIntoWasmAbi for char { + #[inline] + fn none() -> u32 { + 0x00FF_FFFFu32 + } +} + +impl OptionFromWasmAbi for char { + #[inline] + fn is_none(js: &u32) -> bool { + *js == 0x00FF_FFFFu32 + } +} + +impl<T> IntoWasmAbi for *const T { + type Abi = u32; + + #[inline] + fn into_abi(self) -> u32 { + self as u32 + } +} + +impl<T> FromWasmAbi for *const T { + type Abi = u32; + + #[inline] + unsafe fn from_abi(js: u32) -> *const T { + js as *const T + } +} + +impl<T> IntoWasmAbi for *mut T { + type Abi = u32; + + #[inline] + fn into_abi(self) -> u32 { + self as u32 + } +} + +impl<T> FromWasmAbi for *mut T { + type Abi = u32; + + #[inline] + unsafe fn from_abi(js: u32) -> *mut T { + js as *mut T + } +} + +impl IntoWasmAbi for JsValue { + type Abi = u32; + + #[inline] + fn into_abi(self) -> u32 { + let ret = self.idx; + mem::forget(self); + ret + } +} + +impl FromWasmAbi for JsValue { + type Abi = u32; + + #[inline] + unsafe fn from_abi(js: u32) -> JsValue { + JsValue::_new(js) + } +} + +impl<'a> IntoWasmAbi for &'a JsValue { + type Abi = u32; + + #[inline] + fn into_abi(self) -> u32 { + self.idx + } +} + +impl RefFromWasmAbi for JsValue { + type Abi = u32; + type Anchor = ManuallyDrop<JsValue>; + + #[inline] + unsafe fn ref_from_abi(js: u32) -> Self::Anchor { + ManuallyDrop::new(JsValue::_new(js)) + } +} + +impl<T: OptionIntoWasmAbi> IntoWasmAbi for Option<T> { + type Abi = T::Abi; + + #[inline] + fn into_abi(self) -> T::Abi { + match self { + None => T::none(), + Some(me) => me.into_abi(), + } + } +} + +impl<T: OptionFromWasmAbi> FromWasmAbi for Option<T> { + type Abi = T::Abi; + + #[inline] + unsafe fn from_abi(js: T::Abi) -> Self { + if T::is_none(&js) { + None + } else { + Some(T::from_abi(js)) + } + } +} + +impl<T: IntoWasmAbi> IntoWasmAbi for Clamped<T> { + type Abi = T::Abi; + + #[inline] + fn into_abi(self) -> Self::Abi { + self.0.into_abi() + } +} + +impl<T: FromWasmAbi> FromWasmAbi for Clamped<T> { + type Abi = T::Abi; + + #[inline] + unsafe fn from_abi(js: T::Abi) -> Self { + Clamped(T::from_abi(js)) + } +} + +impl IntoWasmAbi for () { + type Abi = (); + + #[inline] + fn into_abi(self) { + self + } +} + +/// This is an encoding of a Result. It can only store things that can be decoded by the JS +/// bindings. +/// +/// At the moment, we do not write the exact struct packing layout of everything into the +/// glue/descriptions of datatypes, so T cannot be arbitrary. The current requirements of the +/// struct unpacker (StructUnpacker), which apply to ResultAbi<T> as a whole, are as follows: +/// +/// - repr(C), of course +/// - u32/i32/f32/f64 fields at the "leaf fields" of the "field tree" +/// - layout equivalent to a completely flattened repr(C) struct, constructed by an in order +/// traversal of all the leaf fields in it. +/// +/// This means that you can't embed struct A(u32, f64) as struct B(u32, A); because the "completely +/// flattened" struct AB(u32, u32, f64) would miss the 4 byte padding that is actually present +/// within B and then as a consequence also miss the 4 byte padding within A that repr(C) inserts. +/// +/// The enemy is padding. Padding is only required when there is an `f64` field. So the enemy is +/// `f64` after anything else, particularly anything arbitrary. There is no smaller sized type, so +/// we don't need to worry about 1-byte integers, etc. It's best, therefore, to place your f64s +/// first in your structs, that's why we have `abi` first, although here it doesn't matter as the +/// other two fields total 8 bytes anyway. +/// +#[repr(C)] +pub struct ResultAbi<T> { + /// This field is the same size/align as `T`. + abi: ResultAbiUnion<T>, + /// Order of args here is such that we can pop() the possible error first, deal with it and + /// move on. Later fields are popped off the stack first. + err: u32, + is_err: u32, +} + +#[repr(C)] +pub union ResultAbiUnion<T> { + // ManuallyDrop is #[repr(transparent)] + ok: std::mem::ManuallyDrop<T>, + err: (), +} + +unsafe impl<T: WasmAbi> WasmAbi for ResultAbi<T> {} +unsafe impl<T: WasmAbi> WasmAbi for ResultAbiUnion<T> {} + +impl<T: IntoWasmAbi, E: Into<JsValue>> ReturnWasmAbi for Result<T, E> { + type Abi = ResultAbi<T::Abi>; + #[inline] + fn return_abi(self) -> Self::Abi { + match self { + Ok(v) => { + let abi = ResultAbiUnion { + ok: std::mem::ManuallyDrop::new(v.into_abi()), + }; + ResultAbi { + abi, + is_err: 0, + err: 0, + } + } + Err(e) => { + let jsval = e.into(); + ResultAbi { + abi: ResultAbiUnion { err: () }, + is_err: 1, + err: jsval.into_abi(), + } + } + } + } +} + +impl IntoWasmAbi for JsError { + type Abi = <JsValue as IntoWasmAbi>::Abi; + + fn into_abi(self) -> Self::Abi { + self.value.into_abi() + } +} diff --git a/vendor/wasm-bindgen/src/convert/mod.rs b/vendor/wasm-bindgen/src/convert/mod.rs new file mode 100644 index 000000000..ce2c0b2c8 --- /dev/null +++ b/vendor/wasm-bindgen/src/convert/mod.rs @@ -0,0 +1,11 @@ +//! This is mostly an internal module, no stability guarantees are provided. Use +//! at your own risk. + +mod closures; +mod impls; +mod slices; +mod traits; + +pub use self::impls::*; +pub use self::slices::WasmSlice; +pub use self::traits::*; diff --git a/vendor/wasm-bindgen/src/convert/slices.rs b/vendor/wasm-bindgen/src/convert/slices.rs new file mode 100644 index 000000000..9d0970f4e --- /dev/null +++ b/vendor/wasm-bindgen/src/convert/slices.rs @@ -0,0 +1,311 @@ +#[cfg(feature = "std")] +use std::prelude::v1::*; + +use core::slice; +use core::str; + +use crate::cast::JsObject; +use crate::convert::OptionIntoWasmAbi; +use crate::convert::{FromWasmAbi, IntoWasmAbi, RefFromWasmAbi, RefMutFromWasmAbi, WasmAbi}; +use cfg_if::cfg_if; + +if_std! { + use core::mem; + use crate::convert::OptionFromWasmAbi; +} + +#[repr(C)] +pub struct WasmSlice { + pub ptr: u32, + pub len: u32, +} + +unsafe impl WasmAbi for WasmSlice {} + +#[inline] +fn null_slice() -> WasmSlice { + WasmSlice { ptr: 0, len: 0 } +} + +macro_rules! vectors { + ($($t:ident)*) => ($( + if_std! { + impl IntoWasmAbi for Box<[$t]> { + type Abi = WasmSlice; + + #[inline] + fn into_abi(self) -> WasmSlice { + let ptr = self.as_ptr(); + let len = self.len(); + mem::forget(self); + WasmSlice { + ptr: ptr.into_abi(), + len: len as u32, + } + } + } + + impl OptionIntoWasmAbi for Box<[$t]> { + #[inline] + fn none() -> WasmSlice { null_slice() } + } + + impl FromWasmAbi for Box<[$t]> { + type Abi = WasmSlice; + + #[inline] + unsafe fn from_abi(js: WasmSlice) -> Self { + let ptr = <*mut $t>::from_abi(js.ptr); + let len = js.len as usize; + Vec::from_raw_parts(ptr, len, len).into_boxed_slice() + } + } + + impl OptionFromWasmAbi for Box<[$t]> { + #[inline] + fn is_none(slice: &WasmSlice) -> bool { slice.ptr == 0 } + } + } + + impl<'a> IntoWasmAbi for &'a [$t] { + type Abi = WasmSlice; + + #[inline] + fn into_abi(self) -> WasmSlice { + WasmSlice { + ptr: self.as_ptr().into_abi(), + len: self.len() as u32, + } + } + } + + impl<'a> OptionIntoWasmAbi for &'a [$t] { + #[inline] + fn none() -> WasmSlice { null_slice() } + } + + impl<'a> IntoWasmAbi for &'a mut [$t] { + type Abi = WasmSlice; + + #[inline] + fn into_abi(self) -> WasmSlice { + (&*self).into_abi() + } + } + + impl<'a> OptionIntoWasmAbi for &'a mut [$t] { + #[inline] + fn none() -> WasmSlice { null_slice() } + } + + impl RefFromWasmAbi for [$t] { + type Abi = WasmSlice; + type Anchor = Box<[$t]>; + + #[inline] + unsafe fn ref_from_abi(js: WasmSlice) -> Box<[$t]> { + <Box<[$t]>>::from_abi(js) + } + } + + impl RefMutFromWasmAbi for [$t] { + type Abi = WasmSlice; + type Anchor = &'static mut [$t]; + + #[inline] + unsafe fn ref_mut_from_abi(js: WasmSlice) + -> &'static mut [$t] + { + slice::from_raw_parts_mut( + <*mut $t>::from_abi(js.ptr), + js.len as usize, + ) + } + } + )*) +} + +vectors! { + u8 i8 u16 i16 u32 i32 u64 i64 usize isize f32 f64 +} + +cfg_if! { + if #[cfg(feature = "enable-interning")] { + #[inline] + fn unsafe_get_cached_str(x: &str) -> Option<WasmSlice> { + // This uses 0 for the ptr as an indication that it is a JsValue and not a str. + crate::cache::intern::unsafe_get_str(x).map(|x| WasmSlice { ptr: 0, len: x }) + } + + } else { + #[inline] + fn unsafe_get_cached_str(_x: &str) -> Option<WasmSlice> { + None + } + } +} + +if_std! { + impl<T> IntoWasmAbi for Vec<T> where Box<[T]>: IntoWasmAbi<Abi = WasmSlice> { + type Abi = <Box<[T]> as IntoWasmAbi>::Abi; + + #[inline] + fn into_abi(self) -> Self::Abi { + self.into_boxed_slice().into_abi() + } + } + + impl<T> OptionIntoWasmAbi for Vec<T> where Box<[T]>: IntoWasmAbi<Abi = WasmSlice> { + #[inline] + fn none() -> WasmSlice { null_slice() } + } + + impl<T> FromWasmAbi for Vec<T> where Box<[T]>: FromWasmAbi<Abi = WasmSlice> { + type Abi = <Box<[T]> as FromWasmAbi>::Abi; + + #[inline] + unsafe fn from_abi(js: Self::Abi) -> Self { + <Box<[T]>>::from_abi(js).into() + } + } + + impl<T> OptionFromWasmAbi for Vec<T> where Box<[T]>: FromWasmAbi<Abi = WasmSlice> { + #[inline] + fn is_none(abi: &WasmSlice) -> bool { abi.ptr == 0 } + } + + impl IntoWasmAbi for String { + type Abi = <Vec<u8> as IntoWasmAbi>::Abi; + + #[inline] + fn into_abi(self) -> Self::Abi { + // This is safe because the JsValue is immediately looked up in the heap and + // then returned, so use-after-free cannot occur. + unsafe_get_cached_str(&self).unwrap_or_else(|| self.into_bytes().into_abi()) + } + } + + impl OptionIntoWasmAbi for String { + #[inline] + fn none() -> Self::Abi { null_slice() } + } + + impl FromWasmAbi for String { + type Abi = <Vec<u8> as FromWasmAbi>::Abi; + + #[inline] + unsafe fn from_abi(js: Self::Abi) -> Self { + String::from_utf8_unchecked(<Vec<u8>>::from_abi(js)) + } + } + + impl OptionFromWasmAbi for String { + #[inline] + fn is_none(slice: &WasmSlice) -> bool { slice.ptr == 0 } + } +} + +impl<'a> IntoWasmAbi for &'a str { + type Abi = <&'a [u8] as IntoWasmAbi>::Abi; + + #[inline] + fn into_abi(self) -> Self::Abi { + // This is safe because the JsValue is immediately looked up in the heap and + // then returned, so use-after-free cannot occur. + unsafe_get_cached_str(self).unwrap_or_else(|| self.as_bytes().into_abi()) + } +} + +impl<'a> OptionIntoWasmAbi for &'a str { + #[inline] + fn none() -> Self::Abi { + null_slice() + } +} + +impl RefFromWasmAbi for str { + type Abi = <[u8] as RefFromWasmAbi>::Abi; + type Anchor = Box<str>; + + #[inline] + unsafe fn ref_from_abi(js: Self::Abi) -> Self::Anchor { + mem::transmute::<Box<[u8]>, Box<str>>(<Box<[u8]>>::from_abi(js)) + } +} + +if_std! { + use crate::JsValue; + + impl IntoWasmAbi for Box<[JsValue]> { + type Abi = WasmSlice; + + #[inline] + fn into_abi(self) -> WasmSlice { + let ptr = self.as_ptr(); + let len = self.len(); + mem::forget(self); + WasmSlice { + ptr: ptr.into_abi(), + len: len as u32, + } + } + } + + impl OptionIntoWasmAbi for Box<[JsValue]> { + #[inline] + fn none() -> WasmSlice { null_slice() } + } + + impl FromWasmAbi for Box<[JsValue]> { + type Abi = WasmSlice; + + #[inline] + unsafe fn from_abi(js: WasmSlice) -> Self { + let ptr = <*mut JsValue>::from_abi(js.ptr); + let len = js.len as usize; + Vec::from_raw_parts(ptr, len, len).into_boxed_slice() + } + } + + impl OptionFromWasmAbi for Box<[JsValue]> { + #[inline] + fn is_none(slice: &WasmSlice) -> bool { slice.ptr == 0 } + } + + impl<T> IntoWasmAbi for Box<[T]> where T: JsObject { + type Abi = WasmSlice; + + #[inline] + fn into_abi(self) -> WasmSlice { + let ptr = self.as_ptr(); + let len = self.len(); + mem::forget(self); + WasmSlice { + ptr: ptr.into_abi(), + len: len as u32, + } + } + } + + impl<T> OptionIntoWasmAbi for Box<[T]> where T: JsObject { + #[inline] + fn none() -> WasmSlice { null_slice() } + } + + impl<T> FromWasmAbi for Box<[T]> where T: JsObject { + type Abi = WasmSlice; + + #[inline] + unsafe fn from_abi(js: WasmSlice) -> Self { + let ptr = <*mut JsValue>::from_abi(js.ptr); + let len = js.len as usize; + let vec: Vec<T> = Vec::from_raw_parts(ptr, len, len).drain(..).map(|js_value| T::unchecked_from_js(js_value)).collect(); + return vec.into_boxed_slice(); + } + } + + impl<T> OptionFromWasmAbi for Box<[T]> where T: JsObject { + #[inline] + fn is_none(slice: &WasmSlice) -> bool { slice.ptr == 0 } + } +} diff --git a/vendor/wasm-bindgen/src/convert/traits.rs b/vendor/wasm-bindgen/src/convert/traits.rs new file mode 100644 index 000000000..b9d12b4c8 --- /dev/null +++ b/vendor/wasm-bindgen/src/convert/traits.rs @@ -0,0 +1,131 @@ +use core::ops::{Deref, DerefMut}; + +use crate::describe::*; + +/// A trait for anything that can be converted into a type that can cross the +/// wasm ABI directly, eg `u32` or `f64`. +/// +/// This is the opposite operation as `FromWasmAbi` and `Ref[Mut]FromWasmAbi`. +pub trait IntoWasmAbi: WasmDescribe { + /// The wasm ABI type that this converts into when crossing the ABI + /// boundary. + type Abi: WasmAbi; + + /// Convert `self` into `Self::Abi` so that it can be sent across the wasm + /// ABI boundary. + fn into_abi(self) -> Self::Abi; +} + +/// A trait for anything that can be recovered by-value from the wasm ABI +/// boundary, eg a Rust `u8` can be recovered from the wasm ABI `u32` type. +/// +/// This is the by-value variant of the opposite operation as `IntoWasmAbi`. +pub trait FromWasmAbi: WasmDescribe { + /// The wasm ABI type that this converts from when coming back out from the + /// ABI boundary. + type Abi: WasmAbi; + + /// Recover a `Self` from `Self::Abi`. + /// + /// # Safety + /// + /// This is only safe to call when -- and implementations may assume that -- + /// the supplied `Self::Abi` was previously generated by a call to `<Self as + /// IntoWasmAbi>::into_abi()` or the moral equivalent in JS. + unsafe fn from_abi(js: Self::Abi) -> Self; +} + +/// A trait for anything that can be recovered as some sort of shared reference +/// from the wasm ABI boundary. +/// +/// This is the shared reference variant of the opposite operation as +/// `IntoWasmAbi`. +pub trait RefFromWasmAbi: WasmDescribe { + /// The wasm ABI type references to `Self` are recovered from. + type Abi: WasmAbi; + + /// The type that holds the reference to `Self` for the duration of the + /// invocation of the function that has an `&Self` parameter. This is + /// required to ensure that the lifetimes don't persist beyond one function + /// call, and so that they remain anonymous. + type Anchor: Deref<Target = Self>; + + /// Recover a `Self::Anchor` from `Self::Abi`. + /// + /// # Safety + /// + /// Same as `FromWasmAbi::from_abi`. + unsafe fn ref_from_abi(js: Self::Abi) -> Self::Anchor; +} + +/// Dual of the `RefFromWasmAbi` trait, except for mutable references. +pub trait RefMutFromWasmAbi: WasmDescribe { + /// Same as `RefFromWasmAbi::Abi` + type Abi: WasmAbi; + /// Same as `RefFromWasmAbi::Anchor` + type Anchor: DerefMut<Target = Self>; + /// Same as `RefFromWasmAbi::ref_from_abi` + unsafe fn ref_mut_from_abi(js: Self::Abi) -> Self::Anchor; +} + +/// Indicates that this type can be passed to JS as `Option<Self>`. +/// +/// This trait is used when implementing `IntoWasmAbi for Option<T>`. +pub trait OptionIntoWasmAbi: IntoWasmAbi { + /// Returns an ABI instance indicating "none", which JS will interpret as + /// the `None` branch of this option. + /// + /// It should be guaranteed that the `IntoWasmAbi` can never produce the ABI + /// value returned here. + fn none() -> Self::Abi; +} + +/// Indicates that this type can be received from JS as `Option<Self>`. +/// +/// This trait is used when implementing `FromWasmAbi for Option<T>`. +pub trait OptionFromWasmAbi: FromWasmAbi { + /// Tests whether the argument is a "none" instance. If so it will be + /// deserialized as `None`, and otherwise it will be passed to + /// `FromWasmAbi`. + fn is_none(abi: &Self::Abi) -> bool; +} + +/// An unsafe trait which represents types that are ABI-safe to pass via wasm +/// arguments. +/// +/// This is an unsafe trait to implement as there's no guarantee the type is +/// actually safe to transfer across the was boundary, it's up to you to +/// guarantee this so codegen works correctly. +pub unsafe trait WasmAbi {} + +unsafe impl WasmAbi for u32 {} +unsafe impl WasmAbi for i32 {} +unsafe impl WasmAbi for u64 {} +unsafe impl WasmAbi for i64 {} +unsafe impl WasmAbi for f32 {} +unsafe impl WasmAbi for f64 {} + +/// A trait representing how to interepret the return value of a function for +/// the wasm ABI. +/// +/// This is very similar to the `IntoWasmAbi` trait and in fact has a blanket +/// implementation for all implementors of the `IntoWasmAbi`. The primary use +/// case of this trait is to enable functions to return `Result`, interpreting +/// an error as "rethrow this to JS" +pub trait ReturnWasmAbi: WasmDescribe { + /// Same as `IntoWasmAbi::Abi` + type Abi: WasmAbi; + + /// Same as `IntoWasmAbi::into_abi`, except that it may throw and never + /// return in the case of `Err`. + fn return_abi(self) -> Self::Abi; +} + +impl<T: IntoWasmAbi> ReturnWasmAbi for T { + type Abi = T::Abi; + + #[inline] + fn return_abi(self) -> Self::Abi { + self.into_abi() + } +} |