RPM build fix (reverted CI changes which will need to be un-reverted or made conditional) and vendor Rust dependencies to make builds much faster in any CI system.
This commit is contained in:
103
zeroidc/vendor/wasm-bindgen/src/cache/intern.rs
vendored
Normal file
103
zeroidc/vendor/wasm-bindgen/src/cache/intern.rs
vendored
Normal file
@@ -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);
|
||||
}
|
||||
1
zeroidc/vendor/wasm-bindgen/src/cache/mod.rs
vendored
Normal file
1
zeroidc/vendor/wasm-bindgen/src/cache/mod.rs
vendored
Normal file
@@ -0,0 +1 @@
|
||||
pub mod intern;
|
||||
160
zeroidc/vendor/wasm-bindgen/src/cast.rs
vendored
Normal file
160
zeroidc/vendor/wasm-bindgen/src/cast.rs
vendored
Normal file
@@ -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 {}
|
||||
871
zeroidc/vendor/wasm-bindgen/src/closure.rs
vendored
Normal file
871
zeroidc/vendor/wasm-bindgen/src/closure.rs
vendored
Normal file
@@ -0,0 +1,871 @@
|
||||
//! 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;
|
||||
#[cfg(feature = "nightly")]
|
||||
use std::marker::Unsize;
|
||||
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). The arguments/return value of the
|
||||
/// trait must be numbers like `u32` for now, although this restriction may be
|
||||
/// lifted in the future!
|
||||
///
|
||||
/// # 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::wrap` to wrap up a Rust closure and create
|
||||
/// // a JS closure.
|
||||
/// let cb = Closure::wrap(Box::new(|| {
|
||||
/// log("interval elapsed!");
|
||||
/// }) as Box<dyn FnMut()>);
|
||||
///
|
||||
/// // 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::wrap(Box::new(|| {
|
||||
/// web_sys::console::log_1(&"interval elapsed!".into());
|
||||
/// }) as Box<dyn FnMut()>);
|
||||
///
|
||||
/// 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,
|
||||
{
|
||||
/// A more ergonomic version of `Closure::wrap` that does the boxing and
|
||||
/// cast to trait object for you.
|
||||
///
|
||||
/// *This method requires the `nightly` feature of the `wasm-bindgen` crate
|
||||
/// to be enabled, meaning this is a nightly-only API. Users on stable
|
||||
/// should use `Closure::wrap`.*
|
||||
#[cfg(feature = "nightly")]
|
||||
pub fn new<F>(t: F) -> Closure<T>
|
||||
where
|
||||
F: Unsize<T> + 'static,
|
||||
{
|
||||
Closure::wrap(Box::new(t) as Box<T>)
|
||||
}
|
||||
|
||||
/// Creates a new instance of `Closure` from the provided boxed Rust
|
||||
/// function.
|
||||
///
|
||||
/// Note that the closure provided here, `Box<T>`, 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 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 js_sys;
|
||||
/// 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();
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
)*)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
225
zeroidc/vendor/wasm-bindgen/src/convert/closures.rs
vendored
Normal file
225
zeroidc/vendor/wasm-bindgen/src/convert/closures.rs
vendored
Normal file
@@ -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();
|
||||
}
|
||||
}
|
||||
474
zeroidc/vendor/wasm-bindgen/src/convert/impls.rs
vendored
Normal file
474
zeroidc/vendor/wasm-bindgen/src/convert/impls.rs
vendored
Normal file
@@ -0,0 +1,474 @@
|
||||
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)]
|
||||
pub struct WasmOptionalI32 {
|
||||
pub present: u32,
|
||||
pub value: i32,
|
||||
}
|
||||
|
||||
unsafe impl WasmAbi for WasmOptionalI32 {}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct WasmOptionalU32 {
|
||||
pub present: u32,
|
||||
pub value: u32,
|
||||
}
|
||||
|
||||
unsafe impl WasmAbi for WasmOptionalU32 {}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct WasmOptionalF32 {
|
||||
pub present: u32,
|
||||
pub value: f32,
|
||||
}
|
||||
|
||||
unsafe impl WasmAbi for WasmOptionalF32 {}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct WasmOptionalF64 {
|
||||
pub present: u32,
|
||||
pub value: f64,
|
||||
}
|
||||
|
||||
unsafe impl WasmAbi for WasmOptionalF64 {}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Wasm64 {
|
||||
pub low: u32,
|
||||
pub high: u32,
|
||||
}
|
||||
|
||||
unsafe impl WasmAbi for Wasm64 {}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct WasmOptional64 {
|
||||
pub present: u32,
|
||||
pub low: u32,
|
||||
pub high: u32,
|
||||
}
|
||||
|
||||
unsafe impl WasmAbi for WasmOptional64 {}
|
||||
|
||||
macro_rules! type_wasm_native {
|
||||
($($t:tt as $c:tt => $r: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 = $r;
|
||||
|
||||
#[inline]
|
||||
fn into_abi(self) -> $r {
|
||||
match self {
|
||||
None => $r {
|
||||
present: 0,
|
||||
value: 0 as $c,
|
||||
},
|
||||
Some(me) => $r {
|
||||
present: 1,
|
||||
value: me as $c,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromWasmAbi for Option<$t> {
|
||||
type Abi = $r;
|
||||
|
||||
#[inline]
|
||||
unsafe fn from_abi(js: $r) -> Self {
|
||||
if js.present == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(js.value as $t)
|
||||
}
|
||||
}
|
||||
}
|
||||
)*)
|
||||
}
|
||||
|
||||
type_wasm_native!(
|
||||
i32 as i32 => WasmOptionalI32
|
||||
isize as i32 => WasmOptionalI32
|
||||
u32 as u32 => WasmOptionalU32
|
||||
usize as u32 => WasmOptionalU32
|
||||
f32 as f32 => WasmOptionalF32
|
||||
f64 as f64 => WasmOptionalF64
|
||||
);
|
||||
|
||||
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);
|
||||
|
||||
macro_rules! type_64 {
|
||||
($($t:tt)*) => ($(
|
||||
impl IntoWasmAbi for $t {
|
||||
type Abi = Wasm64;
|
||||
|
||||
#[inline]
|
||||
fn into_abi(self) -> Wasm64 {
|
||||
Wasm64 {
|
||||
low: self as u32,
|
||||
high: (self >> 32) as u32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromWasmAbi for $t {
|
||||
type Abi = Wasm64;
|
||||
|
||||
#[inline]
|
||||
unsafe fn from_abi(js: Wasm64) -> $t {
|
||||
$t::from(js.low) | ($t::from(js.high) << 32)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoWasmAbi for Option<$t> {
|
||||
type Abi = WasmOptional64;
|
||||
|
||||
#[inline]
|
||||
fn into_abi(self) -> WasmOptional64 {
|
||||
match self {
|
||||
None => WasmOptional64 {
|
||||
present: 0,
|
||||
low: 0 as u32,
|
||||
high: 0 as u32,
|
||||
},
|
||||
Some(me) => WasmOptional64 {
|
||||
present: 1,
|
||||
low: me as u32,
|
||||
high: (me >> 32) as u32,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromWasmAbi for Option<$t> {
|
||||
type Abi = WasmOptional64;
|
||||
|
||||
#[inline]
|
||||
unsafe fn from_abi(js: WasmOptional64) -> Self {
|
||||
if js.present == 0 {
|
||||
None
|
||||
} else {
|
||||
Some($t::from(js.low) | ($t::from(js.high) << 32))
|
||||
}
|
||||
}
|
||||
}
|
||||
)*)
|
||||
}
|
||||
|
||||
type_64!(i64 u64);
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
11
zeroidc/vendor/wasm-bindgen/src/convert/mod.rs
vendored
Normal file
11
zeroidc/vendor/wasm-bindgen/src/convert/mod.rs
vendored
Normal file
@@ -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::*;
|
||||
311
zeroidc/vendor/wasm-bindgen/src/convert/slices.rs
vendored
Normal file
311
zeroidc/vendor/wasm-bindgen/src/convert/slices.rs
vendored
Normal file
@@ -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 }
|
||||
}
|
||||
}
|
||||
129
zeroidc/vendor/wasm-bindgen/src/convert/traits.rs
vendored
Normal file
129
zeroidc/vendor/wasm-bindgen/src/convert/traits.rs
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
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 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()
|
||||
}
|
||||
}
|
||||
192
zeroidc/vendor/wasm-bindgen/src/describe.rs
vendored
Normal file
192
zeroidc/vendor/wasm-bindgen/src/describe.rs
vendored
Normal file
@@ -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 `interpret.rs` in the the cli-support 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();
|
||||
}
|
||||
}
|
||||
184
zeroidc/vendor/wasm-bindgen/src/externref.rs
vendored
Normal file
184
zeroidc/vendor/wasm-bindgen/src/externref.rs
vendored
Normal file
@@ -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() {}
|
||||
1684
zeroidc/vendor/wasm-bindgen/src/lib.rs
vendored
Normal file
1684
zeroidc/vendor/wasm-bindgen/src/lib.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user