rhaiscript / rhai

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

Question: modifying a Rust owned Vec? #168

Closed Stovoy closed 4 years ago

Stovoy commented 4 years ago

Hi, I'm planning to use Rhai for a physics based game, where all the different particle behavior is controlled by different rhai scripts. As such, each script needs to interact with the world in some way.

Simplifying things for this question, let's say the world was a Vec<T>, and we want to be able to read and write to it from Rhai. I tried creating a Rhai scope with a mutable ref to that Vec, but because scopes box their variables, it needs 'static lifetime and that wasn't working out. It also needed to clone() the variable.

In my case, I will only ever be executing one Rhai script at a time, so only one such mutable reference to the Vec would exist at a time, but it looks like that kind of guarantee isn't possible to do in Rhai. Maybe could do something with Rc?

I also tried defining a function in the Rhai script and passing a reference to the Vec with Engine::call_fn, but I couldn't figure out how to pass a mutable reference to the Vec as an argument to the function.

Any suggestions? I was really hoping to use Rhai as a dynamic scripting language for this project! Thank you for all the great work on this.

schungx commented 4 years ago

Yes, Rhai is sandboxed, so scripts should not be able to influence the environment unless explicitly permitted. In fact, an immutable Engine should not allow any mutation at all. This is for protection against malicious user scripts.

You need to use interior mutability for a Rhai script to change the world (i.e. Cell or RefCell). This indicates to Rhai that you've explicitly permitted the caller of that function to mutate an outside state.

Look into: https://github.com/jonathandturner/rhai/blob/master/tests/side_effects.rs

This test simulates a command object with an Arc<Mutex<T>> wrapper that acts as an API into the Rhai engine. A script can call this API to affect state on the command object.

schungx commented 4 years ago

let's say the world was a Vec<T>, and we want to be able to read and write to it from Rhai.

Beware that you're going to be fighting the borrow checker a lot on this, especially when you're running your engine massively parallel - which you'd want to because of all those independent particles...

You probably want to rethink your world data structure.

Stovoy commented 4 years ago

Thanks! This solution works well for me here.