diff options
Diffstat (limited to 'vendor/wasm-bindgen/src/convert/slices.rs')
-rw-r--r-- | vendor/wasm-bindgen/src/convert/slices.rs | 311 |
1 files changed, 311 insertions, 0 deletions
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 } + } +} |