How would I wrap a callback without getting "can't capture dynamic environment in a fn item"?

Hi!
I need to do some stuff, like converting and processing strings, before returning from a callback.
This is how i would usually do it in javascript:

let cb = () => "Hello";

function register_cb(cb) {
    document.onBlahBlahBlah(() => cb() + "world!");
}

register_cb(cb);
// output(when cb is called): "Hello world!"

But when I try to do a similar thing in rust:

use std::slice;

static CONTENT: &'static str = include_str!("../../test.html");

extern "C" {
    fn env_register_on_connection(cb: fn(bp: u32)) -> usize;
}

pub fn register_on_connection(cb: fn() -> String) {
    fn on_connection(buffer_pointer: u32) {
        let buffer = unsafe { slice::from_raw_parts(buffer_pointer as _, 512 as _) };
        let status_line = cb();
        let response = format!("{}{}", status_line, CONTENT);
    }

    unsafe {
        env_register_on_connection(on_connection);
    }
}

I get "can't capture environment in a fn item".

P.S:
I'm compiling for target wasm32-unknown-unknown.

That api doesn't support passing closures or anything else that needs to capture an environment. If you can, you will need to change env_register_on_connection to take a opaque type, and a function fn(opaque, u32) -> usize, then have C pass the opaque type to the function, in order to use closures with captures.

Another option is to stuff things into globals, and use that as your shared state. But that might be buggy.

Or,

use std::slice;

static CONTENT: &'static str = include_str!("../../test.html");

extern "C" {
    fn env_register_on_connection(cb_pass: fn() -> String, cb: extern "C" fn(fn() -> String, bp: u32)) -> usize;
}

pub fn register_on_connection(cb: fn() -> String) {
    extern "C" fn on_connection(cb: fn() -> String, buffer_pointer: u32) {
        // let buffer = unsafe { slice::from_raw_parts(buffer_pointer as _, 512 as _) };
        let status_line = cb();
        let response = format!("{}{}", status_line, CONTENT);
    }

    unsafe {
        env_register_on_connection(cb, on_connection);
    }
}
2 Likes