Stream: git-wasmtime

Topic: wasmtime / issue #9017 `wasi_snapshot_preview1::fd_write...


view this post on Zulip Wasmtime GitHub notifications bot (Jul 26 2024 at 10:25):

itachaaa opened issue #9017:

I know that there are some wasi_snapshot_preview1::fd_write related descriptions in the recent issue: 8521, 7697, and I added add_to_linker_sync in my code. However, the type does not match and the compilation fails. Here are the details,I want to implement a small program that calls the cache interface in wasm.

Running it directly throws an exception like this:

thread 'main' panicked at src/main.rs:62:67:
called `Result::unwrap()` on an `Err` value: unknown import: `wasi_snapshot_preview1::fd_write` has not been defined
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

When I added add_to_linker_sync the compile Error:

error[E0308]: mismatched types
   --> src/main.rs:62:39
    |
62  |     wasmtime_wasi::add_to_linker_sync(&mut linker).unwrap();
    |     --------------------------------- ^^^^^^^^^^^ expected `&mut Linker<_>`, found `&mut Linker<Arc<Mutex<KvStore>>>`
    |     |
    |     arguments to this function are incorrect
    |
    = note: expected mutable reference `&mut wasmtime::component::Linker<_>`
               found mutable reference `&mut wasmtime::Linker<Arc<Mutex<KvStore>>>`

wasm_runner:

use wasmtime::*;
use kv_store::{create_kv_store, SharedKvStore};

fn main() {
    let mut config = Config::new();
    Config::async_support(&mut config, false);
    config.wasm_backtrace_details(WasmBacktraceDetails::Enable);
    config.wasm_component_model(true);
    let engine = Engine::new(&config).unwrap();
    let kv_store = create_kv_store();
    let mut store = Store::new(&engine, kv_store.clone());

    // Load the WebAssembly module
    // let caller_wasm = fs::read("../caller/target/wasm32-wasi/release/caller.wasm").unwrap();
    let caller_module = Module::from_file(&engine, "../caller/target/wasm32-wasi/release/caller.wasm").unwrap();

    // Create a new Linker to link WASI functions
    let mut linker = Linker::new(&engine);

    // Register the `get` function
    linker.func_wrap("env", "kv_get", move |mut caller: Caller<'_, SharedKvStore>, ptr: i32, len: i32, result_ptr: i32| -> i32 {
        let memory = caller.get_export("memory").unwrap().into_memory().unwrap();
        let data = memory.data(&caller);

        // Immutable access to memory to read key
        let key = &data[ptr as usize..(ptr + len) as usize];
        let key_str = std::str::from_utf8(key).unwrap();

        // Perform lookup in the shared KV store
        let value_opt = caller.data().lock().unwrap().get(key_str);

        // Mutable access to memory to write result
        let data_mut = memory.data_mut(&mut caller);
        if let Some(value) = value_opt {
            let value_bytes = value.as_bytes();
            let result_slice = &mut data_mut[result_ptr as usize..(result_ptr as usize + value_bytes.len())];
            result_slice.copy_from_slice(value_bytes);
            value_bytes.len() as i32
        } else {
            -1
        }
    }).unwrap();

    // Register the `set` function
    linker.func_wrap("env", "kv_set", move |mut caller: Caller<'_, SharedKvStore>, key_ptr: i32, key_len: i32, value_ptr: i32, value_len: i32| {
        let memory = caller.get_export("memory").unwrap().into_memory().unwrap();
        let data = memory.data(&caller);

        // Immutable access to memory to read key and value
        let key = &data[key_ptr as usize..(key_ptr + key_len) as usize];
        let value = &data[value_ptr as usize..(value_ptr + value_len) as usize];

        let key_str = std::str::from_utf8(key).unwrap();
        let value_str = std::str::from_utf8(value).unwrap();

        // Perform write operation in the shared KV store
        caller.data().lock().unwrap().set(key_str, value_str);
    })
        .unwrap();

    // Instantiate the module
    // wasmtime_wasi::add_to_linker_sync(&mut linker).unwrap();
    let instance = linker.instantiate(&mut store, &caller_module).unwrap();

    // Call WebAssembly functions
    let set_key_value = instance.get_func(&mut store, "set_key_value").unwrap().typed::<(i32, i32), ()>(&store).unwrap();
    set_key_value.call(&mut store, (0, 0)).unwrap();

    let get_key_value = instance.get_func(&mut store, "get_key_value").unwrap().typed::<i32, i32>(&store).unwrap();
    let result = get_key_value.call(&mut store, 0).unwrap();
    println!("Got value from KV store: {}", result);
}
[package]
name = "wasm_runner"
version = "0.1.0"
edition = "2021"

