feat: add a histrical wit-bindgen
This commit is contained in:
@@ -0,0 +1,202 @@
|
||||
//! Helper library support for `async` wit functions, used for both
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::future::Future;
|
||||
use std::mem;
|
||||
use std::pin::Pin;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use std::task::*;
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
#[link(wasm_import_module = "canonical_abi")]
|
||||
extern "C" {
|
||||
pub fn async_export_done(ctx: i32, ptr: i32);
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub unsafe extern "C" fn async_export_done(_ctx: i32, _ptr: i32) {
|
||||
panic!("only supported on wasm");
|
||||
}
|
||||
|
||||
struct PollingWaker {
|
||||
state: RefCell<State>,
|
||||
}
|
||||
|
||||
enum State {
|
||||
Waiting(Pin<Box<dyn Future<Output = ()>>>),
|
||||
Polling,
|
||||
Woken,
|
||||
}
|
||||
|
||||
// These are valid for single-threaded WebAssembly because everything is
|
||||
// single-threaded and send/sync don't matter much. This module will need
|
||||
// an alternative implementation for threaded WebAssembly when that comes about
|
||||
// to host runtimes off-the-web.
|
||||
#[cfg(not(target_feature = "atomics"))]
|
||||
unsafe impl Send for PollingWaker {}
|
||||
#[cfg(not(target_feature = "atomics"))]
|
||||
unsafe impl Sync for PollingWaker {}
|
||||
|
||||
/// Runs the `future` provided to completion, polling the future whenever its
|
||||
/// waker receives a call to `wake`.
|
||||
pub fn execute(future: impl Future<Output = ()> + 'static) {
|
||||
let waker = Arc::new(PollingWaker {
|
||||
state: RefCell::new(State::Waiting(Box::pin(future))),
|
||||
});
|
||||
waker.wake()
|
||||
}
|
||||
|
||||
impl Wake for PollingWaker {
|
||||
fn wake(self: Arc<Self>) {
|
||||
let mut state = self.state.borrow_mut();
|
||||
let mut future = match mem::replace(&mut *state, State::Polling) {
|
||||
// We are the first wake to come in to wake-up this future. This
|
||||
// means that we need to actually poll the future, so leave the
|
||||
// `Polling` state in place.
|
||||
State::Waiting(future) => future,
|
||||
|
||||
// Otherwise the future is either already polling or it was already
|
||||
// woken while it was being polled, in both instances we reset the
|
||||
// state back to `Woken` and then we return. This means that the
|
||||
// future is owned by some previous stack frame and will drive the
|
||||
// future as necessary.
|
||||
State::Polling | State::Woken => {
|
||||
*state = State::Woken;
|
||||
return;
|
||||
}
|
||||
};
|
||||
drop(state);
|
||||
|
||||
// Create the futures waker/context from ourselves, used for polling.
|
||||
let waker = self.clone().into();
|
||||
let mut cx = Context::from_waker(&waker);
|
||||
loop {
|
||||
match future.as_mut().poll(&mut cx) {
|
||||
// The future is finished! By returning here we destroy the
|
||||
// future and release all of its resources.
|
||||
Poll::Ready(()) => break,
|
||||
|
||||
// The future has work yet-to-do, so continue below.
|
||||
Poll::Pending => {}
|
||||
}
|
||||
|
||||
let mut state = self.state.borrow_mut();
|
||||
match *state {
|
||||
// This means that we were not woken while we were polling and
|
||||
// the state is as it was when we took out the future before. By
|
||||
// `Pending` being returned at this point we're guaranteed that
|
||||
// our waker will be woken up at some point in the future, which
|
||||
// will come look at this future again. This means that we
|
||||
// simply store our future and return, since this call to `wake`
|
||||
// is now finished.
|
||||
State::Polling => {
|
||||
*state = State::Waiting(future);
|
||||
break;
|
||||
}
|
||||
|
||||
// This means that we received a call to `wake` while we were
|
||||
// polling. Ideally we'd enqueue some sort of microtask-tick
|
||||
// here or something like that but for now we just loop around
|
||||
// and poll again.
|
||||
State::Woken => {}
|
||||
|
||||
// This shouldn't be possible since we own the future, and no
|
||||
// one else should insert another future here.
|
||||
State::Waiting(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Oneshot<T> {
|
||||
inner: Rc<OneshotInner<T>>,
|
||||
}
|
||||
|
||||
pub struct Sender<T> {
|
||||
inner: Rc<OneshotInner<T>>,
|
||||
}
|
||||
|
||||
struct OneshotInner<T> {
|
||||
state: RefCell<OneshotState<T>>,
|
||||
}
|
||||
|
||||
enum OneshotState<T> {
|
||||
Start,
|
||||
Waiting(Waker),
|
||||
Done(T),
|
||||
}
|
||||
|
||||
impl<T> Oneshot<T> {
|
||||
/// Returns a new "oneshot" channel as well as a completion callback.
|
||||
pub fn new() -> (Oneshot<T>, Sender<T>) {
|
||||
let inner = Rc::new(OneshotInner {
|
||||
state: RefCell::new(OneshotState::Start),
|
||||
});
|
||||
(
|
||||
Oneshot {
|
||||
inner: Rc::clone(&inner),
|
||||
},
|
||||
Sender { inner },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Future for Oneshot<T> {
|
||||
type Output = T;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> {
|
||||
let mut state = self.inner.state.borrow_mut();
|
||||
match mem::replace(&mut *state, OneshotState::Start) {
|
||||
OneshotState::Done(t) => Poll::Ready(t),
|
||||
OneshotState::Waiting(_) | OneshotState::Start => {
|
||||
*state = OneshotState::Waiting(cx.waker().clone());
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Sender<T> {
|
||||
pub fn into_usize(self) -> usize {
|
||||
Rc::into_raw(self.inner) as usize
|
||||
}
|
||||
|
||||
pub unsafe fn from_usize(ptr: usize) -> Sender<T> {
|
||||
Sender {
|
||||
inner: Rc::from_raw(ptr as *const _),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send(self, val: T) {
|
||||
let mut state = self.inner.state.borrow_mut();
|
||||
let prev = mem::replace(&mut *state, OneshotState::Done(val));
|
||||
// Must `drop` before the `wake` below because waking may induce
|
||||
// polling which would induce another `borrow_mut` which would
|
||||
// conflict with this `borrow_mut` otherwise.
|
||||
drop(state);
|
||||
|
||||
match prev {
|
||||
// nothing has polled the returned future just yet, so we just
|
||||
// filled in the result of the computation. Presumably this will
|
||||
// get picked up at some point in the future.
|
||||
OneshotState::Start => {}
|
||||
|
||||
// Something was waiting for the result, so we wake the waker
|
||||
// here which, for wasm, will likely induce polling immediately.
|
||||
OneshotState::Waiting(waker) => waker.wake(),
|
||||
|
||||
// Shouldn't be possible, this is the only closure that writes
|
||||
// `Done` and this can only be invoked once.
|
||||
OneshotState::Done(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for OneshotInner<T> {
|
||||
fn drop(&mut self) {
|
||||
if let OneshotState::Waiting(waker) = &*self.state.borrow() {
|
||||
waker.wake_by_ref();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
use std::fmt;
|
||||
use std::marker;
|
||||
use std::mem;
|
||||
use std::ops::Deref;
|
||||
|
||||
#[cfg(feature = "macros")]
|
||||
pub use wit_bindgen_rust_impl::{export, import};
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
pub use async_trait::async_trait;
|
||||
#[cfg(feature = "async")]
|
||||
mod futures;
|
||||
|
||||
// Re-export `bitflags` so that we can reference it from macros.
|
||||
#[doc(hidden)]
|
||||
pub use bitflags;
|
||||
|
||||
/// A type for handles to resources that appear in exported functions.
|
||||
///
|
||||
/// This type is used as `Handle<T>` for argument types and return values of
|
||||
/// exported functions when exposing a Rust-defined resource. A `Handle<T>`
|
||||
/// represents an owned reference count on the interface-types-managed resource.
|
||||
/// It's similar to an `Rc<T>` in Rust. Internally a `Handle<T>` can provide
|
||||
/// access to `&T` when `T` is defined in the current module.
|
||||
pub struct Handle<T: HandleType> {
|
||||
val: i32,
|
||||
_marker: marker::PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: HandleType> Handle<T> {
|
||||
/// Creates a new handle around the specified value.
|
||||
///
|
||||
/// Note that the lifetime of `T` will afterwards be managed by the
|
||||
/// interface types runtime. The host may hold references to `T` that wasm
|
||||
/// isn't necessarily aware of, preventing its destruction. Nevertheless
|
||||
/// though the `Drop for T` implementation will still be run when there are
|
||||
/// no more references to `T`.
|
||||
pub fn new(val: T) -> Handle<T>
|
||||
where
|
||||
T: LocalHandle,
|
||||
{
|
||||
unsafe { Handle::from_raw(T::new(Box::into_raw(Box::new(val)) as i32)) }
|
||||
}
|
||||
|
||||
/// Consumes a handle and returns the underlying raw wasm i32 descriptor.
|
||||
///
|
||||
/// Note that this, if used improperly, will leak the resource `T`. This
|
||||
/// generally should be avoided unless you're calling raw ABI bindings and
|
||||
/// managing the lifetime manually.
|
||||
pub fn into_raw(handle: Handle<T>) -> i32 {
|
||||
let ret = handle.val;
|
||||
mem::forget(handle);
|
||||
ret
|
||||
}
|
||||
|
||||
/// Returns the raw underlying handle value for this handle.
|
||||
///
|
||||
/// This typically isn't necessary to interact with, but can be useful when
|
||||
/// interacting with raw ABI bindings.
|
||||
pub fn as_raw(handle: &Handle<T>) -> i32 {
|
||||
handle.val
|
||||
}
|
||||
|
||||
/// Unsafely assumes that the given integer descriptor is a handle for `T`.
|
||||
///
|
||||
/// This is unsafe because no validation is performed to ensure that `val`
|
||||
/// is actually a valid descriptor for `T`.
|
||||
pub unsafe fn from_raw(val: i32) -> Handle<T> {
|
||||
Handle {
|
||||
val,
|
||||
_marker: marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: LocalHandle> Deref for Handle<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
unsafe { &*(T::get(self.val) as *const T) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: LocalHandle> From<T> for Handle<T> {
|
||||
fn from(val: T) -> Handle<T> {
|
||||
Handle::new(val)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: HandleType> Clone for Handle<T> {
|
||||
fn clone(&self) -> Self {
|
||||
unsafe { Handle::from_raw(T::clone(self.val)) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: HandleType> fmt::Debug for Handle<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Handle").field("val", &self.val).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: HandleType> Drop for Handle<T> {
|
||||
fn drop(&mut self) {
|
||||
T::drop(self.val);
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait for types that can show up as the `T` in `Handle<T>`.
|
||||
///
|
||||
/// This trait is automatically synthesized for exported handles and typically
|
||||
/// shouldn't be implemented manually.
|
||||
pub unsafe trait HandleType {
|
||||
#[doc(hidden)]
|
||||
fn clone(val: i32) -> i32;
|
||||
#[doc(hidden)]
|
||||
fn drop(val: i32);
|
||||
}
|
||||
|
||||
/// An extension of the [`HandleType`] trait for locally-defined types.
|
||||
///
|
||||
/// This trait may not stick around forever...
|
||||
pub unsafe trait LocalHandle: HandleType {
|
||||
#[doc(hidden)]
|
||||
fn new(val: i32) -> i32;
|
||||
#[doc(hidden)]
|
||||
fn get(val: i32) -> i32;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub mod rt {
|
||||
use std::alloc::{self, Layout};
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
pub use crate::futures::*;
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn canonical_abi_realloc(
|
||||
old_ptr: *mut u8,
|
||||
old_len: usize,
|
||||
align: usize,
|
||||
new_len: usize,
|
||||
) -> *mut u8 {
|
||||
let layout;
|
||||
let ptr = if old_len == 0 {
|
||||
if new_len == 0 {
|
||||
return align as *mut u8;
|
||||
}
|
||||
layout = Layout::from_size_align_unchecked(new_len, align);
|
||||
alloc::alloc(layout)
|
||||
} else {
|
||||
layout = Layout::from_size_align_unchecked(old_len, align);
|
||||
alloc::realloc(old_ptr, layout, new_len)
|
||||
};
|
||||
if ptr.is_null() {
|
||||
alloc::handle_alloc_error(layout);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn canonical_abi_free(ptr: *mut u8, len: usize, align: usize) {
|
||||
if len == 0 {
|
||||
return;
|
||||
}
|
||||
let layout = Layout::from_size_align_unchecked(len, align);
|
||||
alloc::dealloc(ptr, layout);
|
||||
}
|
||||
|
||||
macro_rules! as_traits {
|
||||
($(($trait_:ident $func:ident $ty:ident <=> $($tys:ident)*))*) => ($(
|
||||
pub fn $func<T: $trait_>(t: T) -> $ty {
|
||||
t.$func()
|
||||
}
|
||||
|
||||
pub trait $trait_ {
|
||||
fn $func(self) -> $ty;
|
||||
}
|
||||
|
||||
impl<'a, T: Copy + $trait_> $trait_ for &'a T {
|
||||
fn $func(self) -> $ty{
|
||||
(*self).$func()
|
||||
}
|
||||
}
|
||||
|
||||
$(
|
||||
impl $trait_ for $tys {
|
||||
#[inline]
|
||||
fn $func(self) -> $ty {
|
||||
self as $ty
|
||||
}
|
||||
}
|
||||
)*
|
||||
|
||||
)*)
|
||||
}
|
||||
|
||||
as_traits! {
|
||||
(AsI64 as_i64 i64 <=> i64 u64)
|
||||
(AsI32 as_i32 i32 <=> i32 u32 i16 u16 i8 u8 char usize)
|
||||
(AsF32 as_f32 f32 <=> f32)
|
||||
(AsF64 as_f64 f64 <=> f64)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user