From 99dd7a6481f9dbdd0402d561fae78bcc9755b4b1 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Wed, 9 Dec 2020 21:06:36 +0800 Subject: [PATCH] Share constant variables for closures. --- RELEASES.md | 5 +++++ doc/src/language/fn-closure.md | 18 ------------------ src/dynamic.rs | 15 ++++++++++++++- src/engine.rs | 13 +++++-------- 4 files changed, 24 insertions(+), 27 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index ac4ddd40..0b296b78 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -10,6 +10,11 @@ Bug fixes * Constants are no longer propagated by the optimizer if shadowed by a non-constant variable. * Constants passed as the `this` parameter to Rhai functions now throws an error if assigned to. +Enhancements +------------ + +* Capturing a constant variable in a closure is now supported, with no cloning. + Version 0.19.7 ============== diff --git a/doc/src/language/fn-closure.md b/doc/src/language/fn-closure.md index 56c79cfd..e4f59fe7 100644 --- a/doc/src/language/fn-closure.md +++ b/doc/src/language/fn-closure.md @@ -57,24 +57,6 @@ f.call(2) == 42; ``` -Constants are Not Captured --------------------------- - -Constants are never shared. Their values are simply cloned. - -```rust -const x = 42; // constant variable 'x' - -let f = |y| x += y; // constant 'x' is cloned and not captured - -x.is_shared() == false; // 'x' is not shared - -f.call(10); // the cloned copy of 'x' is changed - -x == 42; // 'x' is not changed -``` - - Beware: Captured Variables are Truly Shared ------------------------------------------ diff --git a/src/dynamic.rs b/src/dynamic.rs index e5880ea5..41f2756e 100644 --- a/src/dynamic.rs +++ b/src/dynamic.rs @@ -615,7 +615,20 @@ impl Dynamic { /// if its value is going to be modified. This safe-guards constant values from being modified /// from within Rust functions. pub fn is_read_only(&self) -> bool { - self.access_mode().is_read_only() + match self.0 { + #[cfg(not(feature = "no_closure"))] + Union::Shared(_, access) if access.is_read_only() => true, + + #[cfg(not(feature = "no_closure"))] + #[cfg(not(feature = "sync"))] + Union::Shared(ref cell, _) => cell.borrow().access_mode().is_read_only(), + + #[cfg(not(feature = "no_closure"))] + #[cfg(feature = "sync")] + Union::Shared(ref cell, _) => cell.read().unwrap().access_mode().is_read_only(), + + _ => self.access_mode().is_read_only(), + } } /// Create a [`Dynamic`] from any type. A [`Dynamic`] value is simply returned as is. /// diff --git a/src/engine.rs b/src/engine.rs index e42d06ac..129ff1cf 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -2383,16 +2383,13 @@ impl Engine { // Share statement #[cfg(not(feature = "no_closure"))] Stmt::Share(x) => { - match scope.get_index(&x.name) { - Some((index, AccessMode::ReadWrite)) => { - let val = scope.get_mut(index); + if let Some((index, _)) = scope.get_index(&x.name) { + let val = scope.get_mut(index); - if !val.is_shared() { - // Replace the variable with a shared value. - *val = crate::stdlib::mem::take(val).into_shared(); - } + if !val.is_shared() { + // Replace the variable with a shared value. + *val = crate::stdlib::mem::take(val).into_shared(); } - _ => (), } Ok(Dynamic::UNIT) }