mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-06-16 14:31:22 +00:00
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
This commit is contained in:
@ -53,6 +53,8 @@ pub struct SubContext<'a, 'b: 'a> {
|
||||
pub cx: &'a mut Context<'b>,
|
||||
}
|
||||
|
||||
const INITIAL_SLAB_VALUES: &[&str] = &["undefined", "null", "true", "false"];
|
||||
|
||||
impl<'a> Context<'a> {
|
||||
fn export(&mut self, name: &str, contents: &str, comments: Option<String>) {
|
||||
let contents = contents.trim();
|
||||
@ -183,28 +185,6 @@ impl<'a> Context<'a> {
|
||||
))
|
||||
})?;
|
||||
|
||||
self.bind("__wbindgen_undefined_new", &|me| {
|
||||
me.expose_add_heap_object();
|
||||
Ok(String::from(
|
||||
"
|
||||
function() {
|
||||
return addHeapObject(undefined);
|
||||
}
|
||||
",
|
||||
))
|
||||
})?;
|
||||
|
||||
self.bind("__wbindgen_null_new", &|me| {
|
||||
me.expose_add_heap_object();
|
||||
Ok(String::from(
|
||||
"
|
||||
function() {
|
||||
return addHeapObject(null);
|
||||
}
|
||||
",
|
||||
))
|
||||
})?;
|
||||
|
||||
self.bind("__wbindgen_is_null", &|me| {
|
||||
me.expose_get_object();
|
||||
Ok(String::from(
|
||||
@ -227,17 +207,6 @@ impl<'a> Context<'a> {
|
||||
))
|
||||
})?;
|
||||
|
||||
self.bind("__wbindgen_boolean_new", &|me| {
|
||||
me.expose_add_heap_object();
|
||||
Ok(String::from(
|
||||
"
|
||||
function(v) {
|
||||
return addHeapObject(v === 1);
|
||||
}
|
||||
",
|
||||
))
|
||||
})?;
|
||||
|
||||
self.bind("__wbindgen_boolean_get", &|me| {
|
||||
me.expose_get_object();
|
||||
Ok(String::from(
|
||||
@ -782,14 +751,16 @@ impl<'a> Context<'a> {
|
||||
"
|
||||
function dropRef(idx) {{
|
||||
{}
|
||||
let obj = slab[idx >> 1];
|
||||
idx = idx >> 1;
|
||||
if (idx < {}) return;
|
||||
let obj = slab[idx];
|
||||
{}
|
||||
// If we hit 0 then free up our space in the slab
|
||||
slab[idx >> 1] = slab_next;
|
||||
slab_next = idx >> 1;
|
||||
slab[idx] = slab_next;
|
||||
slab_next = idx;
|
||||
}}
|
||||
",
|
||||
validate_owned, dec_ref
|
||||
validate_owned, INITIAL_SLAB_VALUES.len(), dec_ref
|
||||
));
|
||||
}
|
||||
|
||||
@ -820,12 +791,9 @@ impl<'a> Context<'a> {
|
||||
if !self.exposed_globals.insert("slab") {
|
||||
return;
|
||||
}
|
||||
let initial_values = [
|
||||
"{ obj: null }",
|
||||
"{ obj: undefined }",
|
||||
"{ obj: true }",
|
||||
"{ obj: false }",
|
||||
];
|
||||
let initial_values = INITIAL_SLAB_VALUES.iter()
|
||||
.map(|s| format!("{{ obj: {} }}", s))
|
||||
.collect::<Vec<_>>();
|
||||
self.global(&format!("const slab = [{}];", initial_values.join(", ")));
|
||||
if self.config.debug {
|
||||
self.export(
|
||||
@ -1575,6 +1543,17 @@ impl<'a> Context<'a> {
|
||||
name
|
||||
}
|
||||
|
||||
fn expose_is_like_none(&mut self) {
|
||||
if !self.exposed_globals.insert("is_like_none") {
|
||||
return
|
||||
}
|
||||
self.global("
|
||||
function isLikeNone(x) {
|
||||
return x === undefined || x === null;
|
||||
}
|
||||
");
|
||||
}
|
||||
|
||||
fn gc(&mut self) -> Result<(), Error> {
|
||||
let module = mem::replace(self.module, Module::default());
|
||||
let wasm_bytes = parity_wasm::serialize(module)?;
|
||||
|
Reference in New Issue
Block a user