rhaiscript / rhai

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

How to convert the type of Dynamic to a structure? #593

Closed youngzhaozju closed 2 years ago

youngzhaozju commented 2 years ago

Hey,

I tried to use Scope to delivery instance of a structure to Rhai. It works very well. I also want to get the instance from Rhai to rust. I found two ways:

  1. Make a clone of the instance using get_value::("name_of_var"). After that, it is needed to reset the value by set_value("name_of_var", instance); I do not think it is a proper way.
  2. use get_mut(), it is possible to get an instance in &mut Dynamic. How to convert the Dyniamic to the type of structure?

Can anybody inspire me? Thank you! Regards, Yang

schungx commented 2 years ago

use get_mut(), it is possible to get an instance in &mut Dynamic. How to convert the Dyniamic to the type of structure?

let value = scope.get_mut("name_of_var").unwrap();

let x: &mut MyType = &mut *value.write_lock::<MyType>().unwrap();

let x: &MyType = &*value.read_lock::<MyType>().unwrap();

https://rhai.rs/book/rust/register-raw.html#tldr https://rhai.rs/book/language/dynamic.html#methods-and-traits

youngzhaozju commented 2 years ago

Dear Stephen, Thanks so much! I should have had been carefully check the book before asking the question. Thank you! Regards, Yang

schungx commented 2 years ago

No worries. Your question actually prompted me to add a Scope::remove method to do this easier, although you can always do std::mem::take(value) to take ownership of the Dynamic but it is still a bit convoluted.

youngzhaozju commented 2 years ago

No worries. Your question actually prompted me to add a Scope::remove method to do this easier, although you can always do std::mem::take(value) to take ownership of the Dynamic but it is still a bit convoluted.

I think this is a good idea. For example, I have to handle an instance in rust and rhai repeatly. I such a way, I can take the instance from rhai to rust, and then modify it in rust, and set it to rhai for calculation, endly I take it from rhai to rust again.

In pyO3, there is a similar function. It is very feasible.

Thank you! Regards, Yang

schungx commented 2 years ago

You have to be careful though... any variable declared at root level in the Rhai script will persist in the Scope. If not careful enough, you'll find a fast growing Scope.

You have to do a Scope::rewind to remove the extra ones.

youngzhaozju commented 2 years ago

have to be careful th

I found that the function scope.set_value("name", instance) will overwrite the value which has the same key name. It is somewhat like hashmap.insert("key", value); Is it right?

I took the instance from ("name", instance) using std::mem::take(value). It did work. The value is empty. Scope { values: [()], names: ["abc"], aliases: [[]], dummy: PhantomData }

There are no extra ones. Am I right?

Thanks! Yang

schungx commented 2 years ago

I found that the function scope.set_value("name", instance) will overwrite the value which has the same key name. It is somewhat like hashmap.insert("key", value); Is it right?

That's correct.

There are no extra ones. Am I right?

Seems to have only one variable which is (). No extra ones. However, you really should not depend on the fact that a script does not introduce new variables into the Scope. The Scope is there in order to capture new variables from scripts!

Therefore, you should do something like this:

let orig_scope_len = scope.len();

engine.run_with_scope(&mut scope, ....)?;

// ... inspect scope to work with new variables etc.

scope.truncate(orig_scope_len);    // rewind scope to original size