Improve shared value treatment.

This commit is contained in:
Stephen Chung 2020-08-08 16:24:10 +08:00
parent f016655414
commit 5a1a141ce3
6 changed files with 100 additions and 69 deletions

4
.gitignore vendored
View File

@ -3,5 +3,5 @@ Cargo.lock
.vscode/ .vscode/
.cargo/ .cargo/
doc/book/ doc/book/
before before*
after after*

View File

@ -5,7 +5,7 @@ use crate::parser::{ImmutableString, INT};
use crate::r#unsafe::{unsafe_cast_box, unsafe_try_cast}; use crate::r#unsafe::{unsafe_cast_box, unsafe_try_cast};
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
use crate::fn_native::SharedMut; use crate::fn_native::{shared_try_take, Shared};
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
use crate::parser::FLOAT; use crate::parser::FLOAT;
@ -159,9 +159,15 @@ pub enum Union {
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Map(Box<Map>), Map(Box<Map>),
FnPtr(Box<FnPtr>), FnPtr(Box<FnPtr>),
Variant(Box<Box<dyn Variant>>), Variant(Box<Box<dyn Variant>>),
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
Shared(SharedMut<Dynamic>), #[cfg(not(feature = "sync"))]
Shared(Shared<RefCell<Dynamic>>),
#[cfg(not(feature = "no_closure"))]
#[cfg(feature = "sync")]
Shared(Shared<RwLock<Dynamic>>),
} }
/// Underlying `Variant` read guard for `Dynamic`. /// Underlying `Variant` read guard for `Dynamic`.
@ -176,6 +182,7 @@ pub struct DynamicReadLock<'d, T: Variant + Clone>(DynamicReadLockInner<'d, T>);
enum DynamicReadLockInner<'d, T: Variant + Clone> { enum DynamicReadLockInner<'d, T: Variant + Clone> {
/// A simple reference to a non-shared value. /// A simple reference to a non-shared value.
Reference(&'d T), Reference(&'d T),
/// A read guard to a shared `RefCell`. /// A read guard to a shared `RefCell`.
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
#[cfg(not(feature = "sync"))] #[cfg(not(feature = "sync"))]
@ -212,6 +219,7 @@ pub struct DynamicWriteLock<'d, T: Variant + Clone>(DynamicWriteLockInner<'d, T>
enum DynamicWriteLockInner<'d, T: Variant + Clone> { enum DynamicWriteLockInner<'d, T: Variant + Clone> {
/// A simple mutable reference to a non-shared value. /// A simple mutable reference to a non-shared value.
Reference(&'d mut T), Reference(&'d mut T),
/// A write guard to a shared `RefCell`. /// A write guard to a shared `RefCell`.
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
#[cfg(not(feature = "sync"))] #[cfg(not(feature = "sync"))]
@ -406,6 +414,7 @@ impl fmt::Display for Dynamic {
#[cfg(not(feature = "no_std"))] #[cfg(not(feature = "no_std"))]
Union::Variant(value) if value.is::<Instant>() => f.write_str("<timestamp>"), Union::Variant(value) if value.is::<Instant>() => f.write_str("<timestamp>"),
Union::Variant(value) => f.write_str((*value).type_name()), Union::Variant(value) => f.write_str((*value).type_name()),
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
#[cfg(not(feature = "sync"))] #[cfg(not(feature = "sync"))]
Union::Shared(cell) => { Union::Shared(cell) => {
@ -444,6 +453,7 @@ impl fmt::Debug for Dynamic {
#[cfg(not(feature = "no_std"))] #[cfg(not(feature = "no_std"))]
Union::Variant(value) if value.is::<Instant>() => write!(f, "<timestamp>"), Union::Variant(value) if value.is::<Instant>() => write!(f, "<timestamp>"),
Union::Variant(value) => write!(f, "{}", (*value).type_name()), Union::Variant(value) => write!(f, "{}", (*value).type_name()),
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
#[cfg(not(feature = "sync"))] #[cfg(not(feature = "sync"))]
Union::Shared(cell) => { Union::Shared(cell) => {
@ -779,25 +789,46 @@ impl Dynamic {
self.try_cast::<T>().unwrap() self.try_cast::<T>().unwrap()
} }
/// Get a copy of the `Dynamic` as a specific type. /// Dereference the `Dynamic`.
/// ///
/// If the `Dynamic` is not a shared value, it returns a cloned copy of the value. /// If the `Dynamic` is not a shared value, it returns a cloned copy.
/// ///
/// If the `Dynamic` is a shared value, it returns a cloned copy of the shared value. /// If the `Dynamic` is a shared value, it a cloned copy of the shared value.
///
/// Returns `None` if the cast fails.
#[inline(always)] #[inline(always)]
pub fn clone_inner_data<T: Variant + Clone>(self) -> Option<T> { pub fn get_inner_clone(&self) -> Self {
match &self.0 {
#[cfg(not(feature = "no_closure"))]
Union::Shared(cell) => {
#[cfg(not(feature = "sync"))]
return cell.borrow().clone();
#[cfg(feature = "sync")]
return cell.read().unwrap().clone();
}
_ => self.clone(),
}
}
/// Flatten the `Dynamic`.
///
/// If the `Dynamic` is not a shared value, it returns itself.
///
/// If the `Dynamic` is a shared value, it returns the shared value if there are
/// no outstanding references, or a cloned copy.
#[inline(always)]
pub fn flatten(self) -> Self {
match self.0 { match self.0 {
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
Union::Shared(cell) => { Union::Shared(cell) => {
#[cfg(not(feature = "sync"))] #[cfg(not(feature = "sync"))]
return Some(cell.borrow().downcast_ref::<T>().unwrap().clone()); return shared_try_take(cell)
.map_or_else(|c| c.borrow().clone(), RefCell::into_inner);
#[cfg(feature = "sync")] #[cfg(feature = "sync")]
return Some(cell.read().unwrap().downcast_ref::<T>().unwrap().clone()); return shared_try_take(cell)
.map_or_else(|c| c.read().unwrap().clone(), RwLock::into_inner);
} }
_ => self.try_cast(), _ => self,
} }
} }

View File

@ -147,6 +147,7 @@ pub enum Target<'a> {
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
impl Target<'_> { impl Target<'_> {
/// Is the `Target` a reference pointing to other data? /// Is the `Target` a reference pointing to other data?
#[inline(always)]
pub fn is_ref(&self) -> bool { pub fn is_ref(&self) -> bool {
match self { match self {
Self::Ref(_) => true, Self::Ref(_) => true,
@ -159,6 +160,7 @@ impl Target<'_> {
} }
} }
/// Is the `Target` an owned value? /// Is the `Target` an owned value?
#[inline(always)]
pub fn is_value(&self) -> bool { pub fn is_value(&self) -> bool {
match self { match self {
Self::Ref(_) => false, Self::Ref(_) => false,
@ -171,6 +173,7 @@ impl Target<'_> {
} }
} }
/// Is the `Target` a shared value? /// Is the `Target` a shared value?
#[inline(always)]
pub fn is_shared(&self) -> bool { pub fn is_shared(&self) -> bool {
match self { match self {
Self::Ref(r) => r.is_shared(), Self::Ref(r) => r.is_shared(),
@ -184,6 +187,7 @@ impl Target<'_> {
} }
/// Is the `Target` a specific type? /// Is the `Target` a specific type?
#[allow(dead_code)] #[allow(dead_code)]
#[inline(always)]
pub fn is<T: Variant + Clone>(&self) -> bool { pub fn is<T: Variant + Clone>(&self) -> bool {
match self { match self {
Target::Ref(r) => r.is::<T>(), Target::Ref(r) => r.is::<T>(),
@ -196,6 +200,7 @@ impl Target<'_> {
} }
} }
/// Get the value of the `Target` as a `Dynamic`, cloning a referenced value if necessary. /// Get the value of the `Target` as a `Dynamic`, cloning a referenced value if necessary.
#[inline(always)]
pub fn clone_into_dynamic(self) -> Dynamic { pub fn clone_into_dynamic(self) -> Dynamic {
match self { match self {
Self::Ref(r) => r.clone(), // Referenced value is cloned Self::Ref(r) => r.clone(), // Referenced value is cloned
@ -208,6 +213,7 @@ impl Target<'_> {
} }
} }
/// Get a mutable reference from the `Target`. /// Get a mutable reference from the `Target`.
#[inline(always)]
pub fn as_mut(&mut self) -> &mut Dynamic { pub fn as_mut(&mut self) -> &mut Dynamic {
match self { match self {
Self::Ref(r) => *r, Self::Ref(r) => *r,
@ -258,6 +264,7 @@ impl Target<'_> {
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
impl<'a> From<&'a mut Dynamic> for Target<'a> { impl<'a> From<&'a mut Dynamic> for Target<'a> {
#[inline(always)]
fn from(value: &'a mut Dynamic) -> Self { fn from(value: &'a mut Dynamic) -> Self {
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
@ -273,6 +280,7 @@ impl<'a> From<&'a mut Dynamic> for Target<'a> {
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
impl<T: Into<Dynamic>> From<T> for Target<'_> { impl<T: Into<Dynamic>> From<T> for Target<'_> {
#[inline(always)]
fn from(value: T) -> Self { fn from(value: T) -> Self {
Self::Value(value.into()) Self::Value(value.into())
} }
@ -301,6 +309,7 @@ pub struct State {
impl State { impl State {
/// Create a new `State`. /// Create a new `State`.
#[inline(always)]
pub fn new() -> Self { pub fn new() -> Self {
Default::default() Default::default()
} }
@ -407,6 +416,7 @@ pub struct Engine {
} }
impl fmt::Debug for Engine { impl fmt::Debug for Engine {
#[inline(always)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.id.as_ref() { match self.id.as_ref() {
Some(id) => write!(f, "Engine({})", id), Some(id) => write!(f, "Engine({})", id),
@ -689,7 +699,7 @@ impl Engine {
idx_values: &mut StaticVec<Dynamic>, idx_values: &mut StaticVec<Dynamic>,
chain_type: ChainType, chain_type: ChainType,
level: usize, level: usize,
mut _new_val: Option<Dynamic>, new_val: Option<Dynamic>,
) -> Result<(Dynamic, bool), Box<EvalAltResult>> { ) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
if chain_type == ChainType::None { if chain_type == ChainType::None {
panic!(); panic!();
@ -722,12 +732,12 @@ impl Engine {
self.eval_dot_index_chain_helper( self.eval_dot_index_chain_helper(
state, lib, this_ptr, obj_ptr, expr, idx_values, next_chain, level, state, lib, this_ptr, obj_ptr, expr, idx_values, next_chain, level,
_new_val, new_val,
) )
.map_err(|err| err.new_position(*pos)) .map_err(|err| err.new_position(*pos))
} }
// xxx[rhs] = new_val // xxx[rhs] = new_val
_ if _new_val.is_some() => { _ if new_val.is_some() => {
let mut idx_val2 = idx_val.clone(); let mut idx_val2 = idx_val.clone();
// `call_setter` is introduced to bypass double mutable borrowing of target // `call_setter` is introduced to bypass double mutable borrowing of target
@ -737,7 +747,7 @@ impl Engine {
// Indexed value is a reference - update directly // Indexed value is a reference - update directly
Ok(ref mut obj_ptr) => { Ok(ref mut obj_ptr) => {
obj_ptr obj_ptr
.set_value(_new_val.unwrap()) .set_value(new_val.unwrap())
.map_err(|err| err.new_position(rhs.position()))?; .map_err(|err| err.new_position(rhs.position()))?;
None None
@ -747,7 +757,7 @@ impl Engine {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
EvalAltResult::ErrorIndexingType(_, _) => { EvalAltResult::ErrorIndexingType(_, _) => {
// Raise error if there is no index getter nor setter // Raise error if there is no index getter nor setter
Some(_new_val.unwrap()) Some(new_val.unwrap())
} }
// Any other error - return // Any other error - return
err => return Err(Box::new(err)), err => return Err(Box::new(err)),
@ -799,13 +809,13 @@ impl Engine {
// xxx.module::fn_name(...) - syntax error // xxx.module::fn_name(...) - syntax error
Expr::FnCall(_) => unreachable!(), Expr::FnCall(_) => unreachable!(),
// {xxx:map}.id = ??? // {xxx:map}.id = ???
Expr::Property(x) if target.is::<Map>() && _new_val.is_some() => { Expr::Property(x) if target.is::<Map>() && new_val.is_some() => {
let ((prop, _, _), pos) = x.as_ref(); let ((prop, _, _), pos) = x.as_ref();
let index = prop.clone().into(); let index = prop.clone().into();
let mut val = self let mut val = self
.get_indexed_mut(state, lib, target, index, *pos, true, false, level)?; .get_indexed_mut(state, lib, target, index, *pos, true, false, level)?;
val.set_value(_new_val.unwrap()) val.set_value(new_val.unwrap())
.map_err(|err| err.new_position(rhs.position()))?; .map_err(|err| err.new_position(rhs.position()))?;
Ok((Default::default(), true)) Ok((Default::default(), true))
} }
@ -820,9 +830,10 @@ impl Engine {
Ok((val.clone_into_dynamic(), false)) Ok((val.clone_into_dynamic(), false))
} }
// xxx.id = ??? // xxx.id = ???
Expr::Property(x) if _new_val.is_some() => { Expr::Property(x) if new_val.is_some() => {
let ((_, _, setter), pos) = x.as_ref(); let ((_, _, setter), pos) = x.as_ref();
let mut args = [target.as_mut(), _new_val.as_mut().unwrap()]; let mut new_val = new_val;
let mut args = [target.as_mut(), new_val.as_mut().unwrap()];
self.exec_fn_call( self.exec_fn_call(
state, lib, setter, 0, &mut args, is_ref, true, false, None, None, state, lib, setter, 0, &mut args, is_ref, true, false, None, None,
level, level,
@ -872,7 +883,7 @@ impl Engine {
self.eval_dot_index_chain_helper( self.eval_dot_index_chain_helper(
state, lib, this_ptr, &mut val, expr, idx_values, next_chain, level, state, lib, this_ptr, &mut val, expr, idx_values, next_chain, level,
_new_val, new_val,
) )
.map_err(|err| err.new_position(*pos)) .map_err(|err| err.new_position(*pos))
} }
@ -905,7 +916,7 @@ impl Engine {
idx_values, idx_values,
next_chain, next_chain,
level, level,
_new_val, new_val,
) )
.map_err(|err| err.new_position(*pos))?; .map_err(|err| err.new_position(*pos))?;
@ -944,7 +955,7 @@ impl Engine {
self.eval_dot_index_chain_helper( self.eval_dot_index_chain_helper(
state, lib, this_ptr, target, expr, idx_values, next_chain, state, lib, this_ptr, target, expr, idx_values, next_chain,
level, _new_val, level, new_val,
) )
.map_err(|err| err.new_position(*pos)) .map_err(|err| err.new_position(*pos))
} }
@ -1114,7 +1125,7 @@ impl Engine {
state: &mut State, state: &mut State,
_lib: &Module, _lib: &Module,
target: &'a mut Target, target: &'a mut Target,
mut _idx: Dynamic, idx: Dynamic,
idx_pos: Position, idx_pos: Position,
_create: bool, _create: bool,
_indexers: bool, _indexers: bool,
@ -1132,7 +1143,7 @@ impl Engine {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
Dynamic(Union::Array(arr)) => { Dynamic(Union::Array(arr)) => {
// val_array[idx] // val_array[idx]
let index = _idx let index = idx
.as_int() .as_int()
.map_err(|_| EvalAltResult::ErrorNumericIndexExpr(idx_pos))?; .map_err(|_| EvalAltResult::ErrorNumericIndexExpr(idx_pos))?;
@ -1153,13 +1164,13 @@ impl Engine {
Dynamic(Union::Map(map)) => { Dynamic(Union::Map(map)) => {
// val_map[idx] // val_map[idx]
Ok(if _create { Ok(if _create {
let index = _idx let index = idx
.take_immutable_string() .take_immutable_string()
.map_err(|_| EvalAltResult::ErrorStringIndexExpr(idx_pos))?; .map_err(|_| EvalAltResult::ErrorStringIndexExpr(idx_pos))?;
map.entry(index).or_insert(Default::default()).into() map.entry(index).or_insert(Default::default()).into()
} else { } else {
let index = _idx let index = idx
.read_lock::<ImmutableString>() .read_lock::<ImmutableString>()
.ok_or_else(|| EvalAltResult::ErrorStringIndexExpr(idx_pos))?; .ok_or_else(|| EvalAltResult::ErrorStringIndexExpr(idx_pos))?;
@ -1173,7 +1184,7 @@ impl Engine {
Dynamic(Union::Str(s)) => { Dynamic(Union::Str(s)) => {
// val_string[idx] // val_string[idx]
let chars_len = s.chars().count(); let chars_len = s.chars().count();
let index = _idx let index = idx
.as_int() .as_int()
.map_err(|_| EvalAltResult::ErrorNumericIndexExpr(idx_pos))?; .map_err(|_| EvalAltResult::ErrorNumericIndexExpr(idx_pos))?;
@ -1192,7 +1203,8 @@ impl Engine {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
_ if _indexers => { _ if _indexers => {
let type_name = val.type_name(); let type_name = val.type_name();
let args = &mut [val, &mut _idx]; let mut idx = idx;
let args = &mut [val, &mut idx];
self.exec_fn_call( self.exec_fn_call(
state, _lib, FN_IDX_GET, 0, args, is_ref, true, false, None, None, _level, state, _lib, FN_IDX_GET, 0, args, is_ref, true, false, None, None, _level,
) )
@ -1331,11 +1343,11 @@ impl Engine {
)), )),
// Normal assignment // Normal assignment
ScopeEntryType::Normal if op.is_empty() => { ScopeEntryType::Normal if op.is_empty() => {
let rhs_val = rhs_val.clone_inner_data().unwrap(); let value = rhs_val.flatten();
if cfg!(not(feature = "no_closure")) && lhs_ptr.is_shared() { if cfg!(not(feature = "no_closure")) && lhs_ptr.is_shared() {
*lhs_ptr.write_lock::<Dynamic>().unwrap() = rhs_val; *lhs_ptr.write_lock::<Dynamic>().unwrap() = value;
} else { } else {
*lhs_ptr = rhs_val; *lhs_ptr = value;
} }
Ok(Default::default()) Ok(Default::default())
} }
@ -1378,7 +1390,7 @@ impl Engine {
) )
.map_err(|err| err.new_position(*op_pos))?; .map_err(|err| err.new_position(*op_pos))?;
let value = value.clone_inner_data().unwrap(); let value = value.flatten();
if cfg!(not(feature = "no_closure")) && lhs_ptr.is_shared() { if cfg!(not(feature = "no_closure")) && lhs_ptr.is_shared() {
*lhs_ptr.write_lock::<Dynamic>().unwrap() = value; *lhs_ptr.write_lock::<Dynamic>().unwrap() = value;
} else { } else {
@ -1674,14 +1686,14 @@ impl Engine {
let index = scope.len() - 1; let index = scope.len() - 1;
state.scope_level += 1; state.scope_level += 1;
for loop_var in func(iter_type) { for iter_value in func(iter_type) {
let for_var = scope.get_mut(index).0; let (loop_var, _) = scope.get_mut(index);
let value = loop_var.clone_inner_data().unwrap();
if cfg!(not(feature = "no_closure")) && for_var.is_shared() { let value = iter_value.flatten();
*for_var.write_lock().unwrap() = value; if cfg!(not(feature = "no_closure")) && loop_var.is_shared() {
*loop_var.write_lock().unwrap() = value;
} else { } else {
*for_var = value; *loop_var = value;
} }
self.inc_operations(state) self.inc_operations(state)
@ -1750,8 +1762,7 @@ impl Engine {
let expr = expr.as_ref().unwrap(); let expr = expr.as_ref().unwrap();
let val = self let val = self
.eval_expr(scope, mods, state, lib, this_ptr, expr, level)? .eval_expr(scope, mods, state, lib, this_ptr, expr, level)?
.clone_inner_data() .flatten();
.unwrap();
let var_name = unsafe_cast_var_name_to_lifetime(var_name, &state); let var_name = unsafe_cast_var_name_to_lifetime(var_name, &state);
scope.push_dynamic_value(var_name, ScopeEntryType::Normal, val, false); scope.push_dynamic_value(var_name, ScopeEntryType::Normal, val, false);
Ok(Default::default()) Ok(Default::default())
@ -1769,8 +1780,7 @@ impl Engine {
let ((var_name, _), expr, _) = x.as_ref(); let ((var_name, _), expr, _) = x.as_ref();
let val = self let val = self
.eval_expr(scope, mods, state, lib, this_ptr, &expr, level)? .eval_expr(scope, mods, state, lib, this_ptr, &expr, level)?
.clone_inner_data() .flatten();
.unwrap();
let var_name = unsafe_cast_var_name_to_lifetime(var_name, &state); let var_name = unsafe_cast_var_name_to_lifetime(var_name, &state);
scope.push_dynamic_value(var_name, ScopeEntryType::Constant, val, true); scope.push_dynamic_value(var_name, ScopeEntryType::Constant, val, true);
Ok(Default::default()) Ok(Default::default())
@ -2000,6 +2010,7 @@ impl Engine {
} }
/// Map a type_name into a pretty-print name /// Map a type_name into a pretty-print name
#[inline(always)]
pub(crate) fn map_type_name<'a>(&'a self, name: &'a str) -> &'a str { pub(crate) fn map_type_name<'a>(&'a self, name: &'a str) -> &'a str {
self.type_names self.type_names
.as_ref() .as_ref()

View File

@ -925,11 +925,11 @@ impl Engine {
self.inc_operations(state) self.inc_operations(state)
.map_err(|err| err.new_position(pos))?; .map_err(|err| err.new_position(pos))?;
// Turn it into a method call only if the object is not shared
args = if target.is_shared() { args = if target.is_shared() {
arg_values.insert(0, target.clone().clone_inner_data().unwrap()); arg_values.insert(0, target.get_inner_clone());
arg_values.iter_mut().collect() arg_values.iter_mut().collect()
} else { } else {
// Turn it into a method call only if the object is not shared
is_ref = true; is_ref = true;
once(target).chain(arg_values.iter_mut()).collect() once(target).chain(arg_values.iter_mut()).collect()
}; };

View File

@ -21,13 +21,6 @@ use crate::stdlib::rc::Rc;
#[cfg(feature = "sync")] #[cfg(feature = "sync")]
use crate::stdlib::sync::Arc; use crate::stdlib::sync::Arc;
#[cfg(not(feature = "no_closure"))]
#[cfg(not(feature = "sync"))]
use crate::stdlib::cell::RefCell;
#[cfg(not(feature = "no_closure"))]
#[cfg(feature = "sync")]
use crate::stdlib::sync::RwLock;
/// Trait that maps to `Send + Sync` only under the `sync` feature. /// Trait that maps to `Send + Sync` only under the `sync` feature.
#[cfg(feature = "sync")] #[cfg(feature = "sync")]
pub trait SendSync: Send + Sync {} pub trait SendSync: Send + Sync {}
@ -49,15 +42,6 @@ pub type Shared<T> = Rc<T>;
#[cfg(feature = "sync")] #[cfg(feature = "sync")]
pub type Shared<T> = Arc<T>; pub type Shared<T> = Arc<T>;
/// Mutable reference-counted container (read-write lock)
#[cfg(not(feature = "no_closure"))]
#[cfg(not(feature = "sync"))]
pub type SharedMut<T> = Shared<RefCell<T>>;
/// Mutable reference-counted container (read-write lock)
#[cfg(not(feature = "no_closure"))]
#[cfg(feature = "sync")]
pub type SharedMut<T> = Shared<RwLock<T>>;
/// Consume a `Shared` resource and return a mutable reference to the wrapped value. /// Consume a `Shared` resource and return a mutable reference to the wrapped value.
/// If the resource is shared (i.e. has other outstanding references), a cloned copy is used. /// If the resource is shared (i.e. has other outstanding references), a cloned copy is used.
pub fn shared_make_mut<T: Clone>(value: &mut Shared<T>) -> &mut T { pub fn shared_make_mut<T: Clone>(value: &mut Shared<T>) -> &mut T {
@ -67,16 +51,21 @@ pub fn shared_make_mut<T: Clone>(value: &mut Shared<T>) -> &mut T {
return Arc::make_mut(value); return Arc::make_mut(value);
} }
/// Consume a `Shared` resource if is unique (i.e. not shared).
pub fn shared_try_take<T: Clone>(value: Shared<T>) -> Result<T, Shared<T>> {
#[cfg(not(feature = "sync"))]
return Rc::try_unwrap(value);
#[cfg(feature = "sync")]
return Arc::try_unwrap(value);
}
/// Consume a `Shared` resource, assuming that it is unique (i.e. not shared). /// Consume a `Shared` resource, assuming that it is unique (i.e. not shared).
/// ///
/// # Panics /// # Panics
/// ///
/// Panics if the resource is shared (i.e. has other outstanding references). /// Panics if the resource is shared (i.e. has other outstanding references).
pub fn shared_take<T: Clone>(value: Shared<T>) -> T { pub fn shared_take<T: Clone>(value: Shared<T>) -> T {
#[cfg(not(feature = "sync"))] shared_try_take(value).map_err(|_| ()).unwrap()
return Rc::try_unwrap(value).map_err(|_| ()).unwrap();
#[cfg(feature = "sync")]
return Arc::try_unwrap(value).map_err(|_| ()).unwrap();
} }
pub type FnCallArgs<'a> = [&'a mut Dynamic]; pub type FnCallArgs<'a> = [&'a mut Dynamic];

View File

@ -338,7 +338,7 @@ impl<'a> Scope<'a> {
/// ``` /// ```
pub fn get_value<T: Variant + Clone>(&self, name: &str) -> Option<T> { pub fn get_value<T: Variant + Clone>(&self, name: &str) -> Option<T> {
self.get_entry(name) self.get_entry(name)
.and_then(|Entry { value, .. }| value.clone().clone_inner_data::<T>()) .and_then(|Entry { value, .. }| value.get_inner_clone().try_cast())
} }
/// Update the value of the named entry. /// Update the value of the named entry.
@ -441,7 +441,7 @@ impl<'a> Scope<'a> {
/// ``` /// ```
pub fn iter(&self) -> impl Iterator<Item = (&str, Dynamic)> { pub fn iter(&self) -> impl Iterator<Item = (&str, Dynamic)> {
self.iter_raw() self.iter_raw()
.map(|(name, value)| (name, value.clone().clone_inner_data().unwrap())) .map(|(name, value)| (name, value.get_inner_clone()))
} }
/// Get an iterator to entries in the Scope. /// Get an iterator to entries in the Scope.