Files
wasm-bindgen/src/convert/impls.rs

205 lines
4.1 KiB
Rust
Raw Normal View History

Add support for optional slice types (#507) * Shard the `convert.rs` module into sub-modules Hopefully this'll make the organization a little nicer over time! * Start adding support for optional types This commit starts adding support for optional types to wasm-bindgen as arguments/return values to functions. The strategy here is to add two new traits, `OptionIntoWasmAbi` and `OptionFromWasmAbi`. These two traits are used as a blanket impl to implement `IntoWasmAbi` and `FromWasmAbi` for `Option<T>`. Some consequences of this design: * It should be possible to ensure `Option<SomeForeignType>` implements to/from wasm traits. This is because the option-based traits can be implemented for foreign types. * A specialized implementation is possible for all types, so there's no need for `Option<T>` to introduce unnecessary overhead. * Two new traits is a bit unforutnate but I can't currently think of an alternative design that works for the above two constraints, although it doesn't mean one doesn't exist! * The error messages for "can't use this type here" is actually halfway decent because it says these new traits need to be implemented, which provides a good place to document and talk about what's going on here! * Nested references like `Option<&T>` can't implement `FromWasmAbi`. This means that you can't define a function in Rust which takes `Option<&str>`. It may be possible to do this one day but it'll likely require more trait trickery than I'm capable of right now. * Add support for optional slices This commit adds support for optional slice types, things like strings and arrays. The null representation of these has a pointer value of 0, which should never happen in normal Rust. Otherwise the various plumbing is done throughout the tooling to enable these types in all locations. * Fix `takeObject` on global sentinels These don't have a reference count as they're always expected to work, so avoid actually dropping a reference on them. * Remove some no longer needed bindings * Add support for optional anyref types This commit adds support for optional imported class types. Each type imported with `#[wasm_bindgen]` automatically implements the relevant traits and now supports `Option<Foo>` in various argument/return positions. * Fix building without the `std` feature * Actually fix the build... * Add support for optional types to WebIDL Closes #502
2018-07-19 14:44:23 -05:00
use core::char;
use core::mem::{self, ManuallyDrop};
use convert::slices::WasmSlice;
use convert::{Stack, FromWasmAbi, IntoWasmAbi, RefFromWasmAbi};
use convert::{OptionIntoWasmAbi, OptionFromWasmAbi};
use JsValue;
macro_rules! simple {
($($t:tt)*) => ($(
impl IntoWasmAbi for $t {
type Abi = $t;
#[inline]
fn into_abi(self, _extra: &mut Stack) -> $t { self }
}
impl FromWasmAbi for $t {
type Abi = $t;
#[inline]
unsafe fn from_abi(js: $t, _extra: &mut Stack) -> $t { js }
}
)*)
}
simple!(u32 i32 f32 f64);
macro_rules! sixtyfour {
($($t:tt)*) => ($(
impl IntoWasmAbi for $t {
type Abi = WasmSlice;
#[inline]
fn into_abi(self, _extra: &mut Stack) -> WasmSlice {
WasmSlice {
ptr: self as u32,
len: (self >> 32) as u32,
}
}
}
impl FromWasmAbi for $t {
type Abi = WasmSlice;
#[inline]
unsafe fn from_abi(js: WasmSlice, _extra: &mut Stack) -> $t {
(js.ptr as $t) | ((js.len as $t) << 32)
}
}
)*)
}
sixtyfour!(i64 u64);
macro_rules! as_u32 {
($($t:tt)*) => ($(
impl IntoWasmAbi for $t {
type Abi = u32;
#[inline]
fn into_abi(self, _extra: &mut Stack) -> u32 { self as u32 }
}
impl FromWasmAbi for $t {
type Abi = u32;
#[inline]
unsafe fn from_abi(js: u32, _extra: &mut Stack) -> $t { js as $t }
}
)*)
}
as_u32!(i8 u8 i16 u16 isize usize);
impl IntoWasmAbi for bool {
type Abi = u32;
#[inline]
fn into_abi(self, _extra: &mut Stack) -> u32 {
self as u32
}
}
impl FromWasmAbi for bool {
type Abi = u32;
#[inline]
unsafe fn from_abi(js: u32, _extra: &mut Stack) -> bool {
js != 0
}
}
impl IntoWasmAbi for char {
type Abi = u32;
#[inline]
fn into_abi(self, _extra: &mut Stack) -> u32 {
self as u32
}
}
impl FromWasmAbi for char {
type Abi = u32;
#[inline]
unsafe fn from_abi(js: u32, _extra: &mut Stack) -> char {
char::from_u32_unchecked(js)
}
}
impl<T> IntoWasmAbi for *const T {
type Abi = u32;
fn into_abi(self, _extra: &mut Stack) -> u32 {
self as u32
}
}
impl<T> FromWasmAbi for *const T {
type Abi = u32;
unsafe fn from_abi(js: u32, _extra: &mut Stack) -> *const T {
js as *const T
}
}
impl<T> IntoWasmAbi for *mut T {
type Abi = u32;
fn into_abi(self, _extra: &mut Stack) -> u32 {
self as u32
}
}
impl<T> FromWasmAbi for *mut T {
type Abi = u32;
unsafe fn from_abi(js: u32, _extra: &mut Stack) -> *mut T {
js as *mut T
}
}
impl IntoWasmAbi for JsValue {
type Abi = u32;
#[inline]
fn into_abi(self, _extra: &mut Stack) -> u32 {
let ret = self.idx;
mem::forget(self);
return ret;
}
}
impl FromWasmAbi for JsValue {
type Abi = u32;
#[inline]
unsafe fn from_abi(js: u32, _extra: &mut Stack) -> JsValue {
JsValue { idx: js }
}
}
impl<'a> IntoWasmAbi for &'a JsValue {
type Abi = u32;
#[inline]
fn into_abi(self, _extra: &mut Stack) -> u32 {
self.idx
}
}
impl RefFromWasmAbi for JsValue {
type Abi = u32;
type Anchor = ManuallyDrop<JsValue>;
#[inline]
unsafe fn ref_from_abi(js: u32, _extra: &mut Stack) -> Self::Anchor {
ManuallyDrop::new(JsValue { idx: js })
}
}
impl<T: OptionIntoWasmAbi> IntoWasmAbi for Option<T> {
type Abi = T::Abi;
fn into_abi(self, extra: &mut Stack) -> T::Abi {
match self {
Some(me) => me.into_abi(extra),
None => T::none(),
}
}
}
impl<T: OptionFromWasmAbi> FromWasmAbi for Option<T> {
type Abi = T::Abi;
unsafe fn from_abi(js: T::Abi, extra: &mut Stack) -> Self {
if T::is_none(&js) {
None
} else {
Some(T::from_abi(js, extra))
}
}
}