Assume property getters are pure.
This commit is contained in:
parent
d9dca6ef98
commit
6df2178460
@ -4,6 +4,14 @@ Rhai Release Notes
|
|||||||
Version 1.0.6
|
Version 1.0.6
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
Bug fixes
|
||||||
|
---------
|
||||||
|
|
||||||
|
* Eliminate unnecessary property write-back when accessed via a getter since property getters are assumed to be _pure_.
|
||||||
|
|
||||||
|
Enhancements
|
||||||
|
------------
|
||||||
|
|
||||||
* `MultiInputsStream`, `ParseState`, `TokenIterator`, `IdentifierBuilder` and `AccessMode` are exported under the `internals` feature.
|
* `MultiInputsStream`, `ParseState`, `TokenIterator`, `IdentifierBuilder` and `AccessMode` are exported under the `internals` feature.
|
||||||
|
|
||||||
|
|
||||||
|
@ -1480,6 +1480,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
_ => Err(err),
|
_ => Err(err),
|
||||||
},
|
},
|
||||||
|
// Assume getters are always pure
|
||||||
|(v, _)| Ok((v, false)),
|
|(v, _)| Ok((v, false)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -1533,7 +1534,9 @@ impl Engine {
|
|||||||
let hash_set = FnCallHashes::from_native(*hash_set);
|
let hash_set = FnCallHashes::from_native(*hash_set);
|
||||||
let mut arg_values = [target.as_mut(), &mut Default::default()];
|
let mut arg_values = [target.as_mut(), &mut Default::default()];
|
||||||
let args = &mut arg_values[..1];
|
let args = &mut arg_values[..1];
|
||||||
let (mut val, updated) = self
|
|
||||||
|
// Assume getters are always pure
|
||||||
|
let (mut val, _) = self
|
||||||
.exec_fn_call(
|
.exec_fn_call(
|
||||||
mods, state, lib, getter, hash_get, args, is_ref_mut, true,
|
mods, state, lib, getter, hash_get, args, is_ref_mut, true,
|
||||||
*pos, None, level,
|
*pos, None, level,
|
||||||
@ -1577,7 +1580,7 @@ impl Engine {
|
|||||||
.map_err(|err| err.fill_position(*x_pos))?;
|
.map_err(|err| err.fill_position(*x_pos))?;
|
||||||
|
|
||||||
// Feed the value back via a setter just in case it has been updated
|
// Feed the value back via a setter just in case it has been updated
|
||||||
if updated || may_be_changed {
|
if may_be_changed {
|
||||||
// Re-use args because the first &mut parameter will not be consumed
|
// Re-use args because the first &mut parameter will not be consumed
|
||||||
let mut arg_values = [target.as_mut(), val];
|
let mut arg_values = [target.as_mut(), val];
|
||||||
let args = &mut arg_values;
|
let args = &mut arg_values;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#![cfg(not(feature = "no_object"))]
|
#![cfg(not(feature = "no_object"))]
|
||||||
|
|
||||||
use rhai::{Engine, EvalAltResult, INT};
|
use rhai::{Engine, EvalAltResult, Scope, INT};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_get_set() -> Result<(), Box<EvalAltResult>> {
|
fn test_get_set() -> Result<(), Box<EvalAltResult>> {
|
||||||
@ -70,7 +70,7 @@ fn test_get_set() -> Result<(), Box<EvalAltResult>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_get_set_chain() -> Result<(), Box<EvalAltResult>> {
|
fn test_get_set_chain_with_write_back() -> Result<(), Box<EvalAltResult>> {
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct TestChild {
|
struct TestChild {
|
||||||
x: INT,
|
x: INT,
|
||||||
@ -121,9 +121,10 @@ fn test_get_set_chain() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
engine.register_fn("new_tp", TestParent::new);
|
engine.register_fn("new_tp", TestParent::new);
|
||||||
|
|
||||||
|
assert_eq!(engine.eval::<INT>("let a = new_tp(); a.child.x")?, 1);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
engine.eval::<INT>("let a = new_tp(); a.child.x = 500; a.child.x")?,
|
engine.eval::<INT>("let a = new_tp(); a.child.x = 42; a.child.x")?,
|
||||||
500
|
42
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -166,3 +167,48 @@ fn test_get_set_op_assignment() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_get_set_chain_without_write_back() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct Outer {
|
||||||
|
pub inner: Inner,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct Inner {
|
||||||
|
pub value: INT,
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut engine = Engine::new();
|
||||||
|
let mut scope = Scope::new();
|
||||||
|
|
||||||
|
scope.push(
|
||||||
|
"outer",
|
||||||
|
Outer {
|
||||||
|
inner: Inner { value: 42 },
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
engine
|
||||||
|
.register_type::<Inner>()
|
||||||
|
.register_get_set(
|
||||||
|
"value",
|
||||||
|
|t: &mut Inner| t.value,
|
||||||
|
|_: &mut Inner, new: INT| panic!("Inner::value setter called with {}", new),
|
||||||
|
)
|
||||||
|
.register_type::<Outer>()
|
||||||
|
.register_get_set(
|
||||||
|
"inner",
|
||||||
|
|t: &mut Outer| t.inner.clone(),
|
||||||
|
|_: &mut Outer, new: Inner| panic!("Outer::inner setter called with {:?}", new),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
engine.eval_with_scope::<INT>(&mut scope, "outer.inner.value")?,
|
||||||
|
42
|
||||||
|
);
|
||||||
|
engine.consume_with_scope(&mut scope, "print(outer.inner.value)")?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user