[dependencies]
wasmtime = "23.0.1"
wasmtime-wasi = "23.0.1"
kv_store = { path = "../kv_store" }

caller:

extern "C" {
    pub fn kv_get(ptr: *const u8, len: usize, result_ptr: *mut u8) -> i32;
    pub fn kv_set(key_ptr: *const u8, key_len: usize, value_ptr: *const u8, value_len: usize);
}

#[no_mangle]
pub unsafe fn set_key_value(key: &str, value: &str) {
    unsafe {
        kv_set(key.as_ptr(), key.len(), value.as_ptr(), value.len());
    }
}

#[no_mangle]
pub unsafe fn get_key_value(key: &str) -> Option<String> {
    let mut result = vec![0u8; 100]; // 假设结果长度不会超过100字节
    let result_ptr = result.as_mut_ptr();
    let len = unsafe { kv_get(key.as_ptr(), key.len(), result_ptr) };

    if len >= 0 {
        Some(String::from_utf8(result[..len as usize].to_vec()).unwrap())
    } else {
        None
    }
}
[package]
name = "caller"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]
use std::collections::HashMap;
use std::sync::{Arc, Mutex};

pub struct KvStore {
    map: HashMap<String, String>,
}

impl KvStore {
    pub fn new() -> Self {
        KvStore {
            map: HashMap::new(),
        }
    }

    pub fn get(&self, key: &str) -> Option<String> {
        self.map.get(key).cloned()
    }

    pub fn set(&mut self, key: &str, value: &str) {
        self.map.insert(key.to_string(), value.to_string());
    }
}

pub type SharedKvStore = Arc<Mutex<KvStore>>;

pub fn create_kv_store() -> SharedKvStore {
    Arc::new(Mutex::new(KvStore::new()))
}

view this post on Zulip Wasmtime GitHub notifications bot (Jul 26 2024 at 17:25):

alexcrichton commented on issue #9017:

You're currently working at the core wasm abstraction layer, not the component layer, meaning you want the preview1 module.

Even with that though your code contains:

#[no_mangle]
pub unsafe fn set_key_value(key: &str, value: &str) {
   ...
}

which is unlikely to be what you want.

I'd recommend reading over examples/documentation about passing strings into WebAssembly and possible reading up on the component model which would enable that use case more cleanly

view this post on Zulip Wasmtime GitHub notifications bot (Jul 27 2024 at 07:33):

itachaaa commented on issue #9017:

You're currently working at the core wasm abstraction layer, not the component layer, meaning you want the preview1 module.您目前使用的是核心 wasm 抽象层,而不是组件层,这意味着您需要 preview1 模块。

Even with that though your code contains:即便如此,您的代码中仍包含

#[no_mangle] pub unsafe fn set_key_value(key: &str, value: &str) { ... }

which is unlikely to be what you want.这不可能是你想要的。

I'd recommend reading over examples/documentation about passing strings into WebAssembly and possible reading up on the component model which would enable that use case more cleanly我建议你阅读有关向 WebAssembly 传递字符串的示例/文档,并在可能的情况下阅读有关组件模型的内容,这样就能更简洁地实现该用例。

Thanks,it helps a lot about params passing. I changed my code, however, wasi_snapshot_preview1::fd_write has not been defined` still happed.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 27 2024 at 07:34):

itachaaa edited a comment on issue #9017:

You're currently working at the core wasm abstraction layer, not the component layer, meaning you want the preview1 module.您目前使用的是核心 wasm 抽象层,而不是组件层,这意味着您需要 preview1 模块。

Even with that though your code contains:即便如此,您的代码中仍包含

#[no_mangle] pub unsafe fn set_key_value(key: &str, value: &str) { ... }

which is unlikely to be what you want.这不可能是你想要的。

I'd recommend reading over examples/documentation about passing strings into WebAssembly and possible reading up on the component model which would enable that use case more cleanly我建议你阅读有关向 WebAssembly 传递字符串的示例/文档,并在可能的情况下阅读有关组件模型的内容,这样就能更简洁地实现该用例。

Thanks,it helps a lot about params passing. I changed my code, however, wasi_snapshot_preview1::fd_write has not been defined` still happed.

