feat: add a histrical wit-bindgen
This commit is contained in:
248
__wasm/wit-bindgen-sample/wit-bindgen/crates/wasmtime/src/lib.rs
Normal file
248
__wasm/wit-bindgen-sample/wit-bindgen/crates/wasmtime/src/lib.rs
Normal file
@@ -0,0 +1,248 @@
|
||||
pub use wit_bindgen_wasmtime_impl::{export, import};
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
pub use async_trait::async_trait;
|
||||
#[cfg(feature = "tracing-lib")]
|
||||
pub use tracing_lib as tracing;
|
||||
#[doc(hidden)]
|
||||
pub use {anyhow, bitflags, wasmtime};
|
||||
|
||||
mod error;
|
||||
mod le;
|
||||
mod region;
|
||||
mod slab;
|
||||
mod table;
|
||||
|
||||
pub use error::GuestError;
|
||||
pub use le::{Endian, Le};
|
||||
pub use region::{AllBytesValid, BorrowChecker, Region};
|
||||
pub use table::*;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub mod rt {
|
||||
use crate::slab::Slab;
|
||||
use crate::{Endian, Le};
|
||||
use std::mem;
|
||||
use wasmtime::*;
|
||||
|
||||
pub trait RawMem {
|
||||
fn store<T: Endian>(&mut self, offset: i32, val: T) -> Result<(), Trap>;
|
||||
fn store_many<T: Endian>(&mut self, offset: i32, vals: &[T]) -> Result<(), Trap>;
|
||||
fn load<T: Endian>(&self, offset: i32) -> Result<T, Trap>;
|
||||
}
|
||||
|
||||
impl RawMem for [u8] {
|
||||
fn store<T: Endian>(&mut self, offset: i32, val: T) -> Result<(), Trap> {
|
||||
let mem = self
|
||||
.get_mut(offset as usize..)
|
||||
.and_then(|m| m.get_mut(..mem::size_of::<T>()))
|
||||
.ok_or_else(|| Trap::new("out of bounds write"))?;
|
||||
Le::from_slice_mut(mem)[0].set(val);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn store_many<T: Endian>(&mut self, offset: i32, val: &[T]) -> Result<(), Trap> {
|
||||
let mem = self
|
||||
.get_mut(offset as usize..)
|
||||
.and_then(|m| {
|
||||
let len = mem::size_of::<T>().checked_mul(val.len())?;
|
||||
m.get_mut(..len)
|
||||
})
|
||||
.ok_or_else(|| Trap::new("out of bounds write"))?;
|
||||
for (slot, val) in Le::from_slice_mut(mem).iter_mut().zip(val) {
|
||||
slot.set(*val);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn load<T: Endian>(&self, offset: i32) -> Result<T, Trap> {
|
||||
let mem = self
|
||||
.get(offset as usize..)
|
||||
.and_then(|m| m.get(..mem::size_of::<Le<T>>()))
|
||||
.ok_or_else(|| Trap::new("out of bounds read"))?;
|
||||
Ok(Le::from_slice(mem)[0].get())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn char_from_i32(val: i32) -> Result<char, Trap> {
|
||||
core::char::from_u32(val as u32).ok_or_else(|| Trap::new("char value out of valid range"))
|
||||
}
|
||||
|
||||
pub fn invalid_variant(name: &str) -> Trap {
|
||||
let msg = format!("invalid discriminant for `{}`", name);
|
||||
Trap::new(msg)
|
||||
}
|
||||
|
||||
pub fn validate_flags<T, U>(
|
||||
bits: T,
|
||||
all: T,
|
||||
name: &str,
|
||||
mk: impl FnOnce(T) -> U,
|
||||
) -> Result<U, Trap>
|
||||
where
|
||||
T: std::ops::Not<Output = T> + std::ops::BitAnd<Output = T> + From<u8> + PartialEq + Copy,
|
||||
{
|
||||
if bits & !all != 0u8.into() {
|
||||
let msg = format!("invalid flags specified for `{}`", name);
|
||||
Err(Trap::new(msg))
|
||||
} else {
|
||||
Ok(mk(bits))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_func<T>(caller: &mut Caller<'_, T>, func: &str) -> Result<Func, wasmtime::Trap> {
|
||||
let func = caller
|
||||
.get_export(func)
|
||||
.ok_or_else(|| {
|
||||
let msg = format!("`{}` export not available", func);
|
||||
Trap::new(msg)
|
||||
})?
|
||||
.into_func()
|
||||
.ok_or_else(|| {
|
||||
let msg = format!("`{}` export not a function", func);
|
||||
Trap::new(msg)
|
||||
})?;
|
||||
Ok(func)
|
||||
}
|
||||
|
||||
pub fn get_memory<T>(caller: &mut Caller<'_, T>, mem: &str) -> Result<Memory, wasmtime::Trap> {
|
||||
let mem = caller
|
||||
.get_export(mem)
|
||||
.ok_or_else(|| {
|
||||
let msg = format!("`{}` export not available", mem);
|
||||
Trap::new(msg)
|
||||
})?
|
||||
.into_memory()
|
||||
.ok_or_else(|| {
|
||||
let msg = format!("`{}` export not a memory", mem);
|
||||
Trap::new(msg)
|
||||
})?;
|
||||
Ok(mem)
|
||||
}
|
||||
|
||||
pub fn bad_int(_: std::num::TryFromIntError) -> Trap {
|
||||
let msg = "out-of-bounds integer conversion";
|
||||
Trap::new(msg)
|
||||
}
|
||||
|
||||
pub fn copy_slice<T: Endian>(
|
||||
store: impl AsContextMut,
|
||||
memory: &Memory,
|
||||
base: i32,
|
||||
len: i32,
|
||||
_align: i32,
|
||||
) -> Result<Vec<T>, Trap> {
|
||||
let size = (len as u32)
|
||||
.checked_mul(mem::size_of::<T>() as u32)
|
||||
.ok_or_else(|| Trap::new("array too large to fit in wasm memory"))?;
|
||||
let slice = memory
|
||||
.data(&store)
|
||||
.get(base as usize..)
|
||||
.and_then(|s| s.get(..size as usize))
|
||||
.ok_or_else(|| Trap::new("out of bounds read"))?;
|
||||
Ok(Le::from_slice(slice).iter().map(|s| s.get()).collect())
|
||||
}
|
||||
|
||||
macro_rules! as_traits {
|
||||
($(($name:ident $tr:ident $ty:ident ($($tys:ident)*)))*) => ($(
|
||||
pub fn $name<T: $tr>(t: T) -> $ty {
|
||||
t.$name()
|
||||
}
|
||||
|
||||
pub trait $tr {
|
||||
fn $name(self) -> $ty;
|
||||
}
|
||||
|
||||
impl<'a, T: Copy + $tr> $tr for &'a T {
|
||||
fn $name(self) -> $ty {
|
||||
(*self).$name()
|
||||
}
|
||||
}
|
||||
|
||||
$(
|
||||
impl $tr for $tys {
|
||||
#[inline]
|
||||
fn $name(self) -> $ty {
|
||||
self as $ty
|
||||
}
|
||||
}
|
||||
)*
|
||||
)*)
|
||||
}
|
||||
|
||||
as_traits! {
|
||||
(as_i32 AsI32 i32 (char i8 u8 i16 u16 i32 u32))
|
||||
(as_i64 AsI64 i64 (i64 u64))
|
||||
(as_f32 AsF32 f32 (f32))
|
||||
(as_f64 AsF64 f64 (f64))
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct IndexSlab {
|
||||
slab: Slab<ResourceIndex>,
|
||||
}
|
||||
|
||||
impl IndexSlab {
|
||||
pub fn insert(&mut self, resource: ResourceIndex) -> u32 {
|
||||
self.slab.insert(resource)
|
||||
}
|
||||
|
||||
pub fn get(&self, slab_idx: u32) -> Result<ResourceIndex, Trap> {
|
||||
match self.slab.get(slab_idx) {
|
||||
Some(idx) => Ok(*idx),
|
||||
None => Err(Trap::new("invalid index specified for handle")),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, slab_idx: u32) -> Result<ResourceIndex, Trap> {
|
||||
match self.slab.remove(slab_idx) {
|
||||
Some(idx) => Ok(idx),
|
||||
None => Err(Trap::new("invalid index specified for handle")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct ResourceSlab {
|
||||
slab: Slab<Resource>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Resource {
|
||||
wasm: i32,
|
||||
refcnt: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ResourceIndex(u32);
|
||||
|
||||
impl ResourceSlab {
|
||||
pub fn insert(&mut self, wasm: i32) -> ResourceIndex {
|
||||
ResourceIndex(self.slab.insert(Resource { wasm, refcnt: 1 }))
|
||||
}
|
||||
|
||||
pub fn get(&self, idx: ResourceIndex) -> i32 {
|
||||
self.slab.get(idx.0).unwrap().wasm
|
||||
}
|
||||
|
||||
pub fn clone(&mut self, idx: ResourceIndex) -> Result<(), Trap> {
|
||||
let resource = self.slab.get_mut(idx.0).unwrap();
|
||||
resource.refcnt = match resource.refcnt.checked_add(1) {
|
||||
Some(cnt) => cnt,
|
||||
None => return Err(Trap::new("resource index count overflow")),
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn drop(&mut self, idx: ResourceIndex) -> Option<i32> {
|
||||
let resource = self.slab.get_mut(idx.0).unwrap();
|
||||
assert!(resource.refcnt > 0);
|
||||
resource.refcnt -= 1;
|
||||
if resource.refcnt != 0 {
|
||||
return None;
|
||||
}
|
||||
let resource = self.slab.remove(idx.0).unwrap();
|
||||
Some(resource.wasm)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user