feat: add __network/html-crawl-parse, __wasm/wasmtime-serde-demo
This commit is contained in:
29
__wasm/wasmtime-serde-demo/crates/host/src/func.rs
Normal file
29
__wasm/wasmtime-serde-demo/crates/host/src/func.rs
Normal file
@@ -0,0 +1,29 @@
|
||||
use crate::*;
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
|
||||
pub struct Func<P: serde::ser::Serialize, R: serde::de::DeserializeOwned> {
|
||||
pub(crate) wasm_fn: wasmtime::TypedFunc<u64, u64>,
|
||||
pub(crate) store: Rc<RefCell<wasmtime::Store<Option<RuntimeCaller>>>>,
|
||||
pub(crate) par: std::marker::PhantomData<P>,
|
||||
pub(crate) rtn: std::marker::PhantomData<R>,
|
||||
}
|
||||
|
||||
impl<P: serde::ser::Serialize, R: serde::de::DeserializeOwned> Func<P, R> {
|
||||
/// a more ergonomic version of the check_call function, which panic if it fails, using an analogy to an array, if checked_call were array.get(i), call would be array\[i\]
|
||||
pub fn call(&self, value: &P) -> R {
|
||||
self.checked_call(value).unwrap()
|
||||
}
|
||||
/// fail if the function in the guest panic and does not return
|
||||
pub fn checked_call(&self, value: &P) -> anyhow::Result<R> {
|
||||
let RuntimeCaller { memory, alloc_fn, .. } = self.store.borrow().data().unwrap();
|
||||
let buffer = serialize(value)?;
|
||||
let len = buffer.len() as _;
|
||||
let ptr = alloc_fn.call(&mut *self.store.borrow_mut(), len)?;
|
||||
memory.write(&mut *self.store.borrow_mut(), ptr as _, &buffer)?;
|
||||
let ptr = self.wasm_fn.call(&mut *self.store.borrow_mut(), into_bitwise(ptr, len))?;
|
||||
let (ptr, len) = from_bitwise(ptr);
|
||||
let mut buffer = vec![0u8; len as _];
|
||||
memory.read(&*self.store.borrow(), ptr as _, &mut buffer)?;
|
||||
Ok(deserialize(&buffer)?)
|
||||
}
|
||||
}
|
||||
32
__wasm/wasmtime-serde-demo/crates/host/src/lib.rs
Normal file
32
__wasm/wasmtime-serde-demo/crates/host/src/lib.rs
Normal file
@@ -0,0 +1,32 @@
|
||||
//! Simple library for serializing complex types to the wasmtime runtime using serde
|
||||
|
||||
mod func;
|
||||
mod runtime;
|
||||
|
||||
pub use bincode::{deserialize, serialize};
|
||||
pub use func::*;
|
||||
pub use runtime::*;
|
||||
pub use wasmtime_serde_host_macro::*;
|
||||
|
||||
#[inline(always)]
|
||||
const fn from_bitwise(value: u64) -> (u32, u32) {
|
||||
((value << 32 >> 32) as u32, (value >> 32) as u32)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
const fn into_bitwise(a: u32, b: u32) -> u64 {
|
||||
(a as u64) | (b as u64) << 32
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::*;
|
||||
|
||||
#[test]
|
||||
fn bitwise() {
|
||||
const DATA: (u32, u32) = (10, 20);
|
||||
const INTO: u64 = into_bitwise(DATA.0, DATA.1);
|
||||
const FROM: (u32, u32) = from_bitwise(INTO);
|
||||
assert_eq!(DATA, FROM)
|
||||
}
|
||||
}
|
||||
68
__wasm/wasmtime-serde-demo/crates/host/src/runtime.rs
Normal file
68
__wasm/wasmtime-serde-demo/crates/host/src/runtime.rs
Normal file
@@ -0,0 +1,68 @@
|
||||
use crate::*;
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
|
||||
pub struct Runtime {
|
||||
instance: wasmtime::Instance,
|
||||
store: Rc<RefCell<wasmtime::Store<Option<RuntimeCaller>>>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub(crate) struct RuntimeCaller {
|
||||
pub(crate) memory: wasmtime::Memory,
|
||||
pub(crate) alloc_fn: wasmtime::TypedFunc<u32, u32>,
|
||||
pub(crate) dealloc_fn: wasmtime::TypedFunc<u64, ()>,
|
||||
}
|
||||
|
||||
impl Runtime {
|
||||
pub fn from_file(file: impl AsRef<std::path::Path>, imports: &'static [(&'static str, fn(&[u8]) -> Vec<u8>)]) -> anyhow::Result<Self> {
|
||||
Self::new(&std::fs::read(&file)?, imports)
|
||||
}
|
||||
pub fn new(bytes: impl AsRef<[u8]>, imports: &'static [(&'static str, fn(&[u8]) -> Vec<u8>)]) -> anyhow::Result<Self> {
|
||||
let engine = wasmtime::Engine::default();
|
||||
let module = wasmtime::Module::new(&engine, bytes)?;
|
||||
let mut store = wasmtime::Store::new(&engine, None);
|
||||
let mut linker = wasmtime::Linker::new(&engine);
|
||||
for (name, callback) in imports {
|
||||
linker.func_wrap("env", name, |mut caller: wasmtime::Caller<Option<RuntimeCaller>>, ptr: u64| -> u64 {
|
||||
let RuntimeCaller {
|
||||
memory,
|
||||
alloc_fn,
|
||||
dealloc_fn,
|
||||
} = caller.data().unwrap();
|
||||
let (ptr, len) = from_bitwise(ptr);
|
||||
let mut buffer = vec![0u8; len as _];
|
||||
memory.read(&caller, ptr as _, &mut buffer).unwrap();
|
||||
dealloc_fn.call(&mut caller, into_bitwise(ptr, len)).unwrap();
|
||||
let buffer = (callback)(&buffer);
|
||||
let ptr = alloc_fn.call(&mut caller, buffer.len() as _).unwrap();
|
||||
memory.write(&mut caller, ptr as _, &buffer).unwrap();
|
||||
into_bitwise(ptr, buffer.len() as _)
|
||||
})?;
|
||||
}
|
||||
let instance = linker.instantiate(&mut store, &module)?;
|
||||
let memory = instance.get_memory(&mut store, "memory").unwrap();
|
||||
let alloc_fn = instance.get_typed_func(&mut store, "alloc")?;
|
||||
let dealloc_fn = instance.get_typed_func(&mut store, "dealloc")?;
|
||||
*store.data_mut() = Some(RuntimeCaller {
|
||||
memory,
|
||||
alloc_fn,
|
||||
dealloc_fn,
|
||||
});
|
||||
Ok(Self {
|
||||
instance,
|
||||
store: Rc::new(RefCell::new(store)),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_func<P: serde::ser::Serialize, R: serde::de::DeserializeOwned>(&self, name: &str) -> anyhow::Result<Func<P, R>> {
|
||||
let wasm_fn = self
|
||||
.instance
|
||||
.get_typed_func::<u64, u64>(&mut *self.store.borrow_mut(), &format!("_wasm_guest_{name}"))?;
|
||||
Ok(Func {
|
||||
wasm_fn,
|
||||
store: self.store.clone(),
|
||||
par: std::marker::PhantomData::<P>,
|
||||
rtn: std::marker::PhantomData::<R>,
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user