changed caller code:

extern "C" {
    pub fn kv_get(ptr: *const u8, len: i32, result_ptr: i32) -> i32;
    pub fn kv_set(key_ptr: *const u8, key_len: i32, value_ptr: *const u8, value_len: i32);
}

#[no_mangle]
pub unsafe fn set_key_value() {
    unsafe {
        kv_set(KEY.as_ptr(), KEY.len() as i32, VALUE.as_ptr(), VALUE.len() as i32);
    }
}

#[no_mangle]
pub unsafe fn get_key_value() {
    let mut result = vec![0u8; 100]; // 假设结果长度不会超过100字节
    let result_ptr = result.as_mut_ptr();
    let len  = unsafe { kv_get(KEY.as_ptr(), KEY.len() as i32, result_ptr as i32) };
    if len > 0 {
        println!("got value: {}", String::from_utf8(result[..len as usize].to_vec()).unwrap());
    } else {
        println!("failed get value.");    }
}

static KEY: &str = "Name";
static VALUE: &str = "World";

changed main code:

use wasmtime::*;
use kv_store::{create_kv_store, SharedKvStore};

fn main() {
    let mut config = Config::new();
    Config::async_support(&mut config, false);
    config.wasm_backtrace_details(WasmBacktraceDetails::Enable);
    config.wasm_component_model(true);
    let engine = Engine::new(&config).unwrap();
    let kv_store = create_kv_store();
    let mut store = Store::new(&engine, kv_store.clone());

    // Load the WebAssembly module
    let caller_module = Module::from_file(&engine, "../caller/target/wasm32-wasi/release/caller.wasm").unwrap();

    // Create a new Linker to link WASI functions
    let mut linker = Linker::new(&engine);

    // Register the `get` function
    linker.func_wrap("env", "kv_get", move |mut caller: Caller<'_, SharedKvStore>, ptr: i32, len: i32, result_ptr: i32| -> i32 {
        let memory = caller.get_export("memory").unwrap().into_memory().unwrap();
        let data = memory.data(&caller);

        // Immutable access to memory to read key
        let key = &data[ptr as usize..(ptr + len) as usize];
        let key_str = std::str::from_utf8(key).unwrap();

        // Perform lookup in the shared KV store
        let value_opt = caller.data().lock().unwrap().get(key_str);

        // Mutable access to memory to write result
        let data_mut = memory.data_mut(&mut caller);
        if let Some(value) = value_opt {
            let value_bytes = value.as_bytes();
            let result_slice = &mut data_mut[result_ptr as usize..(result_ptr as usize + value_bytes.len())];
            result_slice.copy_from_slice(value_bytes);
            value_bytes.len() as i32
        } else {
            -1
        }
    }).unwrap();

    // Register the `set` function
    linker.func_wrap("env", "kv_set", move |mut caller: Caller<'_, SharedKvStore>, key_ptr: i32, key_len: i32, value_ptr: i32, value_len: i32| {
        let memory = caller.get_export("memory").unwrap().into_memory().unwrap();
        let data = memory.data(&caller);

        // Immutable access to memory to read key and value
        println!("got key_len: {}, key_ptr: {}", key_len, key_ptr);
        let value = &data[value_ptr as usize..(value_ptr + value_len) as usize];
        let key = &data[key_ptr as usize..(key_ptr + key_len) as usize];

        let key_str = std::str::from_utf8(key).unwrap();
        assert_eq!(key_str, "Name");
        let value_str = std::str::from_utf8(value).unwrap();

        // Perform write operation in the shared KV store
        caller.data().lock().unwrap().set(key_str, value_str);
    })
        .unwrap();

    // Instantiate the module
    let instance = linker.instantiate(&mut store, &caller_module).unwrap();

    // Call WebAssembly functions
    let set_key_value = instance.get_func(&mut store, "set_key_value").unwrap().typed::<(), ()>(&store).unwrap();
    set_key_value.call(&mut store, ()).unwrap();

    let get_key_value = instance.get_func(&mut store, "get_key_value").unwrap().typed::<(), ()>(&store).unwrap();
    get_key_value.call(&mut store, ()).unwrap();
}

