feat: add __network/html-crawl-parse, __wasm/wasmtime-serde-demo
This commit is contained in:
@@ -147,6 +147,7 @@ Project or files:
|
||||
│ ├── dingo
|
||||
│ ├── fetch-rs
|
||||
│ ├── fuso-socks5-test
|
||||
│ ├── html-crawl-parse
|
||||
│ ├── ip
|
||||
│ ├── ipnet-demo
|
||||
│ ├── iptables
|
||||
@@ -245,6 +246,7 @@ Project or files:
|
||||
│ ├── wasi
|
||||
│ ├── wasm
|
||||
│ ├── wasmtime
|
||||
│ ├── wasmtime-serde-demo
|
||||
│ └── wit-bindgen-sample
|
||||
├── __web
|
||||
│ ├── actix-web
|
||||
@@ -288,6 +290,6 @@ Project or files:
|
||||
├── vec.rs
|
||||
└── while.rs
|
||||
|
||||
257 directories, 40 files
|
||||
259 directories, 40 files
|
||||
```
|
||||
|
||||
|
||||
1686
__network/html-crawl-parse/Cargo.lock
generated
Normal file
1686
__network/html-crawl-parse/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
12
__network/html-crawl-parse/Cargo.toml
Normal file
12
__network/html-crawl-parse/Cargo.toml
Normal file
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "html-crawl-parse"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
base64 = "0.22.0"
|
||||
reqwest = "0.12.1"
|
||||
scraper = "0.19.0"
|
||||
tokio = { version = "1.36.0", features = ["full"] }
|
||||
33
__network/html-crawl-parse/src/main.rs
Normal file
33
__network/html-crawl-parse/src/main.rs
Normal file
@@ -0,0 +1,33 @@
|
||||
use base64::Engine;
|
||||
use base64::engine::general_purpose::STANDARD;
|
||||
use reqwest::Client;
|
||||
use scraper::{Html, Selector};
|
||||
|
||||
type StdResult = Result<(), Box<dyn std::error::Error>>;
|
||||
|
||||
// from: https://mp.weixin.qq.com/s/5kwVXFobW1OJ5lU1nn9Vkw
|
||||
#[tokio::main]
|
||||
async fn main() -> StdResult {
|
||||
let res = Client::new()
|
||||
.get(String::from_utf8(STANDARD.decode("aHR0cDovL2Jvb2tzLnRvc2NyYXBlLmNvbS8=")?)?)
|
||||
.send().await?;
|
||||
|
||||
let body = res.text().await?;
|
||||
let document = Html::parse_document(&body);
|
||||
|
||||
let book_title_selector = Selector::parse("h3 > a")?;
|
||||
|
||||
for book_title in document.select(&book_title_selector) {
|
||||
let title = book_title.text().collect::<Vec<_>>();
|
||||
println!("Title: {}", title[0]);
|
||||
}
|
||||
|
||||
let book_price_selector = Selector::parse(".price_color")?;
|
||||
|
||||
for book_price in document.select(&book_price_selector) {
|
||||
let price = book_price.text().collect::<Vec<_>>();
|
||||
println!("Price: {}", price[0]);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
16
__wasm/wasmtime-serde-demo/Cargo.toml
Normal file
16
__wasm/wasmtime-serde-demo/Cargo.toml
Normal file
@@ -0,0 +1,16 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"crates/guest",
|
||||
"crates/guest_macro",
|
||||
"crates/host",
|
||||
"crates/host_macro"
|
||||
]
|
||||
exclude = [
|
||||
"docs/examples/guest",
|
||||
"docs/examples/host"
|
||||
]
|
||||
|
||||
[profile.release]
|
||||
opt-level = "z"
|
||||
lto = true
|
||||
strip = true
|
||||
21
__wasm/wasmtime-serde-demo/LICENSE-MIT
Normal file
21
__wasm/wasmtime-serde-demo/LICENSE-MIT
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Heraclito-Q-Saldanha
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
1
__wasm/wasmtime-serde-demo/README.md
Normal file
1
__wasm/wasmtime-serde-demo/README.md
Normal file
@@ -0,0 +1 @@
|
||||
see https://github.com/Heraclito-Q-Saldanha/wasmtime_serde
|
||||
24
__wasm/wasmtime-serde-demo/UNLICENSE
Normal file
24
__wasm/wasmtime-serde-demo/UNLICENSE
Normal file
@@ -0,0 +1,24 @@
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <http://unlicense.org/>
|
||||
13
__wasm/wasmtime-serde-demo/crates/guest/Cargo.toml
Normal file
13
__wasm/wasmtime-serde-demo/crates/guest/Cargo.toml
Normal file
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "wasmtime_serde_guest"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license = "Unlicense OR MIT"
|
||||
authors = ["Heráclito <heraclitoqsaldanha@gmail.com>"]
|
||||
description = "Simple library for serializing complex types to the wasmtime runtime using serde"
|
||||
repository = "https://github.com/Heraclito-Q-Saldanha/wasmtime_serde"
|
||||
|
||||
[dependencies]
|
||||
serde = "1.0.163"
|
||||
bincode = "1.3.3"
|
||||
wasmtime_serde_guest_macro = "0.1.0"
|
||||
60
__wasm/wasmtime-serde-demo/crates/guest/src/lib.rs
Normal file
60
__wasm/wasmtime-serde-demo/crates/guest/src/lib.rs
Normal file
@@ -0,0 +1,60 @@
|
||||
//! Simple library for serializing complex types to the wasmtime runtime using serde
|
||||
|
||||
pub use bincode::{deserialize, serialize};
|
||||
pub use wasmtime_serde_guest_macro::*;
|
||||
|
||||
#[inline]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn alloc(len: u32) -> *mut u8 {
|
||||
let mut buf = Vec::with_capacity(len as _);
|
||||
let ptr = buf.as_mut_ptr();
|
||||
std::mem::forget(buf);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dealloc(value: u64) {
|
||||
let (ptr, len) = from_bitwise(value);
|
||||
let ptr = std::mem::transmute::<usize, *mut u8>(ptr as _);
|
||||
let buffer = Vec::from_raw_parts(ptr, len as _, len as _);
|
||||
std::mem::drop(buffer);
|
||||
}
|
||||
|
||||
pub fn write_msg<T: serde::ser::Serialize>(value: &T) -> u64 {
|
||||
let mut buffer = bincode::serialize(value).unwrap();
|
||||
let len = buffer.len();
|
||||
let ptr = buffer.as_mut_ptr();
|
||||
std::mem::forget(buffer);
|
||||
into_bitwise(ptr as _, len as _)
|
||||
}
|
||||
|
||||
pub unsafe fn read_msg<T: serde::de::DeserializeOwned>(value: u64) -> T {
|
||||
let (ptr, len) = from_bitwise(value);
|
||||
let ptr = std::mem::transmute::<usize, *mut u8>(ptr as _);
|
||||
let buffer = Vec::from_raw_parts(ptr, len as _, len as _);
|
||||
bincode::deserialize(&buffer).unwrap()
|
||||
}
|
||||
|
||||
#[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)
|
||||
}
|
||||
}
|
||||
15
__wasm/wasmtime-serde-demo/crates/guest_macro/Cargo.toml
Normal file
15
__wasm/wasmtime-serde-demo/crates/guest_macro/Cargo.toml
Normal file
@@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "wasmtime_serde_guest_macro"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license = "Unlicense OR MIT"
|
||||
authors = ["Heráclito <heraclitoqsaldanha@gmail.com>"]
|
||||
description = "Simple library for serializing complex types to the wasmtime runtime using serde"
|
||||
repository = "https://github.com/Heraclito-Q-Saldanha/wasmtime_serde"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
syn = {version = "2.0.18", features = ["full"] }
|
||||
quote = "1.0.28"
|
||||
89
__wasm/wasmtime-serde-demo/crates/guest_macro/src/lib.rs
Normal file
89
__wasm/wasmtime-serde-demo/crates/guest_macro/src/lib.rs
Normal file
@@ -0,0 +1,89 @@
|
||||
//! Simple library for serializing complex types to the wasmtime runtime using serde
|
||||
|
||||
use quote::quote;
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn export_fn(_attr: proc_macro::TokenStream, item: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let data = syn::parse_macro_input!(item as syn::ItemFn);
|
||||
let name = &data.sig.ident;
|
||||
let extern_name = quote::format_ident!("_wasm_guest_{}", name);
|
||||
let gen = {
|
||||
let mut argument_types = quote!();
|
||||
let mut call = quote!();
|
||||
for (i, arg) in data.sig.inputs.iter().enumerate() {
|
||||
let i = syn::Index::from(i);
|
||||
call = quote!(#call message.#i,);
|
||||
if let syn::FnArg::Typed(t) = arg {
|
||||
let ty = &t.ty;
|
||||
argument_types = quote!(#argument_types #ty,);
|
||||
} else {
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
argument_types = quote! { (#argument_types) };
|
||||
quote! {
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn #extern_name(value: u64) -> u64 {
|
||||
let message:#argument_types = wasmtime_serde_guest::read_msg(value);
|
||||
wasmtime_serde_guest::write_msg(&#name(#call))
|
||||
}
|
||||
}
|
||||
};
|
||||
quote!(#gen #data).into()
|
||||
}
|
||||
|
||||
struct FnImports {
|
||||
functions: Vec<syn::Signature>,
|
||||
}
|
||||
|
||||
impl syn::parse::Parse for FnImports {
|
||||
fn parse(input: syn::parse::ParseStream) -> syn::parse::Result<Self> {
|
||||
let mut functions = vec![];
|
||||
while let Ok(f) = input.parse::<syn::Signature>() {
|
||||
functions.push(f);
|
||||
input.parse::<syn::Token![;]>()?;
|
||||
}
|
||||
Ok(FnImports { functions })
|
||||
}
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn import_fn(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let mut remote_fns = quote!();
|
||||
let mut local_fns = quote!();
|
||||
let data = syn::parse_macro_input!(input as FnImports);
|
||||
for f in data.functions.iter().cloned() {
|
||||
let remote_name = quote::format_ident!("_wasm_host_{}", f.ident);
|
||||
let mut inputs = quote!();
|
||||
for item in &f.inputs {
|
||||
if let syn::FnArg::Typed(syn::PatType { pat: p, .. }) = item {
|
||||
if let syn::Pat::Ident(i) = p.as_ref() {
|
||||
inputs = quote!(#inputs #i,);
|
||||
} else {
|
||||
panic!()
|
||||
}
|
||||
} else {
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
inputs = quote!((#inputs));
|
||||
local_fns = quote!(
|
||||
#local_fns
|
||||
#f {
|
||||
let ptr = wasmtime_serde_guest::write_msg(&#inputs);
|
||||
unsafe{wasmtime_serde_guest::read_msg(#remote_name(ptr))}
|
||||
}
|
||||
);
|
||||
remote_fns = quote!(
|
||||
#remote_fns
|
||||
fn #remote_name(ptr: u64) -> u64;
|
||||
);
|
||||
}
|
||||
quote! {
|
||||
#local_fns
|
||||
extern "C" {
|
||||
#remote_fns
|
||||
}
|
||||
}
|
||||
.into()
|
||||
}
|
||||
15
__wasm/wasmtime-serde-demo/crates/host/Cargo.toml
Normal file
15
__wasm/wasmtime-serde-demo/crates/host/Cargo.toml
Normal file
@@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "wasmtime_serde_host"
|
||||
version = "0.1.3"
|
||||
edition = "2021"
|
||||
license = "Unlicense OR MIT"
|
||||
authors = ["Heráclito <heraclitoqsaldanha@gmail.com>"]
|
||||
description = "Simple library for serializing complex types to the wasmtime runtime using serde"
|
||||
repository = "https://github.com/Heraclito-Q-Saldanha/wasmtime_serde"
|
||||
|
||||
[dependencies]
|
||||
wasmtime_serde_host_macro = "0.1.0"
|
||||
wasmtime = {version = "9.0.2", default-features = false, features = ["cranelift"]}
|
||||
serde = "1.0.163"
|
||||
bincode = "1.3.3"
|
||||
anyhow = "1.0.71"
|
||||
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>,
|
||||
})
|
||||
}
|
||||
}
|
||||
BIN
__wasm/wasmtime-serde-demo/crates/host/tests/guest.wasm
Executable file
BIN
__wasm/wasmtime-serde-demo/crates/host/tests/guest.wasm
Executable file
Binary file not shown.
32
__wasm/wasmtime-serde-demo/crates/host/tests/runtime.rs
Normal file
32
__wasm/wasmtime-serde-demo/crates/host/tests/runtime.rs
Normal file
@@ -0,0 +1,32 @@
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use wasmtime_serde_host::*;
|
||||
const GUEST_DATA: &[u8] = include_bytes!("guest.wasm");
|
||||
|
||||
#[test]
|
||||
fn load_runtime() {
|
||||
assert!(Runtime::new(GUEST_DATA, &[]).is_ok())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_func() {
|
||||
let runtime = Runtime::new(GUEST_DATA, &[]).unwrap();
|
||||
assert!(runtime.get_func::<(i32, i32), i32>("add").is_ok())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn call() {
|
||||
let runtime = Runtime::new(GUEST_DATA, &[]).unwrap();
|
||||
let add_fn = runtime.get_func::<(i32, i32), i32>("add").unwrap();
|
||||
let result = add_fn.call(&(10, 10));
|
||||
assert_eq!(result, 20)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn checked_call() {
|
||||
let runtime = Runtime::new(GUEST_DATA, &[]).unwrap();
|
||||
let panic_fn = runtime.get_func::<(), ()>("panic").unwrap();
|
||||
let result = panic_fn.checked_call(&());
|
||||
assert!(result.is_err())
|
||||
}
|
||||
}
|
||||
16
__wasm/wasmtime-serde-demo/crates/host_macro/Cargo.toml
Normal file
16
__wasm/wasmtime-serde-demo/crates/host_macro/Cargo.toml
Normal file
@@ -0,0 +1,16 @@
|
||||
[package]
|
||||
name = "wasmtime_serde_host_macro"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license = "Unlicense OR MIT"
|
||||
authors = ["Heráclito <heraclitoqsaldanha@gmail.com>"]
|
||||
description = "Simple library for serializing complex types to the wasmtime runtime using serde"
|
||||
repository = "https://github.com/Heraclito-Q-Saldanha/wasmtime_serde"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
syn = {version = "2.0.18", features = ["full"] }
|
||||
proc-macro2 = "1.0.59"
|
||||
quote = "1.0.28"
|
||||
70
__wasm/wasmtime-serde-demo/crates/host_macro/src/lib.rs
Normal file
70
__wasm/wasmtime-serde-demo/crates/host_macro/src/lib.rs
Normal file
@@ -0,0 +1,70 @@
|
||||
//! Simple library for serializing complex types to the wasmtime runtime using serde
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
use syn::{parse_macro_input, ItemFn};
|
||||
|
||||
struct FnHost {
|
||||
functions: Vec<syn::Ident>,
|
||||
}
|
||||
|
||||
impl syn::parse::Parse for FnHost {
|
||||
fn parse(input: syn::parse::ParseStream) -> syn::parse::Result<Self> {
|
||||
let mut functions = vec![];
|
||||
let mut end = false;
|
||||
while let Ok(f) = input.parse::<syn::Ident>() {
|
||||
if end {
|
||||
panic!("comma")
|
||||
}
|
||||
functions.push(f);
|
||||
end = input.parse::<syn::Token![,]>().is_err();
|
||||
}
|
||||
Ok(Self { functions })
|
||||
}
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn host_funcs(input: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(input as FnHost);
|
||||
let mut list = quote!();
|
||||
let len = input.functions.len();
|
||||
for name in input.functions {
|
||||
let name = format_ident!("_wasm_host_{}", name);
|
||||
let str_name: proc_macro2::TokenStream = format!(r#""{name}""#).parse().unwrap();
|
||||
list = quote!(#list (#str_name, #name),);
|
||||
}
|
||||
quote!({
|
||||
const HOST_FUNC:[(&str, fn(&[u8]) -> Vec<u8>);#len] = [#list];
|
||||
&HOST_FUNC
|
||||
})
|
||||
.into()
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn export_fn(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let data = parse_macro_input!(item as ItemFn);
|
||||
let name = &data.sig.ident;
|
||||
let extern_name = format_ident!("_wasm_host_{}", name);
|
||||
let gen = {
|
||||
let mut argument_types = quote!();
|
||||
let mut call = quote!();
|
||||
for (i, arg) in data.sig.inputs.iter().enumerate() {
|
||||
let i = syn::Index::from(i);
|
||||
call = quote!(#call message.#i,);
|
||||
if let syn::FnArg::Typed(t) = arg {
|
||||
let ty = &t.ty;
|
||||
argument_types = quote!(#argument_types #ty,);
|
||||
} else {
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
argument_types = quote! { (#argument_types) };
|
||||
quote! {
|
||||
fn #extern_name(value: &[u8]) -> Vec<u8> {
|
||||
let message:#argument_types = wasmtime_serde_host::deserialize(value).unwrap();
|
||||
wasmtime_serde_host::serialize(&#name(#call)).unwrap()
|
||||
}
|
||||
}
|
||||
};
|
||||
quote!(#gen #data).into()
|
||||
}
|
||||
29
__wasm/wasmtime-serde-demo/docs/README.md
Normal file
29
__wasm/wasmtime-serde-demo/docs/README.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# wasmtime serde
|
||||
Simple library for serializing complex types to the wasmtime runtime using serde
|
||||
|
||||
### using
|
||||
|
||||
```Rust
|
||||
// guest
|
||||
use wasmtime_serde_guest::*;
|
||||
|
||||
#[export_fn]
|
||||
fn add(a: i32, b: i32) -> i32 {
|
||||
a + b
|
||||
}
|
||||
|
||||
// host
|
||||
use wasmtime_serde_host::*;
|
||||
|
||||
fn main(){
|
||||
let runtime = Runtime::from_file("file.wasm", &[]).unwrap();
|
||||
let add_fn = runtime.get_func::<(i32, i32), i32>("add").unwrap();
|
||||
let result = add_fn.call(&(1, 2));
|
||||
println!("{result}");
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
See the [example code](examples)
|
||||
|
||||
Dual-licensed under [MIT](../LICENSE-MIT) or the [UNLICENSE](../UNLICENSE).
|
||||
17
__wasm/wasmtime-serde-demo/docs/examples/README.md
Normal file
17
__wasm/wasmtime-serde-demo/docs/examples/README.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# examples
|
||||
|
||||
add wasm target
|
||||
|
||||
```
|
||||
rustup target add wasm32-unknown-unknown
|
||||
```
|
||||
|
||||
compile guest
|
||||
```
|
||||
(cd guest; cargo build)
|
||||
```
|
||||
|
||||
compile and run host
|
||||
```
|
||||
(cd host; cargo run)
|
||||
```
|
||||
@@ -0,0 +1,2 @@
|
||||
[build]
|
||||
target = "wasm32-unknown-unknown"
|
||||
105
__wasm/wasmtime-serde-demo/docs/examples/guest/Cargo.lock
generated
Normal file
105
__wasm/wasmtime-serde-demo/docs/examples/guest/Cargo.lock
generated
Normal file
@@ -0,0 +1,105 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "guest"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"wasmtime_serde_guest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.197"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.197"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.55",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "wasmtime_serde_guest"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"serde",
|
||||
"wasmtime_serde_guest_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmtime_serde_guest_macro"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc93afb7801ed4f05fb2dc4b95c38ed65b65239b1088772e9cf609296d27b909"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
17
__wasm/wasmtime-serde-demo/docs/examples/guest/Cargo.toml
Normal file
17
__wasm/wasmtime-serde-demo/docs/examples/guest/Cargo.toml
Normal file
@@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "guest"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license = "Unlicense OR MIT"
|
||||
|
||||
[lib]
|
||||
crate-type = ['cdylib']
|
||||
|
||||
[dependencies]
|
||||
wasmtime_serde_guest = {path = "../../../crates/guest"}
|
||||
serde = {version = "1.0.159", features = ["derive"]}
|
||||
|
||||
[profile.release]
|
||||
opt-level = "z"
|
||||
lto = true
|
||||
strip = true
|
||||
20
__wasm/wasmtime-serde-demo/docs/examples/guest/src/lib.rs
Normal file
20
__wasm/wasmtime-serde-demo/docs/examples/guest/src/lib.rs
Normal file
@@ -0,0 +1,20 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use wasmtime_serde_guest::*;
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
struct Human {
|
||||
name: String,
|
||||
age: u8,
|
||||
}
|
||||
|
||||
#[export_fn]
|
||||
fn add(a: i32, b: i32) -> i32 {
|
||||
let human = get_human();
|
||||
println(format!("{human:?}"));
|
||||
a + b
|
||||
}
|
||||
|
||||
import_fn!(
|
||||
fn get_human() -> Human;
|
||||
fn println(msg: String);
|
||||
);
|
||||
1102
__wasm/wasmtime-serde-demo/docs/examples/host/Cargo.lock
generated
Normal file
1102
__wasm/wasmtime-serde-demo/docs/examples/host/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
14
__wasm/wasmtime-serde-demo/docs/examples/host/Cargo.toml
Normal file
14
__wasm/wasmtime-serde-demo/docs/examples/host/Cargo.toml
Normal file
@@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "host"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license = "Unlicense OR MIT"
|
||||
|
||||
[dependencies]
|
||||
wasmtime_serde_host = {path = "../../../crates/host"}
|
||||
serde = {version = "1.0.159", features = ["derive"]}
|
||||
|
||||
[profile.release]
|
||||
opt-level = "z"
|
||||
lto = true
|
||||
strip = true
|
||||
29
__wasm/wasmtime-serde-demo/docs/examples/host/src/main.rs
Normal file
29
__wasm/wasmtime-serde-demo/docs/examples/host/src/main.rs
Normal file
@@ -0,0 +1,29 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use wasmtime_serde_host::*;
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
struct Human {
|
||||
name: String,
|
||||
age: u8,
|
||||
}
|
||||
|
||||
#[export_fn]
|
||||
fn get_human() -> Human {
|
||||
Human {
|
||||
name: "Ferros".to_string(),
|
||||
age: 192,
|
||||
}
|
||||
}
|
||||
|
||||
#[export_fn]
|
||||
fn println(msg: String) {
|
||||
println!("{msg}")
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let host_fns = host_funcs![println, get_human];
|
||||
let runtime = Runtime::from_file("../guest/target/wasm32-unknown-unknown/debug/guest.wasm", host_fns).unwrap();
|
||||
let add_fn = runtime.get_func::<(i32, i32), i32>("add").unwrap();
|
||||
let result = add_fn.call(&(1, 2));
|
||||
println!("{result}");
|
||||
}
|
||||
4
__wasm/wasmtime-serde-demo/rustfmt.toml
Normal file
4
__wasm/wasmtime-serde-demo/rustfmt.toml
Normal file
@@ -0,0 +1,4 @@
|
||||
use_field_init_shorthand = true
|
||||
newline_style = "Unix"
|
||||
hard_tabs = true
|
||||
max_width = 150
|
||||
Reference in New Issue
Block a user