Avoid hard-coding variable type for shared.

This commit is contained in:
Stephen Chung 2020-08-01 22:28:13 +08:00
parent af2f8acb5d
commit cc53b21731
4 changed files with 71 additions and 86 deletions

View File

@ -160,18 +160,7 @@ pub enum Union {
FnPtr(Box<FnPtr>), FnPtr(Box<FnPtr>),
Variant(Box<Box<dyn Variant>>), Variant(Box<Box<dyn Variant>>),
#[cfg(not(feature = "no_shared"))] #[cfg(not(feature = "no_shared"))]
Shared(Box<SharedCell>), Shared(SharedMut<Dynamic>),
}
/// Internal Shared Dynamic representation.
///
/// Created with `Dynamic::into_shared()`.
#[cfg(not(feature = "no_shared"))]
#[derive(Clone)]
pub struct SharedCell {
value_type_id: TypeId,
value_type_name: &'static str,
container: SharedMut<Dynamic>,
} }
/// Underlying `Variant` read guard for `Dynamic`. /// Underlying `Variant` read guard for `Dynamic`.
@ -202,7 +191,7 @@ impl<'d, T: Variant + Clone> Deref for DynamicReadLock<'d, T> {
#[inline(always)] #[inline(always)]
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
match &self.0 { match &self.0 {
DynamicReadLockInner::Reference(reference) => reference.deref(), DynamicReadLockInner::Reference(reference) => *reference,
// Unwrapping is safe because all checking is already done in its constructor // Unwrapping is safe because all checking is already done in its constructor
#[cfg(not(feature = "no_shared"))] #[cfg(not(feature = "no_shared"))]
DynamicReadLockInner::Guard(guard) => guard.downcast_ref().unwrap(), DynamicReadLockInner::Guard(guard) => guard.downcast_ref().unwrap(),
@ -238,7 +227,7 @@ impl<'d, T: Variant + Clone> Deref for DynamicWriteLock<'d, T> {
#[inline(always)] #[inline(always)]
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
match &self.0 { match &self.0 {
DynamicWriteLockInner::Reference(reference) => reference.deref(), DynamicWriteLockInner::Reference(reference) => *reference,
// Unwrapping is safe because all checking is already done in its constructor // Unwrapping is safe because all checking is already done in its constructor
#[cfg(not(feature = "no_shared"))] #[cfg(not(feature = "no_shared"))]
DynamicWriteLockInner::Guard(guard) => guard.downcast_ref().unwrap(), DynamicWriteLockInner::Guard(guard) => guard.downcast_ref().unwrap(),
@ -250,7 +239,7 @@ impl<'d, T: Variant + Clone> DerefMut for DynamicWriteLock<'d, T> {
#[inline(always)] #[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {
match &mut self.0 { match &mut self.0 {
DynamicWriteLockInner::Reference(reference) => reference.deref_mut(), DynamicWriteLockInner::Reference(reference) => *reference,
// Unwrapping is safe because all checking is already done in its constructor // Unwrapping is safe because all checking is already done in its constructor
#[cfg(not(feature = "no_shared"))] #[cfg(not(feature = "no_shared"))]
DynamicWriteLockInner::Guard(guard) => guard.downcast_mut().unwrap(), DynamicWriteLockInner::Guard(guard) => guard.downcast_mut().unwrap(),
@ -309,7 +298,11 @@ impl Dynamic {
Union::FnPtr(_) => TypeId::of::<FnPtr>(), Union::FnPtr(_) => TypeId::of::<FnPtr>(),
Union::Variant(value) => (***value).type_id(), Union::Variant(value) => (***value).type_id(),
#[cfg(not(feature = "no_shared"))] #[cfg(not(feature = "no_shared"))]
Union::Shared(cell) => (**cell).value_type_id, #[cfg(not(feature = "sync"))]
Union::Shared(cell) => (*cell.borrow()).type_id(),
#[cfg(not(feature = "no_shared"))]
#[cfg(feature = "sync")]
Union::Shared(cell) => (*cell.read().unwrap()).type_id(),
} }
} }
@ -333,7 +326,11 @@ impl Dynamic {
Union::Variant(value) if value.is::<Instant>() => "timestamp", Union::Variant(value) if value.is::<Instant>() => "timestamp",
Union::Variant(value) => (***value).type_name(), Union::Variant(value) => (***value).type_name(),
#[cfg(not(feature = "no_shared"))] #[cfg(not(feature = "no_shared"))]
Union::Shared(cell) => (**cell).value_type_name, #[cfg(not(feature = "sync"))]
Union::Shared(cell) => (*cell.borrow()).type_name(),
#[cfg(not(feature = "no_shared"))]
#[cfg(feature = "sync")]
Union::Shared(cell) => (*cell.read().unwrap()).type_name(),
} }
} }
} }
@ -390,7 +387,7 @@ impl fmt::Display for Dynamic {
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_shared"))] #[cfg(not(feature = "no_shared"))]
Union::Shared(cell) => write!(f, "<shared {}>", (**cell).value_type_name), Union::Shared(_) => f.write_str("<shared>"),
} }
} }
} }
@ -418,7 +415,7 @@ impl fmt::Debug for Dynamic {
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_shared"))] #[cfg(not(feature = "no_shared"))]
Union::Shared(cell) => write!(f, "<shared {}>", (**cell).value_type_name), Union::Shared(_) => f.write_str("<shared>"),
} }
} }
} }
@ -569,15 +566,10 @@ impl Dynamic {
#[cfg(not(feature = "no_shared"))] #[cfg(not(feature = "no_shared"))]
return match self.0 { return match self.0 {
Union::Shared(..) => self, Union::Shared(..) => self,
_ => Self(Union::Shared(Box::new(SharedCell {
value_type_id: self.type_id(),
value_type_name: self.type_name(),
#[cfg(not(feature = "sync"))] #[cfg(not(feature = "sync"))]
container: Rc::new(RefCell::new(self)), _ => Self(Union::Shared(Rc::new(RefCell::new(self)))),
#[cfg(feature = "sync")] #[cfg(feature = "sync")]
container: Arc::new(RwLock::new(self)), _ => Self(Union::Shared(Arc::new(RwLock::new(self)))),
}))),
}; };
#[cfg(feature = "no_shared")] #[cfg(feature = "no_shared")]
@ -614,13 +606,11 @@ impl Dynamic {
match self.0 { match self.0 {
#[cfg(not(feature = "no_shared"))] #[cfg(not(feature = "no_shared"))]
#[cfg(not(feature = "sync"))] #[cfg(not(feature = "sync"))]
Union::Shared(cell) => return cell.container.borrow().deref().clone().try_cast(), Union::Shared(cell) => return cell.borrow().clone().try_cast(),
#[cfg(not(feature = "no_shared"))] #[cfg(not(feature = "no_shared"))]
#[cfg(feature = "sync")] #[cfg(feature = "sync")]
Union::Shared(cell) => { Union::Shared(cell) => return cell.read().unwrap().clone().try_cast(),
return cell.container.read().unwrap().deref().clone().try_cast()
}
_ => (), _ => (),
} }
@ -752,32 +742,11 @@ impl Dynamic {
match self.0 { match self.0 {
#[cfg(not(feature = "no_shared"))] #[cfg(not(feature = "no_shared"))]
Union::Shared(ref cell) => { Union::Shared(ref cell) => {
let type_id = TypeId::of::<T>();
if type_id != TypeId::of::<Dynamic>() && type_id != cell.value_type_id {
return None;
}
#[cfg(not(feature = "sync"))] #[cfg(not(feature = "sync"))]
return Some( return Some(cell.borrow().downcast_ref::<T>().unwrap().clone());
cell.container
.borrow()
.deref()
.downcast_ref::<T>()
.unwrap()
.clone(),
);
#[cfg(feature = "sync")] #[cfg(feature = "sync")]
return Some( return Some(cell.read().unwrap().downcast_ref::<T>().unwrap().clone());
cell.container
.read()
.unwrap()
.deref()
.downcast_ref::<T>()
.unwrap()
.clone(),
);
} }
_ => self.downcast_ref().cloned(), _ => self.downcast_ref().cloned(),
} }
@ -792,20 +761,12 @@ impl Dynamic {
match self.0 { match self.0 {
#[cfg(not(feature = "no_shared"))] #[cfg(not(feature = "no_shared"))]
Union::Shared(ref cell) => { Union::Shared(ref cell) => {
let type_id = TypeId::of::<T>();
if type_id != TypeId::of::<Dynamic>() && type_id != cell.value_type_id {
return None;
}
#[cfg(not(feature = "sync"))] #[cfg(not(feature = "sync"))]
return Some(DynamicReadLock(DynamicReadLockInner::Guard( return Some(DynamicReadLock(DynamicReadLockInner::Guard(cell.borrow())));
cell.container.borrow(),
)));
#[cfg(feature = "sync")] #[cfg(feature = "sync")]
return Some(DynamicReadLock(DynamicReadLockInner::Guard( return Some(DynamicReadLock(DynamicReadLockInner::Guard(
cell.container.read().unwrap(), cell.read().unwrap(),
))); )));
} }
_ => self _ => self
@ -823,20 +784,14 @@ impl Dynamic {
match self.0 { match self.0 {
#[cfg(not(feature = "no_shared"))] #[cfg(not(feature = "no_shared"))]
Union::Shared(ref cell) => { Union::Shared(ref cell) => {
let type_id = TypeId::of::<T>();
if type_id != TypeId::of::<Dynamic>() && cell.value_type_id != type_id {
return None;
}
#[cfg(not(feature = "sync"))] #[cfg(not(feature = "sync"))]
return Some(DynamicWriteLock(DynamicWriteLockInner::Guard( return Some(DynamicWriteLock(DynamicWriteLockInner::Guard(
cell.container.borrow_mut(), cell.borrow_mut(),
))); )));
#[cfg(feature = "sync")] #[cfg(feature = "sync")]
return Some(DynamicWriteLock(DynamicWriteLockInner::Guard( return Some(DynamicWriteLock(DynamicWriteLockInner::Guard(
cell.container.write().unwrap(), cell.write().unwrap(),
))); )));
} }
_ => self _ => self
@ -1086,16 +1041,22 @@ impl Dynamic {
#[cfg(not(feature = "no_shared"))] #[cfg(not(feature = "no_shared"))]
Union::Shared(cell) => { Union::Shared(cell) => {
#[cfg(not(feature = "sync"))] #[cfg(not(feature = "sync"))]
match &cell.container.borrow().deref().0 { {
let inner = cell.borrow();
match &inner.0 {
Union::Str(s) => Ok(s.clone()), Union::Str(s) => Ok(s.clone()),
Union::FnPtr(f) => Ok(f.clone().take_data().0), Union::FnPtr(f) => Ok(f.clone().take_data().0),
_ => Err(cell.value_type_name), _ => Err((*inner).type_name()),
}
} }
#[cfg(feature = "sync")] #[cfg(feature = "sync")]
match &cell.container.read().unwrap().deref().0 { {
let inner = cell.read().unwrap();
match &inner.0 {
Union::Str(s) => Ok(s.clone()), Union::Str(s) => Ok(s.clone()),
Union::FnPtr(f) => Ok(f.clone().take_data().0), Union::FnPtr(f) => Ok(f.clone().take_data().0),
_ => Err(cell.value_type_name), _ => Err((*inner).type_name()),
}
} }
} }
_ => Err(self.type_name()), _ => Err(self.type_name()),

View File

@ -1185,8 +1185,8 @@ pub fn run_builtin_op_assignment(
} }
if args_type == TypeId::of::<INT>() { if args_type == TypeId::of::<INT>() {
let mut x = x.write_lock::<INT>().unwrap();
let y = y.clone().cast::<INT>(); let y = y.clone().cast::<INT>();
let mut x = x.write_lock::<INT>().unwrap();
if cfg!(not(feature = "unchecked")) { if cfg!(not(feature = "unchecked")) {
match op { match op {
@ -1221,8 +1221,8 @@ pub fn run_builtin_op_assignment(
_ => (), _ => (),
} }
} else if args_type == TypeId::of::<bool>() { } else if args_type == TypeId::of::<bool>() {
let mut x = x.write_lock::<bool>().unwrap();
let y = y.clone().cast::<bool>(); let y = y.clone().cast::<bool>();
let mut x = x.write_lock::<bool>().unwrap();
match op { match op {
"&=" => return Ok(Some(*x = *x && y)), "&=" => return Ok(Some(*x = *x && y)),
@ -1230,19 +1230,19 @@ pub fn run_builtin_op_assignment(
_ => (), _ => (),
} }
} else if args_type == TypeId::of::<ImmutableString>() { } else if args_type == TypeId::of::<ImmutableString>() {
let y = y.read_lock::<ImmutableString>().unwrap().deref().clone();
let mut x = x.write_lock::<ImmutableString>().unwrap(); let mut x = x.write_lock::<ImmutableString>().unwrap();
let y = y.read_lock::<ImmutableString>().unwrap();
match op { match op {
"+=" => return Ok(Some(*x += y.deref())), "+=" => return Ok(Some(*x += y)),
_ => (), _ => (),
} }
} }
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
if args_type == TypeId::of::<FLOAT>() { if args_type == TypeId::of::<FLOAT>() {
let mut x = x.write_lock::<FLOAT>().unwrap();
let y = y.clone().cast::<FLOAT>(); let y = y.clone().cast::<FLOAT>();
let mut x = x.write_lock::<FLOAT>().unwrap();
match op { match op {
"+=" => return Ok(Some(*x += y)), "+=" => return Ok(Some(*x += y)),

View File

@ -264,6 +264,18 @@ impl AddAssign<&ImmutableString> for ImmutableString {
} }
} }
impl AddAssign<ImmutableString> for ImmutableString {
fn add_assign(&mut self, rhs: ImmutableString) {
if !rhs.is_empty() {
if self.is_empty() {
self.0 = rhs.0;
} else {
self.make_mut().push_str(rhs.0.as_str());
}
}
}
}
impl Add<&str> for ImmutableString { impl Add<&str> for ImmutableString {
type Output = Self; type Output = Self;

View File

@ -11,11 +11,23 @@ fn test_shared() -> Result<(), Box<EvalAltResult>> {
assert_eq!(engine.eval::<bool>("shared(true)")?, true); assert_eq!(engine.eval::<bool>("shared(true)")?, true);
assert_eq!(
engine.eval::<String>("let x = shared(true); type_of(x)")?,
"bool"
);
assert_eq!(
engine.eval::<String>("let x = shared(true); x = (); type_of(x)")?,
"()"
);
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
assert_eq!(engine.eval::<f64>("shared(4.2)")?, 4.2); assert_eq!(engine.eval::<f64>("shared(4.2)")?, 4.2);
assert_eq!(engine.eval::<String>(r#"shared("test")"#)?, "test"); assert_eq!(engine.eval::<String>(r#"shared("test")"#)?, "test");
assert_eq!(engine.eval::<String>(r#"shared("test")"#)?, "test");
assert_eq!(engine.eval::<char>("shared('x')")?, 'x'); assert_eq!(engine.eval::<char>("shared('x')")?, 'x');
assert!(engine.eval::<bool>("is_shared(shared(42))")?); assert!(engine.eval::<bool>("is_shared(shared(42))")?);