view this post on Zulip Wasmtime GitHub notifications bot (Jul 27 2024 at 07:35):

itachaaa edited a comment on issue #9017:

You're currently working at the core wasm abstraction layer, not the component layer, meaning you want the preview1 module.您目前使用的是核心 wasm 抽象层,而不是组件层,这意味着您需要 preview1 模块。

Even with that though your code contains:即便如此,您的代码中仍包含

#[no_mangle] pub unsafe fn set_key_value(key: &str, value: &str) { ... }

which is unlikely to be what you want.这不可能是你想要的。

I'd recommend reading over examples/documentation about passing strings into WebAssembly and possible reading up on the component model which would enable that use case more cleanly我建议你阅读有关向 WebAssembly 传递字符串的示例/文档,并在可能的情况下阅读有关组件模型的内容,这样就能更简洁地实现该用例。

Thanks,it helps a lot about params passing. I changed my code without passing string params, however, wasi_snapshot_preview1::fd_write has not been defined` still happed.

changed caller code:

extern "C" {
    pub fn kv_get(ptr: *const u8, len: i32, result_ptr: i32) -> i32;
    pub fn kv_set(key_ptr: *const u8, key_len: i32, value_ptr: *const u8, value_len: i32);
}

#[no_mangle]
pub unsafe fn set_key_value() {
    unsafe {
        kv_set(KEY.as_ptr(), KEY.len() as i32, VALUE.as_ptr(), VALUE.len() as i32);
    }
}

#[no_mangle]
pub unsafe fn get_key_value() {
    let mut result = vec![0u8; 100]; // 假设结果长度不会超过100字节
    let result_ptr = result.as_mut_ptr();
    let len  = unsafe { kv_get(KEY.as_ptr(), KEY.len() as i32, result_ptr as i32) };
    if len > 0 {
        println!("got value: {}", String::from_utf8(result[..len as usize].to_vec()).unwrap());
    } else {
        println!("failed get value.");    }
}

static KEY: &str = "Name";
static VALUE: &str = "World";

changed main code:

use wasmtime::*;
use kv_store::{create_kv_store, SharedKvStore};

fn main() {
    let mut config = Config::new();
    Config::async_support(&mut config, false);
    config.wasm_backtrace_details(WasmBacktraceDetails::Enable);
    config.wasm_component_model(true);
    let engine = Engine::new(&config).unwrap();
    let kv_store = create_kv_store();
    let mut store = Store::new(&engine, kv_store.clone());

    // Load the WebAssembly module
    let caller_module = Module::from_file(&engine, "../caller/target/wasm32-wasi/release/caller.wasm").unwrap();

    // Create a new Linker to link WASI functions
    let mut linker = Linker::new(&engine);

    // Register the `get` function
    linker.func_wrap("env", "kv_get", move |mut caller: Caller<'_, SharedKvStore>, ptr: i32, len: i32, result_ptr: i32| -> i32 {
        let memory = caller.get_export("memory").unwrap().into_memory().unwrap();
        let data = memory.data(&caller);

        // Immutable access to memory to read key
        let key = &data[ptr as usize..(ptr + len) as usize];
        let key_str = std::str::from_utf8(key).unwrap();

        // Perform lookup in the shared KV store
        let value_opt = caller.data().lock().unwrap().get(key_str);

        // Mutable access to memory to write result
        let data_mut = memory.data_mut(&mut caller);
        if let Some(value) = value_opt {
            let value_bytes = value.as_bytes();
            let result_slice = &mut data_mut[result_ptr as usize..(result_ptr as usize + value_bytes.len())];
            result_slice.copy_from_slice(value_bytes);
            value_bytes.len() as i32
        } else {
            -1
        }
    }).unwrap();

    // Register the `set` function
    linker.func_wrap("env", "kv_set", move |mut caller: Caller<'_, SharedKvStore>, key_ptr: i32, key_len: i32, value_ptr: i32, value_len: i32| {
        let memory = caller.get_export("memory").unwrap().into_memory().unwrap();
        let data = memory.data(&caller);

        // Immutable access to memory to read key and value
        println!("got key_len: {}, key_ptr: {}", key_len, key_ptr);
        let value = &data[value_ptr as usize..(value_ptr + value_len) as usize];
        let key = &data[key_ptr as usize..(key_ptr + key_len) as usize];

        let key_str = std::str::from_utf8(key).unwrap();
        assert_eq!(key_str, "Name");
        let value_str = std::str::from_utf8(value).unwrap();

        // Perform write operation in the shared KV store
        caller.data().lock().unwrap().set(key_str, value_str);
    })
        .unwrap();

    // Instantiate the module
    let instance = linker.instantiate(&mut store, &caller_module).unwrap();

    // Call WebAssembly functions
    let set_key_value = instance.get_func(&mut store, "set_key_value").unwrap().typed::<(), ()>(&store).unwrap();
    set_key_value.call(&mut store, ()).unwrap();

    let get_key_value = instance.get_func(&mut store, "get_key_value").unwrap().typed::<(), ()>(&store).unwrap();
    get_key_value.call(&mut store, ()).unwrap();
}

view this post on Zulip Wasmtime GitHub notifications bot (Jul 27 2024 at 08:15):

itachaaa edited a comment on issue #9017:

You're currently working at the core wasm abstraction layer, not the component layer, meaning you want the preview1 module.

Even with that though your code contains:

#[no_mangle] pub unsafe fn set_key_value(key: &str, value: &str) { ... }

which is unlikely to be what you want.

I'd recommend reading over examples/documentation about passing strings into WebAssembly and possible reading up on the component model which would enable that use case more cleanly

Thanks,it helps a lot about params passing. I changed my code without passing string params, however, wasi_snapshot_preview1::fd_write has not been defined` still happed.

