use std::collections::HashMap;
use wasmtime::component::bindgen;
use wasmtime::component::{Component, Linker, ResourceTable};
use wasmtime::component::{HasSelf, Resource};
use wasmtime::{Engine, Result, Store};
use wasmtime_wasi::p2::add_to_linker_async;
use wasmtime_wasi::{WasiCtx, WasiCtxView, WasiView};
pub struct ComponentRunStates {
pub wasi_ctx: WasiCtx,
pub resource_table: ResourceTable,
}
impl WasiView for ComponentRunStates {
fn ctx(&mut self) -> WasiCtxView<'_> {
WasiCtxView {
ctx: &mut self.wasi_ctx,
table: &mut self.resource_table,
}
}
}
impl ComponentRunStates {
pub fn new() -> Self {
ComponentRunStates {
wasi_ctx: WasiCtx::builder().build(),
resource_table: ResourceTable::new(),
}
}
}
bindgen!({
path: "./examples/resource-component/kv-store.wit",
world: "kv-database",
imports: { default: async | trappable },
exports: { default: async },
with: {
"example:kv-store/kvdb.connection": Connection
},
});
pub struct Connection {
pub storage: HashMap<String, String>,
}
impl KvDatabaseImports for ComponentRunStates {
async fn log(&mut self, msg: String) -> Result<(), wasmtime::Error> {
println!("Log: {msg}");
Ok(())
}
}
impl example::kv_store::kvdb::Host for ComponentRunStates {}
impl example::kv_store::kvdb::HostConnection for ComponentRunStates {
async fn new(&mut self) -> Result<Resource<Connection>, wasmtime::Error> {
Ok(self.resource_table.push(Connection {
storage: HashMap::new(),
})?)
}
async fn get(
&mut self,
resource: Resource<Connection>,
key: String,
) -> Result<Option<String>, wasmtime::Error> {
let connection = self.resource_table.get(&resource)?;
Ok(connection.storage.get(&key).cloned())
}
async fn set(
&mut self,
resource: Resource<Connection>,
key: String,
value: String,
) -> Result<()> {
let connection = self.resource_table.get_mut(&resource)?;
connection.storage.insert(key, value);
Ok(())
}
async fn remove(
&mut self,
resource: Resource<Connection>,
key: String,
) -> Result<Option<String>> {
let connection = self.resource_table.get_mut(&resource)?;
Ok(connection.storage.remove(&key))
}
async fn clear(&mut self, resource: Resource<Connection>) -> Result<(), wasmtime::Error> {
let large_string = self.resource_table.get_mut(&resource)?;
large_string.storage.clear();
Ok(())
}
async fn drop(&mut self, resource: Resource<Connection>) -> Result<()> {
let _ = self.resource_table.delete(resource)?;
Ok(())
}
}
#[tokio::main]
async fn main() -> Result<()> {
let engine = Engine::default();
let mut linker = Linker::new(&engine);
let state = ComponentRunStates::new();
let mut store = Store::new(&engine, state);
KvDatabase::add_to_linker::<_, HasSelf<_>>(&mut linker, |s| s)?;
add_to_linker_async(&mut linker)?;
let component = Component::from_file(&engine, "target/wasm32-wasip2/debug/guest_kvdb.wasm")?;
let bindings = KvDatabase::instantiate_async(&mut store, &component, &linker).await?;
let result = bindings
.call_replace_value(&mut store, "hello", "world")
.await?;
assert_eq!(result, None);
let result = bindings
.call_replace_value(&mut store, "hello", "wasmtime")
.await?;
assert_eq!(result, Some("world".to_string()));
Ok(())
}