1

I am new to Rust, as will probably be obvious.

Basically I have this scenario you can see below where, I create a new type that has a closure added to it, but this closure needs to access data which has not yet been created. The data will be created by the time the closure gets called, but when the closure is initially created the data is not yet available.

What is the best way to do deal with?

I am also curious if my closure was not a closure, but rather a private function in my implementation, how would I access that data? This closure/function is a callback from WasmTime and requires an explicit method signature which does not allow me to add $self to it. So how could I get at the instance fields of the implementation without a reference to $self in the function parameters?

pub struct EmWasmNode {
    wasmStore: Store<WasiCtx>,
    wasmTable: Table,
}

impl EmWasmNode {
    pub fn new(filePath: &str) -> Result<Self> {

        let engine = Engine::default();
        // let module = Module::from_file(&engine, "wasm/index.wast")?;
        let module = Module::from_file(&engine, filePath)?;
        let mut linker = Linker::new(&engine);
        wasmtime_wasi::add_to_linker(&mut linker, |s| s)?;

        let wasi = WasiCtxBuilder::new()
            .inherit_stdio()
            .inherit_args()?
            .build();
        let mut store = Store::new(&engine, wasi);

        linker.func_wrap("env", "emscripten_set_main_loop", |p0: i32, p1: i32, p2: i32| {
            println!("emscripten_set_main_loop {} {} {}", p0, p1, p2);
/*** How would I access wasmTable and wasmStore from here to execute more methods??? ***/

            //let browserIterationFuncOption:Option<wasmtime::Val> = Self::wasmTable.get(&mut Self::wasmStore, p0 as u32);
            // browserIterationFuncOption.unwrap().unwrap_funcref().call(&store, ());
        })?;

        let instance = linker.instantiate(&mut store, &module)?;

        let table = instance
            .get_export(&mut store, "__indirect_function_table")
            .as_ref()
            .and_then(extern_table)
            .cloned();

        let start = instance.get_typed_func::<(), (), _>(&mut store, "_start")?;

        start.call(&mut store, ())?;

        Ok(EmWasmNode {
            wasmStore: store,
            wasmTable: table.unwrap(),
        })
    }
rygo6
  • 1,929
  • 22
  • 30
  • Did you checked whether the library you are using have similar examples in its documentation? – Ekrem Dinçel Nov 26 '21 at 15:44
  • Why don't you try `let table = RefCell::new(Option::None)`? That seems like the simplest safe solution to me. – Coder-256 Nov 27 '21 at 03:49
  • I tried that before but then I encounter the issue of how exactly do I get the ref into the closure? If change it so the method has &self as a param and call &self.wasmTable inside the closure it errors with: "requirement to implement `Fn` derives from here closure is `FnOnce` because it moves the variable `self` out of its environment" – rygo6 Nov 27 '21 at 07:15
  • Hm so I got past that by putting let wasmTable = &self.wasmTable; inside the closure. That means the closure captures a ref and does not move it I presume? Now I am getting an error the the closure needs to: 'type must satisfy the static lifetime' – rygo6 Nov 27 '21 at 07:30

1 Answers1

0

You have to instantiate a struct before. I suggest the more simple code below to see my idea.

struct Atype
{
    name: String,
}

impl Atype
{
    pub fn new() -> Self
    {
        Self{ name: String::from("zeppi")}
    }
    
    pub fn test(&self) -> ()
    {
        let func = | x | { println!("{} {}", &self.name, x);};
        func(3)
    }
}

fn main() {
    let o = Atype::new();
    o.test();
}
Zeppi
  • 1,175
  • 6
  • 11
  • In my case the data for 'name: string' won't be available in the new() method. That var would have to be filled in a subsequent method call. What would be the best means to deal with that? Make it a Some or another type? Or is there a better way entirely? – rygo6 Nov 26 '21 at 08:27
  • "new" is like a Static method, in Java or other language, and test like a method. You have to work in two time. you can doo like this https://gist.github.com/zeppi/9a876a53595c1439b7eb35162b0b7fac – Zeppi Nov 26 '21 at 09:12
  • Thanks for your help so far, but it doesn't quite solve my issue I think. I've edited your gist to try and better explain the issue the code I originally posted is encountering. https://gist.github.com/rygo6/c1e20c9ce879a5a5e0bde885a0f20230 Basically the closures need to access data that can't be known until after the closures are created. In C++ the closures would just point to some empty memory on the heap on creation. – rygo6 Nov 26 '21 at 10:10