diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:41:35 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:41:35 +0000 |
commit | 7e5d7eea9c580ef4b41a765bde624af431942b96 (patch) | |
tree | 2c0d9ca12878fc4525650aa4e54d77a81a07cc09 /vendor/wasm-bindgen/src | |
parent | Adding debian version 1.70.0+dfsg1-9. (diff) | |
download | rustc-7e5d7eea9c580ef4b41a765bde624af431942b96.tar.xz rustc-7e5d7eea9c580ef4b41a765bde624af431942b96.zip |
Merging upstream version 1.70.0+dfsg2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/wasm-bindgen/src')
-rw-r--r-- | vendor/wasm-bindgen/src/cache/intern.rs | 103 | ||||
-rw-r--r-- | vendor/wasm-bindgen/src/cache/mod.rs | 1 | ||||
-rw-r--r-- | vendor/wasm-bindgen/src/cast.rs | 160 | ||||
-rw-r--r-- | vendor/wasm-bindgen/src/closure.rs | 885 | ||||
-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 | ||||
-rw-r--r-- | vendor/wasm-bindgen/src/describe.rs | 192 | ||||
-rw-r--r-- | vendor/wasm-bindgen/src/externref.rs | 184 | ||||
-rw-r--r-- | vendor/wasm-bindgen/src/lib.rs | 1800 |
12 files changed, 4381 insertions, 0 deletions
diff --git a/vendor/wasm-bindgen/src/cache/intern.rs b/vendor/wasm-bindgen/src/cache/intern.rs new file mode 100644 index 000000000..c8aa51b2c --- /dev/null +++ b/vendor/wasm-bindgen/src/cache/intern.rs @@ -0,0 +1,103 @@ +use cfg_if::cfg_if; + + +cfg_if! { + if #[cfg(feature = "enable-interning")] { + use std::thread_local; + use std::string::String; + use std::borrow::ToOwned; + use std::cell::RefCell; + use std::collections::HashMap; + use crate::JsValue; + + struct Cache { + entries: RefCell<HashMap<String, JsValue>>, + } + + thread_local! { + static CACHE: Cache = Cache { + entries: RefCell::new(HashMap::new()), + }; + } + + /// This returns the raw index of the cached JsValue, so you must take care + /// so that you don't use it after it is freed. + pub(crate) fn unsafe_get_str(s: &str) -> Option<u32> { + CACHE.with(|cache| { + let cache = cache.entries.borrow(); + + cache.get(s).map(|x| x.idx) + }) + } + + fn intern_str(key: &str) { + CACHE.with(|cache| { + let mut cache = cache.entries.borrow_mut(); + + // Can't use `entry` because `entry` requires a `String` + if !cache.contains_key(key) { + cache.insert(key.to_owned(), JsValue::from(key)); + } + }) + } + + fn unintern_str(key: &str) { + CACHE.with(|cache| { + let mut cache = cache.entries.borrow_mut(); + + cache.remove(key); + }) + } + } +} + + +/// Interns Rust strings so that it's much faster to send them to JS. +/// +/// Sending strings from Rust to JS is slow, because it has to do a full `O(n)` +/// copy and *also* encode from UTF-8 to UTF-16. This must be done every single +/// time a string is sent to JS. +/// +/// If you are sending the same string multiple times, you can call this `intern` +/// function, which simply returns its argument unchanged: +/// +/// ```rust +/// # use wasm_bindgen::intern; +/// intern("foo") // returns "foo" +/// # ; +/// ``` +/// +/// However, if you enable the `"enable-interning"` feature for wasm-bindgen, +/// then it will add the string into an internal cache. +/// +/// When you send that cached string to JS, it will look it up in the cache, +/// which completely avoids the `O(n)` copy and encoding. This has a significant +/// speed boost (as high as 783%)! +/// +/// However, there is a small cost to this caching, so you shouldn't cache every +/// string. Only cache strings which have a high likelihood of being sent +/// to JS multiple times. +/// +/// Also, keep in mind that this function is a *performance hint*: it's not +/// *guaranteed* that the string will be cached, and the caching strategy +/// might change at any time, so don't rely upon it. +#[inline] +pub fn intern(s: &str) -> &str { + #[cfg(feature = "enable-interning")] + intern_str(s); + + s +} + + +/// Removes a Rust string from the intern cache. +/// +/// This does the opposite of the [`intern`](fn.intern.html) function. +/// +/// If the [`intern`](fn.intern.html) function is called again then it will re-intern the string. +#[allow(unused_variables)] +#[inline] +pub fn unintern(s: &str) { + #[cfg(feature = "enable-interning")] + unintern_str(s); +} diff --git a/vendor/wasm-bindgen/src/cache/mod.rs b/vendor/wasm-bindgen/src/cache/mod.rs new file mode 100644 index 000000000..96d1a4920 --- /dev/null +++ b/vendor/wasm-bindgen/src/cache/mod.rs @@ -0,0 +1 @@ +pub mod intern; diff --git a/vendor/wasm-bindgen/src/cast.rs b/vendor/wasm-bindgen/src/cast.rs new file mode 100644 index 000000000..6be56a2d7 --- /dev/null +++ b/vendor/wasm-bindgen/src/cast.rs @@ -0,0 +1,160 @@ +use crate::{describe::WasmDescribe, JsValue}; + +/// A trait for checked and unchecked casting between JS types. +/// +/// Specified [in an RFC][rfc] this trait is intended to provide support for +/// casting JS values between differnet types of one another. In JS there aren't +/// many static types but we've ascribed JS values with static types in Rust, +/// yet they often need to be switched to other types temporarily! This trait +/// provides both checked and unchecked casting into various kinds of values. +/// +/// This trait is automatically implemented for any type imported in a +/// `#[wasm_bindgen]` `extern` block. +/// +/// [rfc]: https://github.com/rustwasm/rfcs/blob/master/text/002-wasm-bindgen-inheritance-casting.md +pub trait JsCast +where + Self: AsRef<JsValue> + Into<JsValue>, +{ + /// Test whether this JS value has a type `T`. + /// + /// This method will dynamically check to see if this JS object can be + /// casted to the JS object of type `T`. Usually this uses the `instanceof` + /// operator. This also works with primitive types like + /// booleans/strings/numbers as well as cross-realm object like `Array` + /// which can originate from other iframes. + /// + /// In general this is intended to be a more robust version of + /// `is_instance_of`, but if you want strictly the `instanceof` operator + /// it's recommended to use that instead. + fn has_type<T>(&self) -> bool + where + T: JsCast, + { + T::is_type_of(self.as_ref()) + } + + /// Performs a dynamic cast (checked at runtime) of this value into the + /// target type `T`. + /// + /// This method will return `Err(self)` if `self.has_type::<T>()` + /// returns `false`, and otherwise it will return `Ok(T)` manufactured with + /// an unchecked cast (verified correct via the `has_type` operation). + fn dyn_into<T>(self) -> Result<T, Self> + where + T: JsCast, + { + if self.has_type::<T>() { + Ok(self.unchecked_into()) + } else { + Err(self) + } + } + + /// Performs a dynamic cast (checked at runtime) of this value into the + /// target type `T`. + /// + /// This method will return `None` if `self.has_type::<T>()` + /// returns `false`, and otherwise it will return `Some(&T)` manufactured + /// with an unchecked cast (verified correct via the `has_type` operation). + fn dyn_ref<T>(&self) -> Option<&T> + where + T: JsCast, + { + if self.has_type::<T>() { + Some(self.unchecked_ref()) + } else { + None + } + } + + /// Performs a zero-cost unchecked cast into the specified type. + /// + /// This method will convert the `self` value to the type `T`, where both + /// `self` and `T` are simple wrappers around `JsValue`. This method **does + /// not check whether `self` is an instance of `T`**. If used incorrectly + /// then this method may cause runtime exceptions in both Rust and JS, this + /// should be used with caution. + fn unchecked_into<T>(self) -> T + where + T: JsCast, + { + T::unchecked_from_js(self.into()) + } + + /// Performs a zero-cost unchecked cast into a reference to the specified + /// type. + /// + /// This method will convert the `self` value to the type `T`, where both + /// `self` and `T` are simple wrappers around `JsValue`. This method **does + /// not check whether `self` is an instance of `T`**. If used incorrectly + /// then this method may cause runtime exceptions in both Rust and JS, this + /// should be used with caution. + /// + /// This method, unlike `unchecked_into`, does not consume ownership of + /// `self` and instead works over a shared reference. + fn unchecked_ref<T>(&self) -> &T + where + T: JsCast, + { + T::unchecked_from_js_ref(self.as_ref()) + } + + /// Test whether this JS value is an instance of the type `T`. + /// + /// This method performs a dynamic check (at runtime) using the JS + /// `instanceof` operator. This method returns `self instanceof T`. + /// + /// Note that `instanceof` does not always work with primitive values or + /// across different realms (e.g. iframes). If you're not sure whether you + /// specifically need only `instanceof` it's recommended to use `has_type` + /// instead. + fn is_instance_of<T>(&self) -> bool + where + T: JsCast, + { + T::instanceof(self.as_ref()) + } + + /// Performs a dynamic `instanceof` check to see whether the `JsValue` + /// provided is an instance of this type. + /// + /// This is intended to be an internal implementation detail, you likely + /// won't need to call this. It's generally called through the + /// `is_instance_of` method instead. + fn instanceof(val: &JsValue) -> bool; + + /// Performs a dynamic check to see whether the `JsValue` provided + /// is a value of this type. + /// + /// Unlike `instanceof`, this can be specialised to use a custom check by + /// adding a `#[wasm_bindgen(is_type_of = callback)]` attribute to the + /// type import declaration. + /// + /// Other than that, this is intended to be an internal implementation + /// detail of `has_type` and you likely won't need to call this. + fn is_type_of(val: &JsValue) -> bool { + Self::instanceof(val) + } + + /// Performs a zero-cost unchecked conversion from a `JsValue` into an + /// instance of `Self` + /// + /// This is intended to be an internal implementation detail, you likely + /// won't need to call this. + fn unchecked_from_js(val: JsValue) -> Self; + + /// Performs a zero-cost unchecked conversion from a `&JsValue` into an + /// instance of `&Self`. + /// + /// Note the safety of this method, which basically means that `Self` must + /// be a newtype wrapper around `JsValue`. + /// + /// This is intended to be an internal implementation detail, you likely + /// won't need to call this. + fn unchecked_from_js_ref(val: &JsValue) -> &Self; +} + +/// Trait implemented for wrappers around `JsValue`s generated by `#[wasm_bindgen]`. +#[doc(hidden)] +pub trait JsObject: JsCast + WasmDescribe {} diff --git a/vendor/wasm-bindgen/src/closure.rs b/vendor/wasm-bindgen/src/closure.rs new file mode 100644 index 000000000..37cef06dc --- /dev/null +++ b/vendor/wasm-bindgen/src/closure.rs @@ -0,0 +1,885 @@ +//! Support for long-lived closures in `wasm-bindgen` +//! +//! This module defines the `Closure` type which is used to pass "owned +//! closures" from Rust to JS. Some more details can be found on the `Closure` +//! type itself. + +use std::fmt; +use std::mem::{self, ManuallyDrop}; +use std::prelude::v1::*; + +use crate::convert::*; +use crate::describe::*; +use crate::throw_str; +use crate::JsValue; +use crate::UnwrapThrowExt; + +/// A handle to both a closure in Rust as well as JS closure which will invoke +/// the Rust closure. +/// +/// A `Closure` is the primary way that a `'static` lifetime closure is +/// transferred from Rust to JS. `Closure` currently requires that the closures +/// it's created with have the `'static` lifetime in Rust for soundness reasons. +/// +/// This type is a "handle" in the sense that whenever it is dropped it will +/// invalidate the JS closure that it refers to. Any usage of the closure in JS +/// after the `Closure` has been dropped will raise an exception. It's then up +/// to you to arrange for `Closure` to be properly deallocate at an appropriate +/// location in your program. +/// +/// The type parameter on `Closure` is the type of closure that this represents. +/// Currently this can only be the `Fn` and `FnMut` traits with up to 7 +/// arguments (and an optional return value). +/// +/// # Examples +/// +/// Here are a number of examples of using `Closure`. +/// +/// ## Using the `setInterval` API +/// +/// Sample usage of `Closure` to invoke the `setInterval` API. +/// +/// ```rust,no_run +/// use wasm_bindgen::prelude::*; +/// +/// #[wasm_bindgen] +/// extern "C" { +/// fn setInterval(closure: &Closure<dyn FnMut()>, time: u32) -> i32; +/// fn clearInterval(id: i32); +/// +/// #[wasm_bindgen(js_namespace = console)] +/// fn log(s: &str); +/// } +/// +/// #[wasm_bindgen] +/// pub struct IntervalHandle { +/// interval_id: i32, +/// _closure: Closure<dyn FnMut()>, +/// } +/// +/// impl Drop for IntervalHandle { +/// fn drop(&mut self) { +/// clearInterval(self.interval_id); +/// } +/// } +/// +/// #[wasm_bindgen] +/// pub fn run() -> IntervalHandle { +/// // First up we use `Closure::new` to wrap up a Rust closure and create +/// // a JS closure. +/// let cb = Closure::new(|| { +/// log("interval elapsed!"); +/// }); +/// +/// // Next we pass this via reference to the `setInterval` function, and +/// // `setInterval` gets a handle to the corresponding JS closure. +/// let interval_id = setInterval(&cb, 1_000); +/// +/// // If we were to drop `cb` here it would cause an exception to be raised +/// // whenever the interval elapses. Instead we *return* our handle back to JS +/// // so JS can decide when to cancel the interval and deallocate the closure. +/// IntervalHandle { +/// interval_id, +/// _closure: cb, +/// } +/// } +/// ``` +/// +/// ## Casting a `Closure` to a `js_sys::Function` +/// +/// This is the same `setInterval` example as above, except it is using +/// `web_sys` (which uses `js_sys::Function` for callbacks) instead of manually +/// writing bindings to `setInterval` and other Web APIs. +/// +/// ```rust,ignore +/// use wasm_bindgen::JsCast; +/// +/// #[wasm_bindgen] +/// pub struct IntervalHandle { +/// interval_id: i32, +/// _closure: Closure<dyn FnMut()>, +/// } +/// +/// impl Drop for IntervalHandle { +/// fn drop(&mut self) { +/// let window = web_sys::window().unwrap(); +/// window.clear_interval_with_handle(self.interval_id); +/// } +/// } +/// +/// #[wasm_bindgen] +/// pub fn run() -> Result<IntervalHandle, JsValue> { +/// let cb = Closure::new(|| { +/// web_sys::console::log_1(&"interval elapsed!".into()); +/// }); +/// +/// let window = web_sys::window().unwrap(); +/// let interval_id = window.set_interval_with_callback_and_timeout_and_arguments_0( +/// // Note this method call, which uses `as_ref()` to get a `JsValue` +/// // from our `Closure` which is then converted to a `&Function` +/// // using the `JsCast::unchecked_ref` function. +/// cb.as_ref().unchecked_ref(), +/// 1_000, +/// )?; +/// +/// // Same as above. +/// Ok(IntervalHandle { +/// interval_id, +/// _closure: cb, +/// }) +/// } +/// ``` +/// +/// ## Using `FnOnce` and `Closure::once` with `requestAnimationFrame` +/// +/// Because `requestAnimationFrame` only calls its callback once, we can use +/// `FnOnce` and `Closure::once` with it. +/// +/// ```rust,no_run +/// use wasm_bindgen::prelude::*; +/// +/// #[wasm_bindgen] +/// extern "C" { +/// fn requestAnimationFrame(closure: &Closure<dyn FnMut()>) -> u32; +/// fn cancelAnimationFrame(id: u32); +/// +/// #[wasm_bindgen(js_namespace = console)] +/// fn log(s: &str); +/// } +/// +/// #[wasm_bindgen] +/// pub struct AnimationFrameHandle { +/// animation_id: u32, +/// _closure: Closure<dyn FnMut()>, +/// } +/// +/// impl Drop for AnimationFrameHandle { +/// fn drop(&mut self) { +/// cancelAnimationFrame(self.animation_id); +/// } +/// } +/// +/// // A type that will log a message when it is dropped. +/// struct LogOnDrop(&'static str); +/// impl Drop for LogOnDrop { +/// fn drop(&mut self) { +/// log(self.0); +/// } +/// } +/// +/// #[wasm_bindgen] +/// pub fn run() -> AnimationFrameHandle { +/// // We are using `Closure::once` which takes a `FnOnce`, so the function +/// // can drop and/or move things that it closes over. +/// let fired = LogOnDrop("animation frame fired or canceled"); +/// let cb = Closure::once(move || drop(fired)); +/// +/// // Schedule the animation frame! +/// let animation_id = requestAnimationFrame(&cb); +/// +/// // Again, return a handle to JS, so that the closure is not dropped +/// // immediately and JS can decide whether to cancel the animation frame. +/// AnimationFrameHandle { +/// animation_id, +/// _closure: cb, +/// } +/// } +/// ``` +/// +/// ## Converting `FnOnce`s directly into JavaScript Functions with `Closure::once_into_js` +/// +/// If we don't want to allow a `FnOnce` to be eagerly dropped (maybe because we +/// just want it to drop after it is called and don't care about cancellation) +/// then we can use the `Closure::once_into_js` function. +/// +/// This is the same `requestAnimationFrame` example as above, but without +/// supporting early cancellation. +/// +/// ``` +/// use wasm_bindgen::prelude::*; +/// +/// #[wasm_bindgen] +/// extern "C" { +/// // We modify the binding to take an untyped `JsValue` since that is what +/// // is returned by `Closure::once_into_js`. +/// // +/// // If we were using the `web_sys` binding for `requestAnimationFrame`, +/// // then the call sites would cast the `JsValue` into a `&js_sys::Function` +/// // using `f.unchecked_ref::<js_sys::Function>()`. See the `web_sys` +/// // example above for details. +/// fn requestAnimationFrame(callback: JsValue); +/// +/// #[wasm_bindgen(js_namespace = console)] +/// fn log(s: &str); +/// } +/// +/// // A type that will log a message when it is dropped. +/// struct LogOnDrop(&'static str); +/// impl Drop for LogOnDrop { +/// fn drop(&mut self) { +/// log(self.0); +/// } +/// } +/// +/// #[wasm_bindgen] +/// pub fn run() { +/// // We are using `Closure::once_into_js` which takes a `FnOnce` and +/// // converts it into a JavaScript function, which is returned as a +/// // `JsValue`. +/// let fired = LogOnDrop("animation frame fired"); +/// let cb = Closure::once_into_js(move || drop(fired)); +/// +/// // Schedule the animation frame! +/// requestAnimationFrame(cb); +/// +/// // No need to worry about whether or not we drop a `Closure` +/// // here or return some sort of handle to JS! +/// } +/// ``` +pub struct Closure<T: ?Sized> { + js: ManuallyDrop<JsValue>, + data: ManuallyDrop<Box<T>>, +} + +union FatPtr<T: ?Sized> { + ptr: *mut T, + fields: (usize, usize), +} + +impl<T> Closure<T> +where + T: ?Sized + WasmClosure, +{ + /// Creates a new instance of `Closure` from the provided Rust function. + /// + /// Note that the closure provided here, `F`, has a few requirements + /// associated with it: + /// + /// * It must implement `Fn` or `FnMut` (for `FnOnce` functions see + /// `Closure::once` and `Closure::once_into_js`). + /// + /// * It must be `'static`, aka no stack references (use the `move` + /// keyword). + /// + /// * It can have at most 7 arguments. + /// + /// * Its arguments and return values are all types that can be shared with + /// JS (i.e. have `#[wasm_bindgen]` annotations or are simple numbers, + /// etc.) + pub fn new<F>(t: F) -> Closure<T> + where + F: IntoWasmClosure<T> + 'static, + { + Closure::wrap(Box::new(t).unsize()) + } + + /// A more direct version of `Closure::new` which creates a `Closure` from + /// a `Box<dyn Fn>`/`Box<dyn FnMut>`, which is how it's kept internally. + pub fn wrap(mut data: Box<T>) -> Closure<T> { + assert_eq!(mem::size_of::<*const T>(), mem::size_of::<FatPtr<T>>()); + let (a, b) = unsafe { + FatPtr { + ptr: &mut *data as *mut T, + } + .fields + }; + + // Here we need to create a `JsValue` with the data and `T::invoke()` + // function pointer. To do that we... take a few unconventional turns. + // In essence what happens here is this: + // + // 1. First up, below we call a function, `breaks_if_inlined`. This + // function, as the name implies, does not work if it's inlined. + // More on that in a moment. + // 2. This function internally calls a special import recognized by the + // `wasm-bindgen` CLI tool, `__wbindgen_describe_closure`. This + // imported symbol is similar to `__wbindgen_describe` in that it's + // not intended to show up in the final binary but it's an + // intermediate state for a `wasm-bindgen` binary. + // 3. The `__wbindgen_describe_closure` import is namely passed a + // descriptor function, monomorphized for each invocation. + // + // Most of this doesn't actually make sense to happen at runtime! The + // real magic happens when `wasm-bindgen` comes along and updates our + // generated code. When `wasm-bindgen` runs it performs a few tasks: + // + // * First, it finds all functions that call + // `__wbindgen_describe_closure`. These are all `breaks_if_inlined` + // defined below as the symbol isn't called anywhere else. + // * Next, `wasm-bindgen` executes the `breaks_if_inlined` + // monomorphized functions, passing it dummy arguments. This will + // execute the function just enough to invoke the special import, + // namely telling us about the function pointer that is the describe + // shim. + // * This knowledge is then used to actually find the descriptor in the + // function table which is then executed to figure out the signature + // of the closure. + // * Finally, and probably most heinously, the call to + // `breaks_if_inlined` is rewritten to call an otherwise globally + // imported function. This globally imported function will generate + // the `JsValue` for this closure specialized for the signature in + // question. + // + // Later on `wasm-gc` will clean up all the dead code and ensure that + // we don't actually call `__wbindgen_describe_closure` at runtime. This + // means we will end up not actually calling `breaks_if_inlined` in the + // final binary, all calls to that function should be pruned. + // + // See crates/cli-support/src/js/closures.rs for a more information + // about what's going on here. + + extern "C" fn describe<T: WasmClosure + ?Sized>() { + inform(CLOSURE); + T::describe() + } + + #[inline(never)] + unsafe fn breaks_if_inlined<T: WasmClosure + ?Sized>(a: usize, b: usize) -> u32 { + super::__wbindgen_describe_closure(a as u32, b as u32, describe::<T> as u32) + } + + let idx = unsafe { breaks_if_inlined::<T>(a, b) }; + + Closure { + js: ManuallyDrop::new(JsValue::_new(idx)), + data: ManuallyDrop::new(data), + } + } + + /// Release memory management of this closure from Rust to the JS GC. + /// + /// When a `Closure` is dropped it will release the Rust memory and + /// invalidate the associated JS closure, but this isn't always desired. + /// Some callbacks are alive for the entire duration of the program or for a + /// lifetime dynamically managed by the JS GC. This function can be used + /// to drop this `Closure` while keeping the associated JS function still + /// valid. + /// + /// By default this function will leak memory. This can be dangerous if this + /// function is called many times in an application because the memory leak + /// will overwhelm the page quickly and crash the wasm. + /// + /// If the browser, however, supports weak references, then this function + /// will not leak memory. Instead the Rust memory will be reclaimed when the + /// JS closure is GC'd. Weak references are not enabled by default since + /// they're still a proposal for the JS standard. They can be enabled with + /// `WASM_BINDGEN_WEAKREF=1` when running `wasm-bindgen`, however. + pub fn into_js_value(self) -> JsValue { + let idx = self.js.idx; + mem::forget(self); + JsValue::_new(idx) + } + + /// Same as `into_js_value`, but doesn't return a value. + pub fn forget(self) { + drop(self.into_js_value()); + } +} + +// NB: we use a specific `T` for this `Closure<T>` impl block to avoid every +// call site having to provide an explicit, turbo-fished type like +// `Closure::<dyn FnOnce()>::once(...)`. +impl Closure<dyn FnOnce()> { + /// Create a `Closure` from a function that can only be called once. + /// + /// Since we have no way of enforcing that JS cannot attempt to call this + /// `FnOne(A...) -> R` more than once, this produces a `Closure<dyn FnMut(A...) + /// -> R>` that will dynamically throw a JavaScript error if called more + /// than once. + /// + /// # Example + /// + /// ```rust,no_run + /// use wasm_bindgen::prelude::*; + /// + /// // Create an non-`Copy`, owned `String`. + /// let mut s = String::from("Hello"); + /// + /// // Close over `s`. Since `f` returns `s`, it is `FnOnce` and can only be + /// // called once. If it was called a second time, it wouldn't have any `s` + /// // to work with anymore! + /// let f = move || { + /// s += ", World!"; + /// s + /// }; + /// + /// // Create a `Closure` from `f`. Note that the `Closure`'s type parameter + /// // is `FnMut`, even though `f` is `FnOnce`. + /// let closure: Closure<dyn FnMut() -> String> = Closure::once(f); + /// ``` + pub fn once<F, A, R>(fn_once: F) -> Closure<F::FnMut> + where + F: 'static + WasmClosureFnOnce<A, R>, + { + Closure::wrap(fn_once.into_fn_mut()) + } + + /// Convert a `FnOnce(A...) -> R` into a JavaScript `Function` object. + /// + /// If the JavaScript function is invoked more than once, it will throw an + /// exception. + /// + /// Unlike `Closure::once`, this does *not* return a `Closure` that can be + /// dropped before the function is invoked to deallocate the closure. The + /// only way the `FnOnce` is deallocated is by calling the JavaScript + /// function. If the JavaScript function is never called then the `FnOnce` + /// and everything it closes over will leak. + /// + /// ```rust,ignore + /// use wasm_bindgen::{prelude::*, JsCast}; + /// + /// let f = Closure::once_into_js(move || { + /// // ... + /// }); + /// + /// assert!(f.is_instance_of::<js_sys::Function>()); + /// ``` + pub fn once_into_js<F, A, R>(fn_once: F) -> JsValue + where + F: 'static + WasmClosureFnOnce<A, R>, + { + fn_once.into_js_function() + } +} + +/// A trait for converting an `FnOnce(A...) -> R` into a `FnMut(A...) -> R` that +/// will throw if ever called more than once. +#[doc(hidden)] +pub trait WasmClosureFnOnce<A, R>: 'static { + type FnMut: ?Sized + 'static + WasmClosure; + + fn into_fn_mut(self) -> Box<Self::FnMut>; + + fn into_js_function(self) -> JsValue; +} + +impl<T: ?Sized> AsRef<JsValue> for Closure<T> { + fn as_ref(&self) -> &JsValue { + &self.js + } +} + +impl<T> WasmDescribe for Closure<T> +where + T: WasmClosure + ?Sized, +{ + fn describe() { + inform(EXTERNREF); + } +} + +// `Closure` can only be passed by reference to imports. +impl<'a, T> IntoWasmAbi for &'a Closure<T> +where + T: WasmClosure + ?Sized, +{ + type Abi = u32; + + fn into_abi(self) -> u32 { + (&*self.js).into_abi() + } +} + +impl<'a, T> OptionIntoWasmAbi for &'a Closure<T> +where + T: WasmClosure + ?Sized, +{ + fn none() -> Self::Abi { + 0 + } +} + +fn _check() { + fn _assert<T: IntoWasmAbi>() {} + _assert::<&Closure<dyn Fn()>>(); + _assert::<&Closure<dyn Fn(String)>>(); + _assert::<&Closure<dyn Fn() -> String>>(); + _assert::<&Closure<dyn FnMut()>>(); + _assert::<&Closure<dyn FnMut(String)>>(); + _assert::<&Closure<dyn FnMut() -> String>>(); +} + +impl<T> fmt::Debug for Closure<T> +where + T: ?Sized, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Closure {{ ... }}") + } +} + +impl<T> Drop for Closure<T> +where + T: ?Sized, +{ + fn drop(&mut self) { + unsafe { + // this will implicitly drop our strong reference in addition to + // invalidating all future invocations of the closure + if super::__wbindgen_cb_drop(self.js.idx) != 0 { + ManuallyDrop::drop(&mut self.data); + } + } + } +} + +/// An internal trait for the `Closure` type. +/// +/// This trait is not stable and it's not recommended to use this in bounds or +/// implement yourself. +#[doc(hidden)] +pub unsafe trait WasmClosure { + fn describe(); +} + +/// An internal trait for the `Closure` type. +/// +/// This trait is not stable and it's not recommended to use this in bounds or +/// implement yourself. +#[doc(hidden)] +pub trait IntoWasmClosure<T: ?Sized> { + fn unsize(self: Box<Self>) -> Box<T>; +} + +// The memory safety here in these implementations below is a bit tricky. We +// want to be able to drop the `Closure` object from within the invocation of a +// `Closure` for cases like promises. That means that while it's running we +// might drop the `Closure`, but that shouldn't invalidate the environment yet. +// +// Instead what we do is to wrap closures in `Rc` variables. The main `Closure` +// has a strong reference count which keeps the trait object alive. Each +// invocation of a closure then *also* clones this and gets a new reference +// count. When the closure returns it will release the reference count. +// +// This means that if the main `Closure` is dropped while it's being invoked +// then destruction is deferred until execution returns. Otherwise it'll +// deallocate data immediately. + +macro_rules! doit { + ($( + ($($var:ident)*) + )*) => ($( + unsafe impl<$($var,)* R> WasmClosure for dyn Fn($($var),*) -> R + 'static + where $($var: FromWasmAbi + 'static,)* + R: ReturnWasmAbi + 'static, + { + fn describe() { + #[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"); + } + // Make sure all stack variables are converted before we + // convert `ret` as it may throw (for `Result`, for + // example) + let ret = { + let f: *const dyn Fn($($var),*) -> R = + FatPtr { fields: (a, b) }.ptr; + $( + let $var = <$var as FromWasmAbi>::from_abi($var); + )* + (*f)($($var),*) + }; + ret.return_abi() + } + + inform(invoke::<$($var,)* R> as u32); + + unsafe extern fn destroy<$($var: FromWasmAbi,)* R: ReturnWasmAbi>( + a: usize, + b: usize, + ) { + // This can be called by the JS glue in erroneous situations + // such as when the closure has already been destroyed. If + // that's the case let's not make things worse by + // segfaulting and/or asserting, so just ignore null + // pointers. + if a == 0 { + return; + } + drop(Box::from_raw(FatPtr::<dyn Fn($($var,)*) -> R> { + fields: (a, b) + }.ptr)); + } + inform(destroy::<$($var,)* R> as u32); + + <&Self>::describe(); + } + } + + unsafe impl<$($var,)* R> WasmClosure for dyn FnMut($($var),*) -> R + 'static + where $($var: FromWasmAbi + 'static,)* + R: ReturnWasmAbi + 'static, + { + fn describe() { + #[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"); + } + // Make sure all stack variables are converted before we + // convert `ret` as it may throw (for `Result`, for + // example) + let ret = { + let f: *const dyn FnMut($($var),*) -> R = + FatPtr { fields: (a, b) }.ptr; + let f = f as *mut dyn FnMut($($var),*) -> R; + $( + let $var = <$var as FromWasmAbi>::from_abi($var); + )* + (*f)($($var),*) + }; + ret.return_abi() + } + + inform(invoke::<$($var,)* R> as u32); + + unsafe extern fn destroy<$($var: FromWasmAbi,)* R: ReturnWasmAbi>( + a: usize, + b: usize, + ) { + // See `Fn()` above for why we simply return + if a == 0 { + return; + } + drop(Box::from_raw(FatPtr::<dyn FnMut($($var,)*) -> R> { + fields: (a, b) + }.ptr)); + } + inform(destroy::<$($var,)* R> as u32); + + <&mut Self>::describe(); + } + } + + #[allow(non_snake_case, unused_parens)] + impl<T, $($var,)* R> WasmClosureFnOnce<($($var),*), R> for T + where T: 'static + FnOnce($($var),*) -> R, + $($var: FromWasmAbi + 'static,)* + R: ReturnWasmAbi + 'static + { + type FnMut = dyn FnMut($($var),*) -> R; + + fn into_fn_mut(self) -> Box<Self::FnMut> { + let mut me = Some(self); + Box::new(move |$($var),*| { + let me = me.take().expect_throw("FnOnce called more than once"); + me($($var),*) + }) + } + + fn into_js_function(self) -> JsValue { + use std::rc::Rc; + use crate::__rt::WasmRefCell; + + let mut me = Some(self); + + let rc1 = Rc::new(WasmRefCell::new(None)); + let rc2 = rc1.clone(); + + let closure = Closure::wrap(Box::new(move |$($var),*| { + // Invoke ourself and get the result. + let me = me.take().expect_throw("FnOnce called more than once"); + let result = me($($var),*); + + // And then drop the `Rc` holding this function's `Closure` + // alive. + debug_assert_eq!(Rc::strong_count(&rc2), 1); + let option_closure = rc2.borrow_mut().take(); + debug_assert!(option_closure.is_some()); + drop(option_closure); + + result + }) as Box<dyn FnMut($($var),*) -> R>); + + let js_val = closure.as_ref().clone(); + + *rc1.borrow_mut() = Some(closure); + debug_assert_eq!(Rc::strong_count(&rc1), 2); + drop(rc1); + + js_val + } + } + + impl<T, $($var,)* R> IntoWasmClosure<dyn FnMut($($var),*) -> R> for T + where T: 'static + FnMut($($var),*) -> R, + $($var: FromWasmAbi + 'static,)* + R: ReturnWasmAbi + 'static, + { + fn unsize(self: Box<Self>) -> Box<dyn FnMut($($var),*) -> R> { self } + } + + impl<T, $($var,)* R> IntoWasmClosure<dyn Fn($($var),*) -> R> for T + where T: 'static + Fn($($var),*) -> R, + $($var: FromWasmAbi + 'static,)* + R: ReturnWasmAbi + 'static, + { + fn unsize(self: Box<Self>) -> Box<dyn Fn($($var),*) -> R> { self } + } + )*) +} + +doit! { + () + (A) + (A B) + (A B C) + (A B C D) + (A B C D E) + (A B C D E F) + (A B C D E F G) + (A B C D E F G H) +} + +// Copy the above impls down here for where there's only one argument and it's a +// reference. We could add more impls for more kinds of references, but it +// becomes a combinatorial explosion quickly. Let's see how far we can get with +// just this one! Maybe someone else can figure out voodoo so we don't have to +// duplicate. + +unsafe impl<A, R> WasmClosure for dyn Fn(&A) -> R +where + A: RefFromWasmAbi, + R: ReturnWasmAbi + 'static, +{ + fn describe() { + #[allow(non_snake_case)] + unsafe extern "C" fn invoke<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"); + } + // Make sure all stack variables are converted before we + // convert `ret` as it may throw (for `Result`, for + // example) + let ret = { + let f: *const dyn Fn(&A) -> R = FatPtr { fields: (a, b) }.ptr; + let arg = <A as RefFromWasmAbi>::ref_from_abi(arg); + (*f)(&*arg) + }; + ret.return_abi() + } + + inform(invoke::<A, R> as u32); + + unsafe extern "C" fn destroy<A: RefFromWasmAbi, R: ReturnWasmAbi>(a: usize, b: usize) { + // See `Fn()` above for why we simply return + if a == 0 { + return; + } + drop(Box::from_raw( + FatPtr::<dyn Fn(&A) -> R> { fields: (a, b) }.ptr, + )); + } + inform(destroy::<A, R> as u32); + + <&Self>::describe(); + } +} + +unsafe impl<A, R> WasmClosure for dyn FnMut(&A) -> R +where + A: RefFromWasmAbi, + R: ReturnWasmAbi + 'static, +{ + fn describe() { + #[allow(non_snake_case)] + unsafe extern "C" fn invoke<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"); + } + // Make sure all stack variables are converted before we + // convert `ret` as it may throw (for `Result`, for + // example) + let ret = { + let f: *const dyn FnMut(&A) -> R = FatPtr { fields: (a, b) }.ptr; + let f = f as *mut dyn FnMut(&A) -> R; + let arg = <A as RefFromWasmAbi>::ref_from_abi(arg); + (*f)(&*arg) + }; + ret.return_abi() + } + + inform(invoke::<A, R> as u32); + + unsafe extern "C" fn destroy<A: RefFromWasmAbi, R: ReturnWasmAbi>(a: usize, b: usize) { + // See `Fn()` above for why we simply return + if a == 0 { + return; + } + drop(Box::from_raw( + FatPtr::<dyn FnMut(&A) -> R> { fields: (a, b) }.ptr, + )); + } + inform(destroy::<A, R> as u32); + + <&mut Self>::describe(); + } +} + +#[allow(non_snake_case)] +impl<T, A, R> WasmClosureFnOnce<(&A,), R> for T +where + T: 'static + FnOnce(&A) -> R, + A: RefFromWasmAbi + 'static, + R: ReturnWasmAbi + 'static, +{ + type FnMut = dyn FnMut(&A) -> R; + + fn into_fn_mut(self) -> Box<Self::FnMut> { + let mut me = Some(self); + Box::new(move |arg| { + let me = me.take().expect_throw("FnOnce called more than once"); + me(arg) + }) + } + + fn into_js_function(self) -> JsValue { + use crate::__rt::WasmRefCell; + use std::rc::Rc; + + let mut me = Some(self); + + let rc1 = Rc::new(WasmRefCell::new(None)); + let rc2 = rc1.clone(); + + let closure = Closure::wrap(Box::new(move |arg: &A| { + // Invoke ourself and get the result. + let me = me.take().expect_throw("FnOnce called more than once"); + let result = me(arg); + + // And then drop the `Rc` holding this function's `Closure` + // alive. + debug_assert_eq!(Rc::strong_count(&rc2), 1); + let option_closure = rc2.borrow_mut().take(); + debug_assert!(option_closure.is_some()); + drop(option_closure); + + result + }) as Box<dyn FnMut(&A) -> R>); + + let js_val = closure.as_ref().clone(); + + *rc1.borrow_mut() = Some(closure); + debug_assert_eq!(Rc::strong_count(&rc1), 2); + drop(rc1); + + js_val + } +} 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() + } +} diff --git a/vendor/wasm-bindgen/src/describe.rs b/vendor/wasm-bindgen/src/describe.rs new file mode 100644 index 000000000..2b7c4b628 --- /dev/null +++ b/vendor/wasm-bindgen/src/describe.rs @@ -0,0 +1,192 @@ +//! This is an internal module, no stability guarantees are provided. Use at +//! your own risk. + +#![doc(hidden)] + +use crate::{Clamped, JsError, JsValue}; +use cfg_if::cfg_if; + +macro_rules! tys { + ($($a:ident)*) => (tys! { @ ($($a)*) 0 }); + (@ () $v:expr) => {}; + (@ ($a:ident $($b:ident)*) $v:expr) => { + pub const $a: u32 = $v; + tys!(@ ($($b)*) $v+1); + } +} + +// NB: this list must be kept in sync with `crates/cli-support/src/descriptor.rs` +tys! { + I8 + U8 + I16 + U16 + I32 + U32 + I64 + U64 + F32 + F64 + BOOLEAN + FUNCTION + CLOSURE + CACHED_STRING + STRING + REF + REFMUT + SLICE + VECTOR + EXTERNREF + NAMED_EXTERNREF + ENUM + RUST_STRUCT + CHAR + OPTIONAL + RESULT + UNIT + CLAMPED +} + +#[inline(always)] // see the wasm-interpreter crate +pub fn inform(a: u32) { + unsafe { super::__wbindgen_describe(a) } +} + +pub trait WasmDescribe { + fn describe(); +} + +macro_rules! simple { + ($($t:ident => $d:ident)*) => ($( + impl WasmDescribe for $t { + fn describe() { inform($d) } + } + )*) +} + +simple! { + i8 => I8 + u8 => U8 + i16 => I16 + u16 => U16 + i32 => I32 + u32 => U32 + i64 => I64 + u64 => U64 + isize => I32 + usize => U32 + f32 => F32 + f64 => F64 + bool => BOOLEAN + char => CHAR + JsValue => EXTERNREF +} + +cfg_if! { + if #[cfg(feature = "enable-interning")] { + simple! { + str => CACHED_STRING + } + + } else { + simple! { + str => STRING + } + } +} + +impl<T> WasmDescribe for *const T { + fn describe() { + inform(I32) + } +} + +impl<T> WasmDescribe for *mut T { + fn describe() { + inform(I32) + } +} + +impl<T: WasmDescribe> WasmDescribe for [T] { + fn describe() { + inform(SLICE); + T::describe(); + } +} + +impl<'a, T: WasmDescribe + ?Sized> WasmDescribe for &'a T { + fn describe() { + inform(REF); + T::describe(); + } +} + +impl<'a, T: WasmDescribe + ?Sized> WasmDescribe for &'a mut T { + fn describe() { + inform(REFMUT); + T::describe(); + } +} + +if_std! { + use std::prelude::v1::*; + + cfg_if! { + if #[cfg(feature = "enable-interning")] { + simple! { + String => CACHED_STRING + } + + } else { + simple! { + String => STRING + } + } + } + + impl<T: WasmDescribe> WasmDescribe for Box<[T]> { + fn describe() { + inform(VECTOR); + T::describe(); + } + } + + impl<T> WasmDescribe for Vec<T> where Box<[T]>: WasmDescribe { + fn describe() { + <Box<[T]>>::describe(); + } + } +} + +impl<T: WasmDescribe> WasmDescribe for Option<T> { + fn describe() { + inform(OPTIONAL); + T::describe(); + } +} + +impl WasmDescribe for () { + fn describe() { + inform(UNIT) + } +} + +impl<T: WasmDescribe, E: Into<JsValue>> WasmDescribe for Result<T, E> { + fn describe() { + inform(RESULT); + T::describe(); + } +} + +impl<T: WasmDescribe> WasmDescribe for Clamped<T> { + fn describe() { + inform(CLAMPED); + T::describe(); + } +} + +impl WasmDescribe for JsError { + fn describe() { + JsValue::describe(); + } +} diff --git a/vendor/wasm-bindgen/src/externref.rs b/vendor/wasm-bindgen/src/externref.rs new file mode 100644 index 000000000..a7e5f3ebc --- /dev/null +++ b/vendor/wasm-bindgen/src/externref.rs @@ -0,0 +1,184 @@ +use crate::JsValue; +use std::alloc::{self, Layout}; +use std::cell::Cell; +use std::mem; +use std::ptr; +use std::slice; +use std::vec::Vec; +use std::cmp::max; + +externs! { + #[link(wasm_import_module = "__wbindgen_externref_xform__")] + extern "C" { + fn __wbindgen_externref_table_grow(delta: usize) -> i32; + fn __wbindgen_externref_table_set_null(idx: usize) -> (); + } +} + +pub struct Slab { + data: Vec<usize>, + head: usize, + base: usize, +} + +impl Slab { + fn new() -> Slab { + Slab { + data: Vec::new(), + head: 0, + base: 0, + } + } + + fn alloc(&mut self) -> usize { + let ret = self.head; + if ret == self.data.len() { + let curr_len = self.data.len(); + if curr_len == self.data.capacity() { + let extra = max(128, curr_len); + let r = unsafe { __wbindgen_externref_table_grow(extra) }; + if r == -1 { + internal_error("table grow failure") + } + if self.base == 0 { + self.base = r as usize; + } else if self.base + self.data.len() != r as usize { + internal_error("someone else allocated table entires?") + } + + // poor man's `try_reserve_exact` until that's stable + unsafe { + let new_cap = self.data.capacity() + extra; + let size = mem::size_of::<usize>() * new_cap; + let align = mem::align_of::<usize>(); + let layout = match Layout::from_size_align(size, align) { + Ok(l) => l, + Err(_) => internal_error("size/align layout failure"), + }; + let ptr = alloc::alloc(layout) as *mut usize; + if ptr.is_null() { + internal_error("allocation failure"); + } + ptr::copy_nonoverlapping(self.data.as_ptr(), ptr, self.data.len()); + let new_vec = Vec::from_raw_parts(ptr, self.data.len(), new_cap); + let mut old = mem::replace(&mut self.data, new_vec); + old.set_len(0); + } + } + + // custom condition to ensure `push` below doesn't call `reserve` in + // optimized builds which pulls in lots of panic infrastructure + if self.data.len() >= self.data.capacity() { + internal_error("push should be infallible now") + } + self.data.push(ret + 1); + } + + // usage of `get_mut` thwarts panicking infrastructure in optimized + // builds + match self.data.get_mut(ret) { + Some(slot) => self.head = *slot, + None => internal_error("ret out of bounds"), + } + ret + self.base + } + + fn dealloc(&mut self, slot: usize) { + if slot < self.base { + internal_error("free reserved slot"); + } + let slot = slot - self.base; + + // usage of `get_mut` thwarts panicking infrastructure in optimized + // builds + match self.data.get_mut(slot) { + Some(ptr) => { + *ptr = self.head; + self.head = slot; + } + None => internal_error("slot out of bounds"), + } + } + + fn live_count(&self) -> u32 { + let mut free_count = 0; + let mut next = self.head; + while next < self.data.len() { + debug_assert!((free_count as usize) < self.data.len()); + free_count += 1; + match self.data.get(next) { + Some(n) => next = *n, + None => internal_error("slot out of bounds"), + }; + } + self.data.len() as u32 - free_count + } +} + +fn internal_error(msg: &str) -> ! { + if cfg!(debug_assertions) { + super::throw_str(msg) + } else { + std::process::abort() + } +} + +// Management of `externref` is always thread local since an `externref` value +// can't cross threads in wasm. Indices as a result are always thread-local. +std::thread_local!(pub static HEAP_SLAB: Cell<Slab> = Cell::new(Slab::new())); + +#[no_mangle] +pub extern "C" fn __externref_table_alloc() -> usize { + HEAP_SLAB + .try_with(|slot| { + let mut slab = slot.replace(Slab::new()); + let ret = slab.alloc(); + slot.replace(slab); + ret + }) + .unwrap_or_else(|_| internal_error("tls access failure")) +} + +#[no_mangle] +pub extern "C" fn __externref_table_dealloc(idx: usize) { + if idx < super::JSIDX_RESERVED as usize { + return; + } + // clear this value from the table so while the table slot is un-allocated + // we don't keep around a strong reference to a potentially large object + unsafe { + __wbindgen_externref_table_set_null(idx); + } + HEAP_SLAB + .try_with(|slot| { + let mut slab = slot.replace(Slab::new()); + slab.dealloc(idx); + slot.replace(slab); + }) + .unwrap_or_else(|_| internal_error("tls access failure")) +} + +#[no_mangle] +pub unsafe extern "C" fn __externref_drop_slice(ptr: *mut JsValue, len: usize) { + for slot in slice::from_raw_parts_mut(ptr, len) { + __externref_table_dealloc(slot.idx as usize); + } +} + +// Implementation of `__wbindgen_externref_heap_live_count` for when we are using +// `externref` instead of the JS `heap`. +#[no_mangle] +pub unsafe extern "C" fn __externref_heap_live_count() -> u32 { + HEAP_SLAB + .try_with(|slot| { + let slab = slot.replace(Slab::new()); + let count = slab.live_count(); + slot.replace(slab); + count + }) + .unwrap_or_else(|_| internal_error("tls access failure")) +} + +// see comment in module above this in `link_mem_intrinsics` +#[inline(never)] +pub fn link_intrinsics() {} diff --git a/vendor/wasm-bindgen/src/lib.rs b/vendor/wasm-bindgen/src/lib.rs new file mode 100644 index 000000000..2ccb284b9 --- /dev/null +++ b/vendor/wasm-bindgen/src/lib.rs @@ -0,0 +1,1800 @@ +//! Runtime support for the `wasm-bindgen` tool +//! +//! This crate contains the runtime support necessary for `wasm-bindgen` the +//! attribute and tool. Crates pull in the `#[wasm_bindgen]` attribute through +//! this crate and this crate also provides JS bindings through the `JsValue` +//! interface. + +#![no_std] +#![allow(coherence_leak_check)] +#![doc(html_root_url = "https://docs.rs/wasm-bindgen/0.2")] + +use core::convert::TryFrom; +use core::fmt; +use core::marker; +use core::mem; +use core::ops::{ + Add, BitAnd, BitOr, BitXor, Deref, DerefMut, Div, Mul, Neg, Not, Rem, Shl, Shr, Sub, +}; +use core::u32; + +use crate::convert::{FromWasmAbi, WasmSlice}; + +macro_rules! if_std { + ($($i:item)*) => ($( + #[cfg(feature = "std")] $i + )*) +} + +macro_rules! externs { + ($(#[$attr:meta])* extern "C" { $(fn $name:ident($($args:tt)*) -> $ret:ty;)* }) => ( + #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] + $(#[$attr])* + extern "C" { + $(fn $name($($args)*) -> $ret;)* + } + + $( + #[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))] + #[allow(unused_variables)] + unsafe extern fn $name($($args)*) -> $ret { + panic!("function not implemented on non-wasm32 targets") + } + )* + ) +} + +/// A module which is typically glob imported from: +/// +/// ``` +/// use wasm_bindgen::prelude::*; +/// ``` +pub mod prelude { + pub use crate::JsValue; + pub use crate::UnwrapThrowExt; + #[doc(hidden)] + pub use wasm_bindgen_macro::__wasm_bindgen_class_marker; + pub use wasm_bindgen_macro::wasm_bindgen; + + if_std! { + pub use crate::closure::Closure; + } + + pub use crate::JsError; +} + +pub mod convert; +pub mod describe; + +mod cast; +pub use crate::cast::{JsCast, JsObject}; +use convert::WasmOption; + +if_std! { + extern crate std; + use std::prelude::v1::*; + pub mod closure; + mod externref; + + mod cache; + pub use cache::intern::{intern, unintern}; +} + +/// Representation of an object owned by JS. +/// +/// A `JsValue` doesn't actually live in Rust right now but actually in a table +/// owned by the `wasm-bindgen` generated JS glue code. Eventually the ownership +/// will transfer into wasm directly and this will likely become more efficient, +/// but for now it may be slightly slow. +pub struct JsValue { + idx: u32, + _marker: marker::PhantomData<*mut u8>, // not at all threadsafe +} + +const JSIDX_OFFSET: u32 = 32; // keep in sync with js/mod.rs +const JSIDX_UNDEFINED: u32 = JSIDX_OFFSET + 0; +const JSIDX_NULL: u32 = JSIDX_OFFSET + 1; +const JSIDX_TRUE: u32 = JSIDX_OFFSET + 2; +const JSIDX_FALSE: u32 = JSIDX_OFFSET + 3; +const JSIDX_RESERVED: u32 = JSIDX_OFFSET + 4; + +impl JsValue { + /// The `null` JS value constant. + pub const NULL: JsValue = JsValue { + idx: JSIDX_NULL, + _marker: marker::PhantomData, + }; + + /// The `undefined` JS value constant. + pub const UNDEFINED: JsValue = JsValue { + idx: JSIDX_UNDEFINED, + _marker: marker::PhantomData, + }; + + /// The `true` JS value constant. + pub const TRUE: JsValue = JsValue { + idx: JSIDX_TRUE, + _marker: marker::PhantomData, + }; + + /// The `false` JS value constant. + pub const FALSE: JsValue = JsValue { + idx: JSIDX_FALSE, + _marker: marker::PhantomData, + }; + + #[inline] + fn _new(idx: u32) -> JsValue { + JsValue { + idx, + _marker: marker::PhantomData, + } + } + + /// Creates a new JS value which is a string. + /// + /// The utf-8 string provided is copied to the JS heap and the string will + /// be owned by the JS garbage collector. + #[inline] + pub fn from_str(s: &str) -> JsValue { + unsafe { JsValue::_new(__wbindgen_string_new(s.as_ptr(), s.len())) } + } + + /// Creates a new JS value which is a number. + /// + /// This function creates a JS value representing a number (a heap + /// allocated number) and returns a handle to the JS version of it. + #[inline] + pub fn from_f64(n: f64) -> JsValue { + unsafe { JsValue::_new(__wbindgen_number_new(n)) } + } + + /// Creates a new JS value which is a bigint from a string representing a number. + /// + /// This function creates a JS value representing a bigint (a heap + /// allocated large integer) and returns a handle to the JS version of it. + #[inline] + pub fn bigint_from_str(s: &str) -> JsValue { + unsafe { JsValue::_new(__wbindgen_bigint_from_str(s.as_ptr(), s.len())) } + } + + /// Creates a new JS value which is a boolean. + /// + /// This function creates a JS object representing a boolean (a heap + /// allocated boolean) and returns a handle to the JS version of it. + #[inline] + pub fn from_bool(b: bool) -> JsValue { + if b { + JsValue::TRUE + } else { + JsValue::FALSE + } + } + + /// Creates a new JS value representing `undefined`. + #[inline] + pub fn undefined() -> JsValue { + JsValue::UNDEFINED + } + + /// Creates a new JS value representing `null`. + #[inline] + pub fn null() -> JsValue { + JsValue::NULL + } + + /// Creates a new JS symbol with the optional description specified. + /// + /// This function will invoke the `Symbol` constructor in JS and return the + /// JS object corresponding to the symbol created. + pub fn symbol(description: Option<&str>) -> JsValue { + unsafe { + match description { + Some(description) => JsValue::_new(__wbindgen_symbol_named_new( + description.as_ptr(), + description.len(), + )), + None => JsValue::_new(__wbindgen_symbol_anonymous_new()), + } + } + } + + /// Creates a new `JsValue` from the JSON serialization of the object `t` + /// provided. + /// + /// **This function is deprecated**, due to [creating a dependency cycle in + /// some circumstances][dep-cycle-issue]. Use [`serde-wasm-bindgen`] or + /// [`gloo_utils::format::JsValueSerdeExt`] instead. + /// + /// [dep-cycle-issue]: https://github.com/rustwasm/wasm-bindgen/issues/2770 + /// [`serde-wasm-bindgen`]: https://docs.rs/serde-wasm-bindgen + /// [`gloo_utils::format::JsValueSerdeExt`]: https://docs.rs/gloo-utils/latest/gloo_utils/format/trait.JsValueSerdeExt.html + /// + /// This function will serialize the provided value `t` to a JSON string, + /// send the JSON string to JS, parse it into a JS object, and then return + /// a handle to the JS object. This is unlikely to be super speedy so it's + /// not recommended for large payloads, but it's a nice to have in some + /// situations! + /// + /// Usage of this API requires activating the `serde-serialize` feature of + /// the `wasm-bindgen` crate. + /// + /// # Errors + /// + /// Returns any error encountered when serializing `T` into JSON. + #[cfg(feature = "serde-serialize")] + #[deprecated = "causes dependency cycles, use `serde-wasm-bindgen` or `gloo_utils::format::JsValueSerdeExt` instead"] + pub fn from_serde<T>(t: &T) -> serde_json::Result<JsValue> + where + T: serde::ser::Serialize + ?Sized, + { + let s = serde_json::to_string(t)?; + unsafe { Ok(JsValue::_new(__wbindgen_json_parse(s.as_ptr(), s.len()))) } + } + + /// Invokes `JSON.stringify` on this value and then parses the resulting + /// JSON into an arbitrary Rust value. + /// + /// **This function is deprecated**, due to [creating a dependency cycle in + /// some circumstances][dep-cycle-issue]. Use [`serde-wasm-bindgen`] or + /// [`gloo_utils::format::JsValueSerdeExt`] instead. + /// + /// [dep-cycle-issue]: https://github.com/rustwasm/wasm-bindgen/issues/2770 + /// [`serde-wasm-bindgen`]: https://docs.rs/serde-wasm-bindgen + /// [`gloo_utils::format::JsValueSerdeExt`]: https://docs.rs/gloo-utils/latest/gloo_utils/format/trait.JsValueSerdeExt.html + /// + /// This function will first call `JSON.stringify` on the `JsValue` itself. + /// The resulting string is then passed into Rust which then parses it as + /// JSON into the resulting value. + /// + /// Usage of this API requires activating the `serde-serialize` feature of + /// the `wasm-bindgen` crate. + /// + /// # Errors + /// + /// Returns any error encountered when parsing the JSON into a `T`. + #[cfg(feature = "serde-serialize")] + #[deprecated = "causes dependency cycles, use `serde-wasm-bindgen` or `gloo_utils::format::JsValueSerdeExt` instead"] + pub fn into_serde<T>(&self) -> serde_json::Result<T> + where + T: for<'a> serde::de::Deserialize<'a>, + { + unsafe { + let ret = __wbindgen_json_serialize(self.idx); + let s = String::from_abi(ret); + serde_json::from_str(&s) + } + } + + /// Returns the `f64` value of this JS value if it's an instance of a + /// number. + /// + /// If this JS value is not an instance of a number then this returns + /// `None`. + #[inline] + pub fn as_f64(&self) -> Option<f64> { + unsafe { FromWasmAbi::from_abi(__wbindgen_number_get(self.idx)) } + } + + /// Tests whether this JS value is a JS string. + #[inline] + pub fn is_string(&self) -> bool { + unsafe { __wbindgen_is_string(self.idx) == 1 } + } + + /// If this JS value is a string value, this function copies the JS string + /// value into wasm linear memory, encoded as UTF-8, and returns it as a + /// Rust `String`. + /// + /// To avoid the copying and re-encoding, consider the + /// `JsString::try_from()` function from [js-sys](https://docs.rs/js-sys) + /// instead. + /// + /// If this JS value is not an instance of a string or if it's not valid + /// utf-8 then this returns `None`. + /// + /// # UTF-16 vs UTF-8 + /// + /// JavaScript strings in general are encoded as UTF-16, but Rust strings + /// are encoded as UTF-8. This can cause the Rust string to look a bit + /// different than the JS string sometimes. For more details see the + /// [documentation about the `str` type][caveats] which contains a few + /// caveats about the encodings. + /// + /// [caveats]: https://rustwasm.github.io/docs/wasm-bindgen/reference/types/str.html + #[cfg(feature = "std")] + #[inline] + pub fn as_string(&self) -> Option<String> { + unsafe { FromWasmAbi::from_abi(__wbindgen_string_get(self.idx)) } + } + + /// Returns the `bool` value of this JS value if it's an instance of a + /// boolean. + /// + /// If this JS value is not an instance of a boolean then this returns + /// `None`. + #[inline] + pub fn as_bool(&self) -> Option<bool> { + unsafe { + match __wbindgen_boolean_get(self.idx) { + 0 => Some(false), + 1 => Some(true), + _ => None, + } + } + } + + /// Tests whether this JS value is `null` + #[inline] + pub fn is_null(&self) -> bool { + unsafe { __wbindgen_is_null(self.idx) == 1 } + } + + /// Tests whether this JS value is `undefined` + #[inline] + pub fn is_undefined(&self) -> bool { + unsafe { __wbindgen_is_undefined(self.idx) == 1 } + } + + /// Tests whether the type of this JS value is `symbol` + #[inline] + pub fn is_symbol(&self) -> bool { + unsafe { __wbindgen_is_symbol(self.idx) == 1 } + } + + /// Tests whether `typeof self == "object" && self !== null`. + #[inline] + pub fn is_object(&self) -> bool { + unsafe { __wbindgen_is_object(self.idx) == 1 } + } + + /// Tests whether the type of this JS value is `function`. + #[inline] + pub fn is_function(&self) -> bool { + unsafe { __wbindgen_is_function(self.idx) == 1 } + } + + /// Tests whether the type of this JS value is `bigint`. + #[inline] + pub fn is_bigint(&self) -> bool { + unsafe { __wbindgen_is_bigint(self.idx) == 1 } + } + + /// Applies the unary `typeof` JS operator on a `JsValue`. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof) + #[inline] + pub fn js_typeof(&self) -> JsValue { + unsafe { JsValue::_new(__wbindgen_typeof(self.idx)) } + } + + /// Applies the binary `in` JS operator on the two `JsValue`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/in) + #[inline] + pub fn js_in(&self, obj: &JsValue) -> bool { + unsafe { __wbindgen_in(self.idx, obj.idx) == 1 } + } + + /// Tests whether the value is ["truthy"]. + /// + /// ["truthy"]: https://developer.mozilla.org/en-US/docs/Glossary/Truthy + #[inline] + pub fn is_truthy(&self) -> bool { + !self.is_falsy() + } + + /// Tests whether the value is ["falsy"]. + /// + /// ["falsy"]: https://developer.mozilla.org/en-US/docs/Glossary/Falsy + #[inline] + pub fn is_falsy(&self) -> bool { + unsafe { __wbindgen_is_falsy(self.idx) == 1 } + } + + /// Get a string representation of the JavaScript object for debugging. + #[cfg(feature = "std")] + fn as_debug_string(&self) -> String { + unsafe { + let mut ret = [0; 2]; + __wbindgen_debug_string(&mut ret, self.idx); + let data = Vec::from_raw_parts(ret[0] as *mut u8, ret[1], ret[1]); + String::from_utf8_unchecked(data) + } + } + + /// Compare two `JsValue`s for equality, using the `==` operator in JS. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Equality) + #[inline] + pub fn loose_eq(&self, other: &Self) -> bool { + unsafe { __wbindgen_jsval_loose_eq(self.idx, other.idx) != 0 } + } + + /// Applies the unary `~` JS operator on a `JsValue`. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_NOT) + #[inline] + pub fn bit_not(&self) -> JsValue { + unsafe { JsValue::_new(__wbindgen_bit_not(self.idx)) } + } + + /// Applies the binary `>>>` JS operator on the two `JsValue`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unsigned_right_shift) + #[inline] + pub fn unsigned_shr(&self, rhs: &Self) -> u32 { + unsafe { __wbindgen_unsigned_shr(self.idx, rhs.idx) } + } + + /// Applies the binary `/` JS operator on two `JsValue`s, catching and returning any `RangeError` thrown. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Division) + #[inline] + pub fn checked_div(&self, rhs: &Self) -> Self { + unsafe { JsValue::_new(__wbindgen_checked_div(self.idx, rhs.idx)) } + } + + /// Applies the binary `**` JS operator on the two `JsValue`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Exponentiation) + #[inline] + pub fn pow(&self, rhs: &Self) -> Self { + unsafe { JsValue::_new(__wbindgen_pow(self.idx, rhs.idx)) } + } + + /// Applies the binary `<` JS operator on the two `JsValue`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Less_than) + #[inline] + pub fn lt(&self, other: &Self) -> bool { + unsafe { __wbindgen_lt(self.idx, other.idx) == 1 } + } + + /// Applies the binary `<=` JS operator on the two `JsValue`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Less_than_or_equal) + #[inline] + pub fn le(&self, other: &Self) -> bool { + unsafe { __wbindgen_le(self.idx, other.idx) == 1 } + } + + /// Applies the binary `>=` JS operator on the two `JsValue`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Greater_than_or_equal) + #[inline] + pub fn ge(&self, other: &Self) -> bool { + unsafe { __wbindgen_ge(self.idx, other.idx) == 1 } + } + + /// Applies the binary `>` JS operator on the two `JsValue`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Greater_than) + #[inline] + pub fn gt(&self, other: &Self) -> bool { + unsafe { __wbindgen_gt(self.idx, other.idx) == 1 } + } + + /// Applies the unary `+` JS operator on a `JsValue`. Can throw. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unary_plus) + #[inline] + pub fn unchecked_into_f64(&self) -> f64 { + unsafe { __wbindgen_as_number(self.idx) } + } +} + +impl PartialEq for JsValue { + /// Compares two `JsValue`s for equality, using the `===` operator in JS. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Strict_equality) + #[inline] + fn eq(&self, other: &Self) -> bool { + unsafe { __wbindgen_jsval_eq(self.idx, other.idx) != 0 } + } +} + +impl PartialEq<bool> for JsValue { + #[inline] + fn eq(&self, other: &bool) -> bool { + self.as_bool() == Some(*other) + } +} + +impl PartialEq<str> for JsValue { + #[inline] + fn eq(&self, other: &str) -> bool { + *self == JsValue::from_str(other) + } +} + +impl<'a> PartialEq<&'a str> for JsValue { + #[inline] + fn eq(&self, other: &&'a str) -> bool { + <JsValue as PartialEq<str>>::eq(self, other) + } +} + +if_std! { + impl PartialEq<String> for JsValue { + #[inline] + fn eq(&self, other: &String) -> bool { + <JsValue as PartialEq<str>>::eq(self, other) + } + } + impl<'a> PartialEq<&'a String> for JsValue { + #[inline] + fn eq(&self, other: &&'a String) -> bool { + <JsValue as PartialEq<str>>::eq(self, other) + } + } +} + +macro_rules! forward_deref_unop { + (impl $imp:ident, $method:ident for $t:ty) => { + impl $imp for $t { + type Output = <&'static $t as $imp>::Output; + + #[inline] + fn $method(self) -> <&'static $t as $imp>::Output { + $imp::$method(&self) + } + } + }; +} + +macro_rules! forward_deref_binop { + (impl $imp:ident, $method:ident for $t:ty) => { + impl<'a> $imp<$t> for &'a $t { + type Output = <&'static $t as $imp<&'static $t>>::Output; + + #[inline] + fn $method(self, other: $t) -> <&'static $t as $imp<&'static $t>>::Output { + $imp::$method(self, &other) + } + } + + impl $imp<&$t> for $t { + type Output = <&'static $t as $imp<&'static $t>>::Output; + + #[inline] + fn $method(self, other: &$t) -> <&'static $t as $imp<&'static $t>>::Output { + $imp::$method(&self, other) + } + } + + impl $imp<$t> for $t { + type Output = <&'static $t as $imp<&'static $t>>::Output; + + #[inline] + fn $method(self, other: $t) -> <&'static $t as $imp<&'static $t>>::Output { + $imp::$method(&self, &other) + } + } + }; +} + +impl Not for &JsValue { + type Output = bool; + + /// Applies the `!` JS operator on a `JsValue`. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_NOT) + #[inline] + fn not(self) -> Self::Output { + JsValue::is_falsy(self) + } +} + +forward_deref_unop!(impl Not, not for JsValue); + +impl TryFrom<JsValue> for f64 { + type Error = JsValue; + + /// Applies the unary `+` JS operator on a `JsValue`. + /// Returns the numeric result on success, or the JS error value on error. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unary_plus) + #[inline] + fn try_from(val: JsValue) -> Result<Self, Self::Error> { + f64::try_from(&val) + } +} + +impl TryFrom<&JsValue> for f64 { + type Error = JsValue; + + /// Applies the unary `+` JS operator on a `JsValue`. + /// Returns the numeric result on success, or the JS error value on error. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unary_plus) + #[inline] + fn try_from(val: &JsValue) -> Result<Self, Self::Error> { + let jsval = unsafe { JsValue::_new(__wbindgen_try_into_number(val.idx)) }; + return match jsval.as_f64() { + Some(num) => Ok(num), + None => Err(jsval), + }; + } +} + +impl Neg for &JsValue { + type Output = JsValue; + + /// Applies the unary `-` JS operator on a `JsValue`. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unary_negation) + #[inline] + fn neg(self) -> Self::Output { + unsafe { JsValue::_new(__wbindgen_neg(self.idx)) } + } +} + +forward_deref_unop!(impl Neg, neg for JsValue); + +impl BitAnd for &JsValue { + type Output = JsValue; + + /// Applies the binary `&` JS operator on two `JsValue`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_AND) + #[inline] + fn bitand(self, rhs: Self) -> Self::Output { + unsafe { JsValue::_new(__wbindgen_bit_and(self.idx, rhs.idx)) } + } +} + +forward_deref_binop!(impl BitAnd, bitand for JsValue); + +impl BitOr for &JsValue { + type Output = JsValue; + + /// Applies the binary `|` JS operator on two `JsValue`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_OR) + #[inline] + fn bitor(self, rhs: Self) -> Self::Output { + unsafe { JsValue::_new(__wbindgen_bit_or(self.idx, rhs.idx)) } + } +} + +forward_deref_binop!(impl BitOr, bitor for JsValue); + +impl BitXor for &JsValue { + type Output = JsValue; + + /// Applies the binary `^` JS operator on two `JsValue`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_XOR) + #[inline] + fn bitxor(self, rhs: Self) -> Self::Output { + unsafe { JsValue::_new(__wbindgen_bit_xor(self.idx, rhs.idx)) } + } +} + +forward_deref_binop!(impl BitXor, bitxor for JsValue); + +impl Shl for &JsValue { + type Output = JsValue; + + /// Applies the binary `<<` JS operator on two `JsValue`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Left_shift) + #[inline] + fn shl(self, rhs: Self) -> Self::Output { + unsafe { JsValue::_new(__wbindgen_shl(self.idx, rhs.idx)) } + } +} + +forward_deref_binop!(impl Shl, shl for JsValue); + +impl Shr for &JsValue { + type Output = JsValue; + + /// Applies the binary `>>` JS operator on two `JsValue`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Right_shift) + #[inline] + fn shr(self, rhs: Self) -> Self::Output { + unsafe { JsValue::_new(__wbindgen_shr(self.idx, rhs.idx)) } + } +} + +forward_deref_binop!(impl Shr, shr for JsValue); + +impl Add for &JsValue { + type Output = JsValue; + + /// Applies the binary `+` JS operator on two `JsValue`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Addition) + #[inline] + fn add(self, rhs: Self) -> Self::Output { + unsafe { JsValue::_new(__wbindgen_add(self.idx, rhs.idx)) } + } +} + +forward_deref_binop!(impl Add, add for JsValue); + +impl Sub for &JsValue { + type Output = JsValue; + + /// Applies the binary `-` JS operator on two `JsValue`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Subtraction) + #[inline] + fn sub(self, rhs: Self) -> Self::Output { + unsafe { JsValue::_new(__wbindgen_sub(self.idx, rhs.idx)) } + } +} + +forward_deref_binop!(impl Sub, sub for JsValue); + +impl Div for &JsValue { + type Output = JsValue; + + /// Applies the binary `/` JS operator on two `JsValue`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Division) + #[inline] + fn div(self, rhs: Self) -> Self::Output { + unsafe { JsValue::_new(__wbindgen_div(self.idx, rhs.idx)) } + } +} + +forward_deref_binop!(impl Div, div for JsValue); + +impl Mul for &JsValue { + type Output = JsValue; + + /// Applies the binary `*` JS operator on two `JsValue`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Multiplication) + #[inline] + fn mul(self, rhs: Self) -> Self::Output { + unsafe { JsValue::_new(__wbindgen_mul(self.idx, rhs.idx)) } + } +} + +forward_deref_binop!(impl Mul, mul for JsValue); + +impl Rem for &JsValue { + type Output = JsValue; + + /// Applies the binary `%` JS operator on two `JsValue`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Remainder) + #[inline] + fn rem(self, rhs: Self) -> Self::Output { + unsafe { JsValue::_new(__wbindgen_rem(self.idx, rhs.idx)) } + } +} + +forward_deref_binop!(impl Rem, rem for JsValue); + +impl<'a> From<&'a str> for JsValue { + #[inline] + fn from(s: &'a str) -> JsValue { + JsValue::from_str(s) + } +} + +if_std! { + impl<'a> From<&'a String> for JsValue { + #[inline] + fn from(s: &'a String) -> JsValue { + JsValue::from_str(s) + } + } + + impl From<String> for JsValue { + #[inline] + fn from(s: String) -> JsValue { + JsValue::from_str(&s) + } + } +} + +impl From<bool> for JsValue { + #[inline] + fn from(s: bool) -> JsValue { + JsValue::from_bool(s) + } +} + +impl<'a, T> From<&'a T> for JsValue +where + T: JsCast, +{ + #[inline] + fn from(s: &'a T) -> JsValue { + s.as_ref().clone() + } +} + +impl<T> From<Option<T>> for JsValue +where + JsValue: From<T>, +{ + #[inline] + fn from(s: Option<T>) -> JsValue { + match s { + Some(s) => s.into(), + None => JsValue::undefined(), + } + } +} + +impl JsCast for JsValue { + // everything is a `JsValue`! + #[inline] + fn instanceof(_val: &JsValue) -> bool { + true + } + #[inline] + fn unchecked_from_js(val: JsValue) -> Self { + val + } + #[inline] + fn unchecked_from_js_ref(val: &JsValue) -> &Self { + val + } +} + +impl AsRef<JsValue> for JsValue { + #[inline] + fn as_ref(&self) -> &JsValue { + self + } +} + +macro_rules! numbers { + ($($n:ident)*) => ($( + impl PartialEq<$n> for JsValue { + #[inline] + fn eq(&self, other: &$n) -> bool { + self.as_f64() == Some(f64::from(*other)) + } + } + + impl From<$n> for JsValue { + #[inline] + fn from(n: $n) -> JsValue { + JsValue::from_f64(n.into()) + } + } + )*) +} + +numbers! { i8 u8 i16 u16 i32 u32 f32 f64 } + +macro_rules! big_numbers { + (|$arg:ident|, $($n:ident = $handle:expr,)*) => ($( + impl PartialEq<$n> for JsValue { + #[inline] + fn eq(&self, other: &$n) -> bool { + self == &JsValue::from(*other) + } + } + + impl From<$n> for JsValue { + #[inline] + fn from($arg: $n) -> JsValue { + unsafe { JsValue::_new($handle) } + } + } + )*) +} + +fn bigint_get_as_i64(v: &JsValue) -> Option<i64> { + unsafe { Option::from_abi(__wbindgen_bigint_get_as_i64(v.idx)) } +} + +macro_rules! try_from_for_num64 { + ($ty:ty) => { + impl TryFrom<JsValue> for $ty { + type Error = JsValue; + + #[inline] + fn try_from(v: JsValue) -> Result<Self, JsValue> { + bigint_get_as_i64(&v) + // Reinterpret bits; ABI-wise this is safe to do and allows us to avoid + // having separate intrinsics per signed/unsigned types. + .map(|as_i64| as_i64 as Self) + // Double-check that we didn't truncate the bigint to 64 bits. + .filter(|as_self| v == *as_self) + // Not a bigint or not in range. + .ok_or(v) + } + } + }; +} + +try_from_for_num64!(i64); +try_from_for_num64!(u64); + +macro_rules! try_from_for_num128 { + ($ty:ty, $hi_ty:ty) => { + impl TryFrom<JsValue> for $ty { + type Error = JsValue; + + #[inline] + fn try_from(v: JsValue) -> Result<Self, JsValue> { + // Truncate the bigint to 64 bits, this will give us the lower part. + let lo = match bigint_get_as_i64(&v) { + // The lower part must be interpreted as unsigned in both i128 and u128. + Some(lo) => lo as u64, + // Not a bigint. + None => return Err(v), + }; + // Now we know it's a bigint, so we can safely use `>> 64n` without + // worrying about a JS exception on type mismatch. + let hi = v >> JsValue::from(64_u64); + // The high part is the one we want checked against a 64-bit range. + // If it fits, then our original number is in the 128-bit range. + let hi = <$hi_ty>::try_from(hi)?; + Ok(Self::from(hi) << 64 | Self::from(lo)) + } + } + }; +} + +try_from_for_num128!(i128, i64); +try_from_for_num128!(u128, u64); + +big_numbers! { + |n|, + i64 = __wbindgen_bigint_from_i64(n), + u64 = __wbindgen_bigint_from_u64(n), + i128 = __wbindgen_bigint_from_i128((n >> 64) as i64, n as u64), + u128 = __wbindgen_bigint_from_u128((n >> 64) as u64, n as u64), +} + +// `usize` and `isize` have to be treated a bit specially, because we know that +// they're 32-bit but the compiler conservatively assumes they might be bigger. +// So, we have to manually forward to the `u32`/`i32` versions. +impl PartialEq<usize> for JsValue { + #[inline] + fn eq(&self, other: &usize) -> bool { + *self == (*other as u32) + } +} + +impl From<usize> for JsValue { + #[inline] + fn from(n: usize) -> Self { + Self::from(n as u32) + } +} + +impl PartialEq<isize> for JsValue { + #[inline] + fn eq(&self, other: &isize) -> bool { + *self == (*other as i32) + } +} + +impl From<isize> for JsValue { + #[inline] + fn from(n: isize) -> Self { + Self::from(n as i32) + } +} + +externs! { + #[link(wasm_import_module = "__wbindgen_placeholder__")] + extern "C" { + fn __wbindgen_object_clone_ref(idx: u32) -> u32; + fn __wbindgen_object_drop_ref(idx: u32) -> (); + + fn __wbindgen_string_new(ptr: *const u8, len: usize) -> u32; + fn __wbindgen_number_new(f: f64) -> u32; + fn __wbindgen_bigint_from_str(ptr: *const u8, len: usize) -> u32; + fn __wbindgen_bigint_from_i64(n: i64) -> u32; + fn __wbindgen_bigint_from_u64(n: u64) -> u32; + fn __wbindgen_bigint_from_i128(hi: i64, lo: u64) -> u32; + fn __wbindgen_bigint_from_u128(hi: u64, lo: u64) -> u32; + fn __wbindgen_symbol_named_new(ptr: *const u8, len: usize) -> u32; + fn __wbindgen_symbol_anonymous_new() -> u32; + + fn __wbindgen_externref_heap_live_count() -> u32; + + fn __wbindgen_is_null(idx: u32) -> u32; + fn __wbindgen_is_undefined(idx: u32) -> u32; + fn __wbindgen_is_symbol(idx: u32) -> u32; + fn __wbindgen_is_object(idx: u32) -> u32; + fn __wbindgen_is_function(idx: u32) -> u32; + fn __wbindgen_is_string(idx: u32) -> u32; + fn __wbindgen_is_bigint(idx: u32) -> u32; + fn __wbindgen_typeof(idx: u32) -> u32; + + fn __wbindgen_in(prop: u32, obj: u32) -> u32; + + fn __wbindgen_is_falsy(idx: u32) -> u32; + fn __wbindgen_as_number(idx: u32) -> f64; + fn __wbindgen_try_into_number(idx: u32) -> u32; + fn __wbindgen_neg(idx: u32) -> u32; + fn __wbindgen_bit_and(a: u32, b: u32) -> u32; + fn __wbindgen_bit_or(a: u32, b: u32) -> u32; + fn __wbindgen_bit_xor(a: u32, b: u32) -> u32; + fn __wbindgen_bit_not(idx: u32) -> u32; + fn __wbindgen_shl(a: u32, b: u32) -> u32; + fn __wbindgen_shr(a: u32, b: u32) -> u32; + fn __wbindgen_unsigned_shr(a: u32, b: u32) -> u32; + fn __wbindgen_add(a: u32, b: u32) -> u32; + fn __wbindgen_sub(a: u32, b: u32) -> u32; + fn __wbindgen_div(a: u32, b: u32) -> u32; + fn __wbindgen_checked_div(a: u32, b: u32) -> u32; + fn __wbindgen_mul(a: u32, b: u32) -> u32; + fn __wbindgen_rem(a: u32, b: u32) -> u32; + fn __wbindgen_pow(a: u32, b: u32) -> u32; + fn __wbindgen_lt(a: u32, b: u32) -> u32; + fn __wbindgen_le(a: u32, b: u32) -> u32; + fn __wbindgen_ge(a: u32, b: u32) -> u32; + fn __wbindgen_gt(a: u32, b: u32) -> u32; + + fn __wbindgen_number_get(idx: u32) -> WasmOption<f64>; + fn __wbindgen_boolean_get(idx: u32) -> u32; + fn __wbindgen_string_get(idx: u32) -> WasmSlice; + fn __wbindgen_bigint_get_as_i64(idx: u32) -> WasmOption<i64>; + + fn __wbindgen_debug_string(ret: *mut [usize; 2], idx: u32) -> (); + + fn __wbindgen_throw(a: *const u8, b: usize) -> !; + fn __wbindgen_rethrow(a: u32) -> !; + fn __wbindgen_error_new(a: *const u8, b: usize) -> u32; + + fn __wbindgen_cb_drop(idx: u32) -> u32; + + fn __wbindgen_describe(v: u32) -> (); + fn __wbindgen_describe_closure(a: u32, b: u32, c: u32) -> u32; + + fn __wbindgen_json_parse(ptr: *const u8, len: usize) -> u32; + fn __wbindgen_json_serialize(idx: u32) -> WasmSlice; + fn __wbindgen_jsval_eq(a: u32, b: u32) -> u32; + fn __wbindgen_jsval_loose_eq(a: u32, b: u32) -> u32; + + fn __wbindgen_not(idx: u32) -> u32; + + fn __wbindgen_memory() -> u32; + fn __wbindgen_module() -> u32; + fn __wbindgen_function_table() -> u32; + } +} + +impl Clone for JsValue { + #[inline] + fn clone(&self) -> JsValue { + unsafe { + let idx = __wbindgen_object_clone_ref(self.idx); + JsValue::_new(idx) + } + } +} + +#[cfg(feature = "std")] +impl fmt::Debug for JsValue { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "JsValue({})", self.as_debug_string()) + } +} + +#[cfg(not(feature = "std"))] +impl fmt::Debug for JsValue { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("JsValue") + } +} + +impl Drop for JsValue { + #[inline] + fn drop(&mut self) { + unsafe { + // We definitely should never drop anything in the stack area + debug_assert!(self.idx >= JSIDX_OFFSET, "free of stack slot {}", self.idx); + + // Otherwise if we're not dropping one of our reserved values, + // actually call the intrinsic. See #1054 for eventually removing + // this branch. + if self.idx >= JSIDX_RESERVED { + __wbindgen_object_drop_ref(self.idx); + } + } + } +} + +impl Default for JsValue { + fn default() -> Self { + Self::UNDEFINED + } +} + +/// Wrapper type for imported statics. +/// +/// This type is used whenever a `static` is imported from a JS module, for +/// example this import: +/// +/// ```ignore +/// #[wasm_bindgen] +/// extern "C" { +/// static console: JsValue; +/// } +/// ``` +/// +/// will generate in Rust a value that looks like: +/// +/// ```ignore +/// static console: JsStatic<JsValue> = ...; +/// ``` +/// +/// This type implements `Deref` to the inner type so it's typically used as if +/// it were `&T`. +#[cfg(feature = "std")] +pub struct JsStatic<T: 'static> { + #[doc(hidden)] + pub __inner: &'static std::thread::LocalKey<T>, +} + +#[cfg(feature = "std")] +impl<T: FromWasmAbi + 'static> Deref for JsStatic<T> { + type Target = T; + fn deref(&self) -> &T { + // We know that our tls key is never overwritten after initialization, + // so it should be safe (on that axis at least) to hand out a reference + // that lives longer than the closure below. + // + // FIXME: this is not sound if we ever implement thread exit hooks on + // wasm, as the pointer will eventually be invalidated but you can get + // `&'static T` from this interface. We... probably need to deprecate + // and/or remove this interface nowadays. + unsafe { self.__inner.with(|ptr| &*(ptr as *const T)) } + } +} + +#[cold] +#[inline(never)] +#[deprecated(note = "renamed to `throw_str`")] +#[doc(hidden)] +pub fn throw(s: &str) -> ! { + throw_str(s) +} + +/// Throws a JS exception. +/// +/// This function will throw a JS exception with the message provided. The +/// function will not return as the wasm stack will be popped when the exception +/// is thrown. +/// +/// Note that it is very easy to leak memory with this function because this +/// function, unlike `panic!` on other platforms, **will not run destructors**. +/// It's recommended to return a `Result` where possible to avoid the worry of +/// leaks. +#[cold] +#[inline(never)] +pub fn throw_str(s: &str) -> ! { + unsafe { + __wbindgen_throw(s.as_ptr(), s.len()); + } +} + +/// Rethrow a JS exception +/// +/// This function will throw a JS exception with the JS value provided. This +/// function will not return and the wasm stack will be popped until the point +/// of entry of wasm itself. +/// +/// Note that it is very easy to leak memory with this function because this +/// function, unlike `panic!` on other platforms, **will not run destructors**. +/// It's recommended to return a `Result` where possible to avoid the worry of +/// leaks. +#[cold] +#[inline(never)] +pub fn throw_val(s: JsValue) -> ! { + unsafe { + let idx = s.idx; + mem::forget(s); + __wbindgen_rethrow(idx); + } +} + +/// Get the count of live `externref`s / `JsValue`s in `wasm-bindgen`'s heap. +/// +/// ## Usage +/// +/// This is intended for debugging and writing tests. +/// +/// To write a test that asserts against unnecessarily keeping `anref`s / +/// `JsValue`s alive: +/// +/// * get an initial live count, +/// +/// * perform some series of operations or function calls that should clean up +/// after themselves, and should not keep holding onto `externref`s / `JsValue`s +/// after completion, +/// +/// * get the final live count, +/// +/// * and assert that the initial and final counts are the same. +/// +/// ## What is Counted +/// +/// Note that this only counts the *owned* `externref`s / `JsValue`s that end up in +/// `wasm-bindgen`'s heap. It does not count borrowed `externref`s / `JsValue`s +/// that are on its stack. +/// +/// For example, these `JsValue`s are accounted for: +/// +/// ```ignore +/// #[wasm_bindgen] +/// pub fn my_function(this_is_counted: JsValue) { +/// let also_counted = JsValue::from_str("hi"); +/// assert!(wasm_bindgen::externref_heap_live_count() >= 2); +/// } +/// ``` +/// +/// While this borrowed `JsValue` ends up on the stack, not the heap, and +/// therefore is not accounted for: +/// +/// ```ignore +/// #[wasm_bindgen] +/// pub fn my_other_function(this_is_not_counted: &JsValue) { +/// // ... +/// } +/// ``` +pub fn externref_heap_live_count() -> u32 { + unsafe { __wbindgen_externref_heap_live_count() } +} + +#[doc(hidden)] +pub fn anyref_heap_live_count() -> u32 { + externref_heap_live_count() +} + +/// An extension trait for `Option<T>` and `Result<T, E>` for unwrapping the `T` +/// value, or throwing a JS error if it is not available. +/// +/// These methods should have a smaller code size footprint than the normal +/// `Option::unwrap` and `Option::expect` methods, but they are specific to +/// working with wasm and JS. +/// +/// On non-wasm32 targets, defaults to the normal unwrap/expect calls. +/// +/// # Example +/// +/// ``` +/// use wasm_bindgen::prelude::*; +/// +/// // If the value is `Option::Some` or `Result::Ok`, then we just get the +/// // contained `T` value. +/// let x = Some(42); +/// assert_eq!(x.unwrap_throw(), 42); +/// +/// let y: Option<i32> = None; +/// +/// // This call would throw an error to JS! +/// // +/// // y.unwrap_throw() +/// // +/// // And this call would throw an error to JS with a custom error message! +/// // +/// // y.expect_throw("woopsie daisy!") +/// ``` +pub trait UnwrapThrowExt<T>: Sized { + /// Unwrap this `Option` or `Result`, but instead of panicking on failure, + /// throw an exception to JavaScript. + fn unwrap_throw(self) -> T { + self.expect_throw("`unwrap_throw` failed") + } + + /// Unwrap this container's `T` value, or throw an error to JS with the + /// given message if the `T` value is unavailable (e.g. an `Option<T>` is + /// `None`). + fn expect_throw(self, message: &str) -> T; +} + +impl<T> UnwrapThrowExt<T> for Option<T> { + fn expect_throw(self, message: &str) -> T { + if cfg!(all(target_arch = "wasm32", not(target_os = "emscripten"))) { + match self { + Some(val) => val, + None => throw_str(message), + } + } else { + self.expect(message) + } + } +} + +impl<T, E> UnwrapThrowExt<T> for Result<T, E> +where + E: core::fmt::Debug, +{ + fn expect_throw(self, message: &str) -> T { + if cfg!(all(target_arch = "wasm32", not(target_os = "emscripten"))) { + match self { + Ok(val) => val, + Err(_) => throw_str(message), + } + } else { + self.expect(message) + } + } +} + +/// Returns a handle to this wasm instance's `WebAssembly.Module` +/// +/// Note that this is only available when the final wasm app is built with +/// `--target no-modules`, it's not recommended to rely on this API yet! This is +/// largely just an experimental addition to enable threading demos. Using this +/// may prevent your wasm module from building down the road. +#[doc(hidden)] +pub fn module() -> JsValue { + unsafe { JsValue::_new(__wbindgen_module()) } +} + +/// Returns a handle to this wasm instance's `WebAssembly.Memory` +pub fn memory() -> JsValue { + unsafe { JsValue::_new(__wbindgen_memory()) } +} + +/// Returns a handle to this wasm instance's `WebAssembly.Table` which is the +/// indirect function table used by Rust +pub fn function_table() -> JsValue { + unsafe { JsValue::_new(__wbindgen_function_table()) } +} + +#[doc(hidden)] +pub mod __rt { + use crate::JsValue; + use core::cell::{Cell, UnsafeCell}; + use core::ops::{Deref, DerefMut}; + + pub extern crate core; + #[cfg(feature = "std")] + pub extern crate std; + + #[macro_export] + #[doc(hidden)] + #[cfg(feature = "std")] + macro_rules! __wbindgen_if_not_std { + ($($i:item)*) => {}; + } + + #[macro_export] + #[doc(hidden)] + #[cfg(not(feature = "std"))] + macro_rules! __wbindgen_if_not_std { + ($($i:item)*) => ($($i)*) + } + + #[inline] + pub fn assert_not_null<T>(s: *mut T) { + if s.is_null() { + throw_null(); + } + } + + #[cold] + #[inline(never)] + fn throw_null() -> ! { + super::throw_str("null pointer passed to rust"); + } + + /// A vendored version of `RefCell` from the standard library. + /// + /// Now why, you may ask, would we do that? Surely `RefCell` in libstd is + /// quite good. And you're right, it is indeed quite good! Functionally + /// nothing more is needed from `RefCell` in the standard library but for + /// now this crate is also sort of optimizing for compiled code size. + /// + /// One major factor to larger binaries in Rust is when a panic happens. + /// Panicking in the standard library involves a fair bit of machinery + /// (formatting, panic hooks, synchronization, etc). It's all worthwhile if + /// you need it but for something like `WasmRefCell` here we don't actually + /// need all that! + /// + /// This is just a wrapper around all Rust objects passed to JS intended to + /// guard accidental reentrancy, so this vendored version is intended solely + /// to not panic in libstd. Instead when it "panics" it calls our `throw` + /// function in this crate which raises an error in JS. + pub struct WasmRefCell<T: ?Sized> { + borrow: Cell<usize>, + value: UnsafeCell<T>, + } + + impl<T: ?Sized> WasmRefCell<T> { + pub fn new(value: T) -> WasmRefCell<T> + where + T: Sized, + { + WasmRefCell { + value: UnsafeCell::new(value), + borrow: Cell::new(0), + } + } + + pub fn get_mut(&mut self) -> &mut T { + unsafe { &mut *self.value.get() } + } + + pub fn borrow(&self) -> Ref<T> { + unsafe { + if self.borrow.get() == usize::max_value() { + borrow_fail(); + } + self.borrow.set(self.borrow.get() + 1); + Ref { + value: &*self.value.get(), + borrow: &self.borrow, + } + } + } + + pub fn borrow_mut(&self) -> RefMut<T> { + unsafe { + if self.borrow.get() != 0 { + borrow_fail(); + } + self.borrow.set(usize::max_value()); + RefMut { + value: &mut *self.value.get(), + borrow: &self.borrow, + } + } + } + + pub fn into_inner(self) -> T + where + T: Sized, + { + self.value.into_inner() + } + } + + pub struct Ref<'b, T: ?Sized + 'b> { + value: &'b T, + borrow: &'b Cell<usize>, + } + + impl<'b, T: ?Sized> Deref for Ref<'b, T> { + type Target = T; + + #[inline] + fn deref(&self) -> &T { + self.value + } + } + + impl<'b, T: ?Sized> Drop for Ref<'b, T> { + fn drop(&mut self) { + self.borrow.set(self.borrow.get() - 1); + } + } + + pub struct RefMut<'b, T: ?Sized + 'b> { + value: &'b mut T, + borrow: &'b Cell<usize>, + } + + impl<'b, T: ?Sized> Deref for RefMut<'b, T> { + type Target = T; + + #[inline] + fn deref(&self) -> &T { + self.value + } + } + + impl<'b, T: ?Sized> DerefMut for RefMut<'b, T> { + #[inline] + fn deref_mut(&mut self) -> &mut T { + self.value + } + } + + impl<'b, T: ?Sized> Drop for RefMut<'b, T> { + fn drop(&mut self) { + self.borrow.set(0); + } + } + + fn borrow_fail() -> ! { + super::throw_str( + "recursive use of an object detected which would lead to \ + unsafe aliasing in rust", + ); + } + + if_std! { + use std::alloc::{alloc, dealloc, realloc, Layout}; + use std::mem; + + #[no_mangle] + pub extern "C" fn __wbindgen_malloc(size: usize) -> *mut u8 { + let align = mem::align_of::<usize>(); + if let Ok(layout) = Layout::from_size_align(size, align) { + unsafe { + if layout.size() > 0 { + let ptr = alloc(layout); + if !ptr.is_null() { + return ptr + } + } else { + return align as *mut u8 + } + } + } + + malloc_failure(); + } + + #[no_mangle] + pub unsafe extern "C" fn __wbindgen_realloc(ptr: *mut u8, old_size: usize, new_size: usize) -> *mut u8 { + let align = mem::align_of::<usize>(); + debug_assert!(old_size > 0); + debug_assert!(new_size > 0); + if let Ok(layout) = Layout::from_size_align(old_size, align) { + let ptr = realloc(ptr, layout, new_size); + if !ptr.is_null() { + return ptr + } + } + malloc_failure(); + } + + #[cold] + fn malloc_failure() -> ! { + if cfg!(debug_assertions) { + super::throw_str("invalid malloc request") + } else { + std::process::abort(); + } + } + + #[no_mangle] + pub unsafe extern "C" fn __wbindgen_free(ptr: *mut u8, size: usize) { + // This happens for zero-length slices, and in that case `ptr` is + // likely bogus so don't actually send this to the system allocator + if size == 0 { + return + } + let align = mem::align_of::<usize>(); + let layout = Layout::from_size_align_unchecked(size, align); + dealloc(ptr, layout); + } + } + + /// This is a curious function necessary to get wasm-bindgen working today, + /// and it's a bit of an unfortunate hack. + /// + /// The general problem is that somehow we need the above two symbols to + /// exist in the final output binary (__wbindgen_malloc and + /// __wbindgen_free). These symbols may be called by JS for various + /// bindings, so we for sure need to make sure they're exported. + /// + /// The problem arises, though, when what if no Rust code uses the symbols? + /// For all intents and purposes it looks to LLVM and the linker like the + /// above two symbols are dead code, so they're completely discarded! + /// + /// Specifically what happens is this: + /// + /// * The above two symbols are generated into some object file inside of + /// libwasm_bindgen.rlib + /// * The linker, LLD, will not load this object file unless *some* symbol + /// is loaded from the object. In this case, if the Rust code never calls + /// __wbindgen_malloc or __wbindgen_free then the symbols never get linked + /// in. + /// * Later when `wasm-bindgen` attempts to use the symbols they don't + /// exist, causing an error. + /// + /// This function is a weird hack for this problem. We inject a call to this + /// function in all generated code. Usage of this function should then + /// ensure that the above two intrinsics are translated. + /// + /// Due to how rustc creates object files this function (and anything inside + /// it) will be placed into the same object file as the two intrinsics + /// above. That means if this function is called and referenced we'll pull + /// in the object file and link the intrinsics. + /// + /// Ideas for how to improve this are most welcome! + pub fn link_mem_intrinsics() { + crate::externref::link_intrinsics(); + } + + static mut GLOBAL_EXNDATA: [u32; 2] = [0; 2]; + + #[no_mangle] + pub unsafe extern "C" fn __wbindgen_exn_store(idx: u32) { + debug_assert_eq!(GLOBAL_EXNDATA[0], 0); + GLOBAL_EXNDATA[0] = 1; + GLOBAL_EXNDATA[1] = idx; + } + + pub fn take_last_exception() -> Result<(), super::JsValue> { + unsafe { + let ret = if GLOBAL_EXNDATA[0] == 1 { + Err(super::JsValue::_new(GLOBAL_EXNDATA[1])) + } else { + Ok(()) + }; + GLOBAL_EXNDATA[0] = 0; + GLOBAL_EXNDATA[1] = 0; + return ret; + } + } + + /// An internal helper trait for usage in `#[wasm_bindgen]` on `async` + /// functions to convert the return value of the function to + /// `Result<JsValue, JsValue>` which is what we'll return to JS (where an + /// error is a failed future). + pub trait IntoJsResult { + fn into_js_result(self) -> Result<JsValue, JsValue>; + } + + impl IntoJsResult for () { + fn into_js_result(self) -> Result<JsValue, JsValue> { + Ok(JsValue::undefined()) + } + } + + impl<T: Into<JsValue>> IntoJsResult for T { + fn into_js_result(self) -> Result<JsValue, JsValue> { + Ok(self.into()) + } + } + + impl<T: Into<JsValue>, E: Into<JsValue>> IntoJsResult for Result<T, E> { + fn into_js_result(self) -> Result<JsValue, JsValue> { + match self { + Ok(e) => Ok(e.into()), + Err(e) => Err(e.into()), + } + } + } + + impl<E: Into<JsValue>> IntoJsResult for Result<(), E> { + fn into_js_result(self) -> Result<JsValue, JsValue> { + match self { + Ok(()) => Ok(JsValue::undefined()), + Err(e) => Err(e.into()), + } + } + } + + /// An internal helper trait for usage in `#[wasm_bindgen(start)]` + /// functions to throw the error (if it is `Err`). + pub trait Start { + fn start(self); + } + + impl Start for () { + #[inline] + fn start(self) {} + } + + impl<E: Into<JsValue>> Start for Result<(), E> { + #[inline] + fn start(self) { + if let Err(e) = self { + crate::throw_val(e.into()); + } + } + } +} + +/// A wrapper type around slices and vectors for binding the `Uint8ClampedArray` +/// array in JS. +/// +/// If you need to invoke a JS API which must take `Uint8ClampedArray` array, +/// then you can define it as taking one of these types: +/// +/// * `Clamped<&[u8]>` +/// * `Clamped<&mut [u8]>` +/// * `Clamped<Vec<u8>>` +/// +/// All of these types will show up as `Uint8ClampedArray` in JS and will have +/// different forms of ownership in Rust. +#[derive(Copy, Clone, PartialEq, Debug, Eq)] +pub struct Clamped<T>(pub T); + +impl<T> Deref for Clamped<T> { + type Target = T; + + fn deref(&self) -> &T { + &self.0 + } +} + +impl<T> DerefMut for Clamped<T> { + fn deref_mut(&mut self) -> &mut T { + &mut self.0 + } +} + +/// Convenience type for use on exported `fn() -> Result<T, JsError>` functions, where you wish to +/// throw a JavaScript `Error` object. +/// +/// You can get wasm_bindgen to throw basic errors by simply returning +/// `Err(JsError::new("message"))` from such a function. +/// +/// For more complex error handling, `JsError` implements `From<T> where T: std::error::Error` by +/// converting it to a string, so you can use it with `?`. Many Rust error types already do this, +/// and you can use [`thiserror`](https://crates.io/crates/thiserror) to derive Display +/// implementations easily or use any number of boxed error types that implement it already. +/// +/// +/// To allow JavaScript code to catch only your errors, you may wish to add a subclass of `Error` +/// in a JS module, and then implement `Into<JsValue>` directly on a type and instantiate that +/// subclass. In that case, you would not need `JsError` at all. +/// +/// ### Basic example +/// +/// ```rust,no_run +/// use wasm_bindgen::prelude::*; +/// +/// #[wasm_bindgen] +/// pub fn throwing_function() -> Result<(), JsError> { +/// Err(JsError::new("message")) +/// } +/// ``` +/// +/// ### Complex Example +/// +/// ```rust,no_run +/// use wasm_bindgen::prelude::*; +/// +/// #[derive(Debug, Clone)] +/// enum MyErrorType { +/// SomeError, +/// } +/// +/// use core::fmt; +/// impl std::error::Error for MyErrorType {} +/// impl fmt::Display for MyErrorType { +/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +/// write!(f, "display implementation becomes the error message") +/// } +/// } +/// +/// fn internal_api() -> Result<(), MyErrorType> { +/// Err(MyErrorType::SomeError) +/// } +/// +/// #[wasm_bindgen] +/// pub fn throwing_function() -> Result<(), JsError> { +/// internal_api()?; +/// Ok(()) +/// } +/// +/// ``` +#[derive(Clone)] +pub struct JsError { + value: JsValue, +} + +impl JsError { + /// Construct a JavaScript `Error` object with a string message + #[inline] + pub fn new(s: &str) -> JsError { + Self { + value: unsafe { JsValue::_new(crate::__wbindgen_error_new(s.as_ptr(), s.len())) }, + } + } +} + +if_std! { + impl<E> From<E> for JsError + where + E: std::error::Error, + { + fn from(error: E) -> Self { + JsError::new(&error.to_string()) + } + } +} + +impl From<JsError> for JsValue { + fn from(error: JsError) -> Self { + error.value + } +} |