changed caller code:

extern "C" {
    pub fn kv_get(ptr: *const u8, len: i32, result_ptr: i32) -> i32;
    pub fn kv_set(key_ptr: *const u8, key_len: i32, value_ptr: *const u8, value_len: i32);
}

#[no_mangle]
pub unsafe fn set_key_value() {
    unsafe {
        kv_set(KEY.as_ptr(), KEY.len() as i32, VALUE.as_ptr(), VALUE.len() as i32);
    }
}

#[no_mangle]
pub unsafe fn get_key_value() {
    let mut result = vec![0u8; 100];
    let result_ptr = result.as_mut_ptr();
    let len  = unsafe { kv_get(KEY.as_ptr(), KEY.len() as i32, result_ptr as i32) };
    if len > 0 {
        println!("got value: {}", String::from_utf8(result[..len as usize].to_vec()).unwrap());
    } else {
        println!("failed get value.");    }
}

static KEY: &str = "Name";
static VALUE: &str = "World";

changed main code:

use wasmtime::*;
use kv_store::{create_kv_store, SharedKvStore};

fn main() {
    let mut config = Config::new();
    Config::async_support(&mut config, false);
    config.wasm_backtrace_details(WasmBacktraceDetails::Enable);
    config.wasm_component_model(true);
    let engine = Engine::new(&config).unwrap();
    let kv_store = create_kv_store();
    let mut store = Store::new(&engine, kv_store.clone());

    // Load the WebAssembly module
    let caller_module = Module::from_file(&engine, "../caller/target/wasm32-wasi/release/caller.wasm").unwrap();

    // Create a new Linker to link WASI functions
    let mut linker = Linker::new(&engine);

    // Register the `get` function
    linker.func_wrap("env", "kv_get", move |mut caller: Caller<'_, SharedKvStore>, ptr: i32, len: i32, result_ptr: i32| -> i32 {
        let memory = caller.get_export("memory").unwrap().into_memory().unwrap();
        let data = memory.data(&caller);

        // Immutable access to memory to read key
        let key = &data[ptr as usize..(ptr + len) as usize];
        let key_str = std::str::from_utf8(key).unwrap();

        // Perform lookup in the shared KV store
        let value_opt = caller.data().lock().unwrap().get(key_str);

        // Mutable access to memory to write result
        let data_mut = memory.data_mut(&mut caller);
        if let Some(value) = value_opt {
            let value_bytes = value.as_bytes();
            let result_slice = &mut data_mut[result_ptr as usize..(result_ptr as usize + value_bytes.len())];
            result_slice.copy_from_slice(value_bytes);
            value_bytes.len() as i32
        } else {
            -1
        }
    }).unwrap();

    // Register the `set` function
    linker.func_wrap("env", "kv_set", move |mut caller: Caller<'_, SharedKvStore>, key_ptr: i32, key_len: i32, value_ptr: i32, value_len: i32| {
        let memory = caller.get_export("memory").unwrap().into_memory().unwrap();
        let data = memory.data(&caller);

        // Immutable access to memory to read key and value
        println!("got key_len: {}, key_ptr: {}", key_len, key_ptr);
        let value = &data[value_ptr as usize..(value_ptr + value_len) as usize];
        let key = &data[key_ptr as usize..(key_ptr + key_len) as usize];

        let key_str = std::str::from_utf8(key).unwrap();
        assert_eq!(key_str, "Name");
        let value_str = std::str::from_utf8(value).unwrap();

        // Perform write operation in the shared KV store
        caller.data().lock().unwrap().set(key_str, value_str);
    })
        .unwrap();

    // Instantiate the module
    let instance = linker.instantiate(&mut store, &caller_module).unwrap();

    // Call WebAssembly functions
    let set_key_value = instance.get_func(&mut store, "set_key_value").unwrap().typed::<(), ()>(&store).unwrap();
    set_key_value.call(&mut store, ()).unwrap();

    let get_key_value = instance.get_func(&mut store, "get_key_value").unwrap().typed::<(), ()>(&store).unwrap();
    get_key_value.call(&mut store, ()).unwrap();
}

