rhaiscript / rhai

Rhai - An embedded scripting language for Rust.
https://crates.io/crates/rhai
Apache License 2.0
3.81k stars 179 forks source link

How to export a function that uses a property of my struct but I dont want to export the whole struct? #735

Closed jkvargas closed 1 year ago

jkvargas commented 1 year ago
struct Plugin {
    engine: Engine,
    compiled_code: AST,
    work_dir: PathBuf,
}

impl Plugin {
    pub(crate) fn new_from_string(code: String, work_dir: PathBuf) -> Result<Self> {
        let mut engine = Engine::new_raw();
        engine.register_fn("mkdir", Plugin::mkdir);

        let compiled_code = engine.compile(code)?;

        Ok(Self {
            engine,
            compiled_code,
            work_dir,
        })
    }

    pub(crate) fn mkdir(&self, directory: ImmutableString) -> bool {
        let final_dir = self.work_dir.join(directory.as_str());
        let res = create_dir_all(final_dir);
        if res.is_ok() { false } else { true }
    }
}

how do I use the mkdir function in rhai script without having to instantiate Plugin? that object creation will happen inside rust :)

schungx commented 1 year ago

First of all, &self is not supported by Rhai. You'd need &mut self at the very least.

As to your question, it seems that you need to, somehow, pass in the working directory into the Engine such that it knows where the root is. There are a few ways to do this, but in your case, as it is unlikely to change, it is simplest to store this kind of info into the Engine's tag.

https://rhai.rs/book/engine/options.html?highlight=set_default_tag#runtime-behavior

The tag is set by calling Engine::set_default_tag. You can then access this tag from the NativeCallContext of the function. If you have more than one piece of information, you can make this an object map.

If your root directory will be changed dynamically, then set it before you evaluate scripts.

Essentially you have two routes to access the same property: via the Plugin type as well as via a Rhai script. Alternatively, you can treat this as a mutable global state. This obviously calls for a shared data value (e.g. Rc<RefCell<...>>) that you can capture into a closure for the register_fn call.

jkvargas commented 1 year ago

thanks so much for the info. Also, what are the other options you mentioned. Can you point out on the docs? Thanks!

schungx commented 1 year ago

Also, what are the other options you mentioned.

What are the other options you require?