feat: add __network/html-crawl-parse, __wasm/wasmtime-serde-demo
This commit is contained in:
@@ -147,6 +147,7 @@ Project or files:
|
|||||||
│ ├── dingo
|
│ ├── dingo
|
||||||
│ ├── fetch-rs
|
│ ├── fetch-rs
|
||||||
│ ├── fuso-socks5-test
|
│ ├── fuso-socks5-test
|
||||||
|
│ ├── html-crawl-parse
|
||||||
│ ├── ip
|
│ ├── ip
|
||||||
│ ├── ipnet-demo
|
│ ├── ipnet-demo
|
||||||
│ ├── iptables
|
│ ├── iptables
|
||||||
@@ -245,6 +246,7 @@ Project or files:
|
|||||||
│ ├── wasi
|
│ ├── wasi
|
||||||
│ ├── wasm
|
│ ├── wasm
|
||||||
│ ├── wasmtime
|
│ ├── wasmtime
|
||||||
|
│ ├── wasmtime-serde-demo
|
||||||
│ └── wit-bindgen-sample
|
│ └── wit-bindgen-sample
|
||||||
├── __web
|
├── __web
|
||||||
│ ├── actix-web
|
│ ├── actix-web
|
||||||
@@ -288,6 +290,6 @@ Project or files:
|
|||||||
├── vec.rs
|
├── vec.rs
|
||||||
└── while.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