view this post on Zulip Wasmtime GitHub notifications bot (Jul 29 2024 at 14:17):

alexcrichton commented on issue #9017:

You'll want to to read over the documentation in the link I mentioned above, namely:

Next a wasmtime::Linker is configured with WASI imports by using the add_to_linker_* desired

which is this method

view this post on Zulip Wasmtime GitHub notifications bot (Jul 30 2024 at 02:01):

itachaaa commented on issue #9017:

Thanks!

view this post on Zulip Wasmtime GitHub notifications bot (Jul 30 2024 at 14:24):

alexcrichton closed issue #9017:

I know that there are some wasi_snapshot_preview1::fd_write related descriptions in the recent issue: 8521, 7697, and I added add_to_linker_sync in my code. However, the type does not match and the compilation fails. Here are the details,I want to implement a small program that calls the cache interface in wasm.

Running it directly throws an exception like this:

thread 'main' panicked at src/main.rs:62:67:
called `Result::unwrap()` on an `Err` value: unknown import: `wasi_snapshot_preview1::fd_write` has not been defined
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

When I added add_to_linker_sync the compile Error:

error[E0308]: mismatched types
   --> src/main.rs:62:39
    |
62  |     wasmtime_wasi::add_to_linker_sync(&mut linker).unwrap();
    |     --------------------------------- ^^^^^^^^^^^ expected `&mut Linker<_>`, found `&mut Linker<Arc<Mutex<KvStore>>>`
    |     |
    |     arguments to this function are incorrect
    |
    = note: expected mutable reference `&mut wasmtime::component::Linker<_>`
               found mutable reference `&mut wasmtime::Linker<Arc<Mutex<KvStore>>>`

wasm_runner:

use wasmtime::*;
use kv_store::{create_kv_store, SharedKvStore};

fn main() {
    let mut config = Config::new();
    Config::async_support(&mut config, false);
    config.wasm_backtrace_details(WasmBacktraceDetails::Enable);
    config.wasm_component_model(true);
    let engine = Engine::new(&config).unwrap();
    let kv_store = create_kv_store();
    let mut store = Store::new(&engine, kv_store.clone());

    // Load the WebAssembly module
    // let caller_wasm = fs::read("../caller/target/wasm32-wasi/release/caller.wasm").unwrap();
    let caller_module = Module::from_file(&engine, "../caller/target/wasm32-wasi/release/caller.wasm").unwrap();

    // Create a new Linker to link WASI functions
    let mut linker = Linker::new(&engine);

    // Register the `get` function
    linker.func_wrap("env", "kv_get", move |mut caller: Caller<'_, SharedKvStore>, ptr: i32, len: i32, result_ptr: i32| -> i32 {
        let memory = caller.get_export("memory").unwrap().into_memory().unwrap();
        let data = memory.data(&caller);

        // Immutable access to memory to read key
        let key = &data[ptr as usize..(ptr + len) as usize];
        let key_str = std::str::from_utf8(key).unwrap();

        // Perform lookup in the shared KV store
        let value_opt = caller.data().lock().unwrap().get(key_str);

        // Mutable access to memory to write result
        let data_mut = memory.data_mut(&mut caller);
        if let Some(value) = value_opt {
            let value_bytes = value.as_bytes();
            let result_slice = &mut data_mut[result_ptr as usize..(result_ptr as usize + value_bytes.len())];
            result_slice.copy_from_slice(value_bytes);
            value_bytes.len() as i32
        } else {
            -1
        }
    }).unwrap();

    // Register the `set` function
    linker.func_wrap("env", "kv_set", move |mut caller: Caller<'_, SharedKvStore>, key_ptr: i32, key_len: i32, value_ptr: i32, value_len: i32| {
        let memory = caller.get_export("memory").unwrap().into_memory().unwrap();
        let data = memory.data(&caller);

        // Immutable access to memory to read key and value
        let key = &data[key_ptr as usize..(key_ptr + key_len) as usize];
        let value = &data[value_ptr as usize..(value_ptr + value_len) as usize];

        let key_str = std::str::from_utf8(key).unwrap();
        let value_str = std::str::from_utf8(value).unwrap();

        // Perform write operation in the shared KV store
        caller.data().lock().unwrap().set(key_str, value_str);
    })
        .unwrap();

    // Instantiate the module
    // wasmtime_wasi::add_to_linker_sync(&mut linker).unwrap();
    let instance = linker.instantiate(&mut store, &caller_module).unwrap();

    // Call WebAssembly functions
    let set_key_value = instance.get_func(&mut store, "set_key_value").unwrap().typed::<(i32, i32), ()>(&store).unwrap();
    set_key_value.call(&mut store, (0, 0)).unwrap();

    let get_key_value = instance.get_func(&mut store, "get_key_value").unwrap().typed::<i32, i32>(&store).unwrap();
    let result = get_key_value.call(&mut store, 0).unwrap();
    println!("Got value from KV store: {}", result);
}
[package]
name = "wasm_runner"
version = "0.1.0"
edition = "2021"

[dependencies]
wasmtime = "23.0.1"
wasmtime-wasi = "23.0.1"
kv_store = { path = "../kv_store" }

caller:

extern "C" {
    pub fn kv_get(ptr: *const u8, len: usize, result_ptr: *mut u8) -> i32;
    pub fn kv_set(key_ptr: *const u8, key_len: usize, value_ptr: *const u8, value_len: usize);
}

#[no_mangle]
pub unsafe fn set_key_value(key: &str, value: &str) {
    unsafe {
        kv_set(key.as_ptr(), key.len(), value.as_ptr(), value.len());
    }
}

#[no_mangle]
pub unsafe fn get_key_value(key: &str) -> Option<String> {
    let mut result = vec![0u8; 100]; // 假设结果长度不会超过100字节
    let result_ptr = result.as_mut_ptr();
    let len = unsafe { kv_get(key.as_ptr(), key.len(), result_ptr) };

    if len >= 0 {
        Some(String::from_utf8(result[..len as usize].to_vec()).unwrap())
    } else {
        None
    }
}
[package]
name = "caller"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]
use std::collections::HashMap;
use std::sync::{Arc, Mutex};

pub struct KvStore {
    map: HashMap<String, String>,
}

impl KvStore {
    pub fn new() -> Self {
        KvStore {
            map: HashMap::new(),
        }
    }

    pub fn get(&self, key: &str) -> Option<String> {
        self.map.get(key).cloned()
    }

    pub fn set(&mut self, key: &str, value: &str) {
        self.map.insert(key.to_string(), value.to_string());
    }
}

pub type SharedKvStore = Arc<Mutex<KvStore>>;

pub fn create_kv_store() -> SharedKvStore {
    Arc::new(Mutex::new(KvStore::new()))
}

Last updated: Dec 23 2024 at 13:07 UTC