diff --git a/src/ast.rs b/src/ast.rs index 3d16bf68..6c04c0de 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -1419,7 +1419,7 @@ impl fmt::Debug for FnCallHashes { } impl FnCallHashes { - /// Create a [`FnCallHash`] with only the native Rust hash. + /// Create a [`FnCallHashes`] with only the native Rust hash. #[inline(always)] pub fn from_native(hash: u64) -> Self { Self { @@ -1427,7 +1427,7 @@ impl FnCallHashes { native: hash, } } - /// Create a [`FnCallHash`] with both native Rust and script function hashes set to the same value. + /// Create a [`FnCallHashes`] with both native Rust and script function hashes set to the same value. #[inline(always)] pub fn from_script(hash: u64) -> Self { Self { @@ -1435,7 +1435,7 @@ impl FnCallHashes { native: hash, } } - /// Create a [`FnCallHash`] with both native Rust and script function hashes. + /// Create a [`FnCallHashes`] with both native Rust and script function hashes. #[inline(always)] pub fn from_script_and_native(script: u64, native: u64) -> Self { Self { @@ -1443,21 +1443,21 @@ impl FnCallHashes { native, } } - /// Is this [`FnCallHash`] native Rust only? + /// Is this [`FnCallHashes`] native Rust only? #[inline(always)] pub fn is_native_only(&self) -> bool { self.script.is_none() } - /// Get the script function hash from this [`FnCallHash`]. + /// Get the script function hash from this [`FnCallHashes`]. /// /// # Panics /// - /// Panics if the [`FnCallHash`] is native Rust only. + /// Panics if the [`FnCallHashes`] is native Rust only. #[inline(always)] pub fn script_hash(&self) -> u64 { self.script.unwrap() } - /// Get the naive Rust function hash from this [`FnCallHash`]. + /// Get the naive Rust function hash from this [`FnCallHashes`]. #[inline(always)] pub fn native_hash(&self) -> u64 { self.native diff --git a/src/dynamic.rs b/src/dynamic.rs index 2414d31f..d58e9d60 100644 --- a/src/dynamic.rs +++ b/src/dynamic.rs @@ -140,6 +140,12 @@ pub enum AccessMode { ReadOnly, } +/// Arbitrary data attached to a [`Dynamic`] value. +pub type Tag = i16; + +/// Default tag value for [`Dynamic`]. +const DEFAULT_TAG: Tag = 0; + /// Dynamic type containing any value. pub struct Dynamic(pub(crate) Union); @@ -148,39 +154,39 @@ pub struct Dynamic(pub(crate) Union); /// Most variants are boxed to reduce the size. pub enum Union { /// The Unit value - (). - Unit((), AccessMode), + Unit((), Tag, AccessMode), /// A boolean value. - Bool(bool, AccessMode), + Bool(bool, Tag, AccessMode), /// An [`ImmutableString`] value. - Str(ImmutableString, AccessMode), + Str(ImmutableString, Tag, AccessMode), /// A character value. - Char(char, AccessMode), + Char(char, Tag, AccessMode), /// An integer value. - Int(INT, AccessMode), + Int(INT, Tag, AccessMode), /// A floating-point value. #[cfg(not(feature = "no_float"))] - Float(FloatWrapper, AccessMode), + Float(FloatWrapper, Tag, AccessMode), /// A fixed-precision decimal value. #[cfg(feature = "decimal")] - Decimal(Box, AccessMode), + Decimal(Box, Tag, AccessMode), /// An array value. #[cfg(not(feature = "no_index"))] - Array(Box, AccessMode), + Array(Box, Tag, AccessMode), /// An object map value. #[cfg(not(feature = "no_object"))] - Map(Box, AccessMode), + Map(Box, Tag, AccessMode), /// A function pointer. - FnPtr(Box, AccessMode), + FnPtr(Box, Tag, AccessMode), /// A timestamp value. #[cfg(not(feature = "no_std"))] - TimeStamp(Box, AccessMode), + TimeStamp(Box, Tag, AccessMode), /// Any type as a trait object. - Variant(Box>, AccessMode), + Variant(Box>, Tag, AccessMode), /// A _shared_ value of any type. #[cfg(not(feature = "no_closure"))] - Shared(crate::Shared>, AccessMode), + Shared(crate::Shared>, Tag, AccessMode), } /// Underlying [`Variant`] read guard for [`Dynamic`]. @@ -270,12 +276,62 @@ impl<'d, T: Any + Clone> DerefMut for DynamicWriteLock<'d, T> { } impl Dynamic { + /// Get the arbitrary data attached to this [`Dynamic`]. + pub fn tag(&self) -> Tag { + match self.0 { + Union::Unit(_, tag, _) + | Union::Bool(_, tag, _) + | Union::Str(_, tag, _) + | Union::Char(_, tag, _) + | Union::Int(_, tag, _) + | Union::FnPtr(_, tag, _) + | Union::Variant(_, tag, _) => tag, + + #[cfg(not(feature = "no_float"))] + Union::Float(_, tag, _) => tag, + #[cfg(feature = "decimal")] + Union::Decimal(_, tag, _) => tag, + #[cfg(not(feature = "no_index"))] + Union::Array(_, tag, _) => tag, + #[cfg(not(feature = "no_object"))] + Union::Map(_, tag, _) => tag, + #[cfg(not(feature = "no_std"))] + Union::TimeStamp(_, tag, _) => tag, + #[cfg(not(feature = "no_closure"))] + Union::Shared(_, tag, _) => tag, + } + } + /// Attach arbitrary data to this [`Dynamic`]. + pub fn set_tag(&mut self, value: Tag) { + match &mut self.0 { + Union::Unit(_, tag, _) + | Union::Bool(_, tag, _) + | Union::Str(_, tag, _) + | Union::Char(_, tag, _) + | Union::Int(_, tag, _) + | Union::FnPtr(_, tag, _) + | Union::Variant(_, tag, _) => *tag = value, + + #[cfg(not(feature = "no_float"))] + Union::Float(_, tag, _) => *tag = value, + #[cfg(feature = "decimal")] + Union::Decimal(_, tag, _) => *tag = value, + #[cfg(not(feature = "no_index"))] + Union::Array(_, tag, _) => *tag = value, + #[cfg(not(feature = "no_object"))] + Union::Map(_, tag, _) => *tag = value, + #[cfg(not(feature = "no_std"))] + Union::TimeStamp(_, tag, _) => *tag = value, + #[cfg(not(feature = "no_closure"))] + Union::Shared(_, tag, _) => *tag = value, + } + } /// Does this [`Dynamic`] hold a variant data type /// instead of one of the supported system primitive types? #[inline(always)] pub fn is_variant(&self) -> bool { match self.0 { - Union::Variant(_, _) => true, + Union::Variant(_, _, _) => true, _ => false, } } @@ -287,7 +343,7 @@ impl Dynamic { pub fn is_shared(&self) -> bool { #[cfg(not(feature = "no_closure"))] match self.0 { - Union::Shared(_, _) => return true, + Union::Shared(_, _, _) => return true, _ => (), } @@ -315,27 +371,27 @@ impl Dynamic { /// Otherwise, this call panics if the data is currently borrowed for write. pub fn type_id(&self) -> TypeId { match &self.0 { - Union::Unit(_, _) => TypeId::of::<()>(), - Union::Bool(_, _) => TypeId::of::(), - Union::Str(_, _) => TypeId::of::(), - Union::Char(_, _) => TypeId::of::(), - Union::Int(_, _) => TypeId::of::(), + Union::Unit(_, _, _) => TypeId::of::<()>(), + Union::Bool(_, _, _) => TypeId::of::(), + Union::Str(_, _, _) => TypeId::of::(), + Union::Char(_, _, _) => TypeId::of::(), + Union::Int(_, _, _) => TypeId::of::(), #[cfg(not(feature = "no_float"))] - Union::Float(_, _) => TypeId::of::(), + Union::Float(_, _, _) => TypeId::of::(), #[cfg(feature = "decimal")] - Union::Decimal(_, _) => TypeId::of::(), + Union::Decimal(_, _, _) => TypeId::of::(), #[cfg(not(feature = "no_index"))] - Union::Array(_, _) => TypeId::of::(), + Union::Array(_, _, _) => TypeId::of::(), #[cfg(not(feature = "no_object"))] - Union::Map(_, _) => TypeId::of::(), - Union::FnPtr(_, _) => TypeId::of::(), + Union::Map(_, _, _) => TypeId::of::(), + Union::FnPtr(_, _, _) => TypeId::of::(), #[cfg(not(feature = "no_std"))] - Union::TimeStamp(_, _) => TypeId::of::(), + Union::TimeStamp(_, _, _) => TypeId::of::(), - Union::Variant(value, _) => (***value).type_id(), + Union::Variant(value, _, _) => (***value).type_id(), #[cfg(not(feature = "no_closure"))] - Union::Shared(cell, _) => { + Union::Shared(cell, _, _) => { #[cfg(not(feature = "sync"))] let value = cell.borrow(); #[cfg(feature = "sync")] @@ -353,34 +409,34 @@ impl Dynamic { /// Otherwise, this call panics if the data is currently borrowed for write. pub fn type_name(&self) -> &'static str { match &self.0 { - Union::Unit(_, _) => "()", - Union::Bool(_, _) => "bool", - Union::Str(_, _) => "string", - Union::Char(_, _) => "char", - Union::Int(_, _) => type_name::(), + Union::Unit(_, _, _) => "()", + Union::Bool(_, _, _) => "bool", + Union::Str(_, _, _) => "string", + Union::Char(_, _, _) => "char", + Union::Int(_, _, _) => type_name::(), #[cfg(not(feature = "no_float"))] - Union::Float(_, _) => type_name::(), + Union::Float(_, _, _) => type_name::(), #[cfg(feature = "decimal")] - Union::Decimal(_, _) => "decimal", + Union::Decimal(_, _, _) => "decimal", #[cfg(not(feature = "no_index"))] - Union::Array(_, _) => "array", + Union::Array(_, _, _) => "array", #[cfg(not(feature = "no_object"))] - Union::Map(_, _) => "map", - Union::FnPtr(_, _) => "Fn", + Union::Map(_, _, _) => "map", + Union::FnPtr(_, _, _) => "Fn", #[cfg(not(feature = "no_std"))] - Union::TimeStamp(_, _) => "timestamp", + Union::TimeStamp(_, _, _) => "timestamp", - Union::Variant(value, _) => (***value).type_name(), + Union::Variant(value, _, _) => (***value).type_name(), #[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "sync"))] - Union::Shared(cell, _) => cell + Union::Shared(cell, _, _) => cell .try_borrow() .map(|v| (*v).type_name()) .unwrap_or(""), #[cfg(not(feature = "no_closure"))] #[cfg(feature = "sync")] - Union::Shared(cell, _) => (*cell.read().unwrap()).type_name(), + Union::Shared(cell, _, _) => (*cell.read().unwrap()).type_name(), } } } @@ -388,17 +444,17 @@ impl Dynamic { impl Hash for Dynamic { fn hash(&self, state: &mut H) { match &self.0 { - Union::Unit(_, _) => ().hash(state), - Union::Bool(value, _) => value.hash(state), - Union::Str(s, _) => s.hash(state), - Union::Char(ch, _) => ch.hash(state), - Union::Int(i, _) => i.hash(state), + Union::Unit(_, _, _) => ().hash(state), + Union::Bool(value, _, _) => value.hash(state), + Union::Str(s, _, _) => s.hash(state), + Union::Char(ch, _, _) => ch.hash(state), + Union::Int(i, _, _) => i.hash(state), #[cfg(not(feature = "no_float"))] - Union::Float(f, _) => f.hash(state), + Union::Float(f, _, _) => f.hash(state), #[cfg(not(feature = "no_index"))] - Union::Array(a, _) => (**a).hash(state), + Union::Array(a, _, _) => (**a).hash(state), #[cfg(not(feature = "no_object"))] - Union::Map(m, _) => { + Union::Map(m, _, _) => { let mut buf: crate::StaticVec<_> = m.iter().collect(); buf.sort_by(|(a, _), (b, _)| a.cmp(b)); @@ -407,16 +463,16 @@ impl Hash for Dynamic { value.hash(state); }) } - Union::FnPtr(f, _) if f.is_curried() => { + Union::FnPtr(f, _, _) if f.is_curried() => { unimplemented!( "{} with curried arguments cannot be hashed", self.type_name() ) } - Union::FnPtr(f, _) => f.fn_name().hash(state), + Union::FnPtr(f, _, _) => f.fn_name().hash(state), #[cfg(not(feature = "no_closure"))] - Union::Shared(cell, _) => { + Union::Shared(cell, _, _) => { #[cfg(not(feature = "sync"))] let value = cell.borrow(); #[cfg(feature = "sync")] @@ -468,27 +524,27 @@ pub(crate) fn map_std_type_name(name: &str) -> &str { impl fmt::Display for Dynamic { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.0 { - Union::Unit(_, _) => write!(f, ""), - Union::Bool(value, _) => fmt::Display::fmt(value, f), - Union::Str(value, _) => fmt::Display::fmt(value, f), - Union::Char(value, _) => fmt::Display::fmt(value, f), - Union::Int(value, _) => fmt::Display::fmt(value, f), + Union::Unit(_, _, _) => write!(f, ""), + Union::Bool(value, _, _) => fmt::Display::fmt(value, f), + Union::Str(value, _, _) => fmt::Display::fmt(value, f), + Union::Char(value, _, _) => fmt::Display::fmt(value, f), + Union::Int(value, _, _) => fmt::Display::fmt(value, f), #[cfg(not(feature = "no_float"))] - Union::Float(value, _) => fmt::Display::fmt(value, f), + Union::Float(value, _, _) => fmt::Display::fmt(value, f), #[cfg(feature = "decimal")] - Union::Decimal(value, _) => fmt::Display::fmt(value, f), + Union::Decimal(value, _, _) => fmt::Display::fmt(value, f), #[cfg(not(feature = "no_index"))] - Union::Array(value, _) => fmt::Debug::fmt(value, f), + Union::Array(value, _, _) => fmt::Debug::fmt(value, f), #[cfg(not(feature = "no_object"))] - Union::Map(value, _) => { + Union::Map(value, _, _) => { f.write_str("#")?; fmt::Debug::fmt(value, f) } - Union::FnPtr(value, _) => fmt::Display::fmt(value, f), + Union::FnPtr(value, _, _) => fmt::Display::fmt(value, f), #[cfg(not(feature = "no_std"))] - Union::TimeStamp(_, _) => f.write_str(""), + Union::TimeStamp(_, _, _) => f.write_str(""), - Union::Variant(value, _) => { + Union::Variant(value, _, _) => { let _type_id = (***value).type_id(); #[cfg(not(feature = "only_i32"))] @@ -530,7 +586,7 @@ impl fmt::Display for Dynamic { #[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "sync"))] - Union::Shared(cell, _) => { + Union::Shared(cell, _, _) => { if let Ok(v) = cell.try_borrow() { fmt::Display::fmt(&*v, f) } else { @@ -539,7 +595,7 @@ impl fmt::Display for Dynamic { } #[cfg(not(feature = "no_closure"))] #[cfg(feature = "sync")] - Union::Shared(cell, _) => fmt::Display::fmt(&*cell.read().unwrap(), f), + Union::Shared(cell, _, _) => fmt::Display::fmt(&*cell.read().unwrap(), f), } } } @@ -547,27 +603,27 @@ impl fmt::Display for Dynamic { impl fmt::Debug for Dynamic { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.0 { - Union::Unit(value, _) => fmt::Debug::fmt(value, f), - Union::Bool(value, _) => fmt::Debug::fmt(value, f), - Union::Str(value, _) => fmt::Debug::fmt(value, f), - Union::Char(value, _) => fmt::Debug::fmt(value, f), - Union::Int(value, _) => fmt::Debug::fmt(value, f), + Union::Unit(value, _, _) => fmt::Debug::fmt(value, f), + Union::Bool(value, _, _) => fmt::Debug::fmt(value, f), + Union::Str(value, _, _) => fmt::Debug::fmt(value, f), + Union::Char(value, _, _) => fmt::Debug::fmt(value, f), + Union::Int(value, _, _) => fmt::Debug::fmt(value, f), #[cfg(not(feature = "no_float"))] - Union::Float(value, _) => fmt::Debug::fmt(value, f), + Union::Float(value, _, _) => fmt::Debug::fmt(value, f), #[cfg(feature = "decimal")] - Union::Decimal(value, _) => fmt::Debug::fmt(value, f), + Union::Decimal(value, _, _) => fmt::Debug::fmt(value, f), #[cfg(not(feature = "no_index"))] - Union::Array(value, _) => fmt::Debug::fmt(value, f), + Union::Array(value, _, _) => fmt::Debug::fmt(value, f), #[cfg(not(feature = "no_object"))] - Union::Map(value, _) => { + Union::Map(value, _, _) => { f.write_str("#")?; fmt::Debug::fmt(value, f) } - Union::FnPtr(value, _) => fmt::Debug::fmt(value, f), + Union::FnPtr(value, _, _) => fmt::Debug::fmt(value, f), #[cfg(not(feature = "no_std"))] - Union::TimeStamp(_, _) => write!(f, ""), + Union::TimeStamp(_, _, _) => write!(f, ""), - Union::Variant(value, _) => { + Union::Variant(value, _, _) => { let _type_id = (***value).type_id(); #[cfg(not(feature = "only_i32"))] @@ -617,7 +673,7 @@ impl fmt::Debug for Dynamic { #[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "sync"))] - Union::Shared(cell, _) => { + Union::Shared(cell, _, _) => { if let Ok(v) = cell.try_borrow() { write!(f, "{:?} (shared)", *v) } else { @@ -626,7 +682,7 @@ impl fmt::Debug for Dynamic { } #[cfg(not(feature = "no_closure"))] #[cfg(feature = "sync")] - Union::Shared(cell, _) => fmt::Debug::fmt(&*cell.read().unwrap(), f), + Union::Shared(cell, _, _) => fmt::Debug::fmt(&*cell.read().unwrap(), f), } } } @@ -639,31 +695,45 @@ impl Clone for Dynamic { /// The cloned copy is marked read-write even if the original is read-only. fn clone(&self) -> Self { match self.0 { - Union::Unit(value, _) => Self(Union::Unit(value, AccessMode::ReadWrite)), - Union::Bool(value, _) => Self(Union::Bool(value, AccessMode::ReadWrite)), - Union::Str(ref value, _) => Self(Union::Str(value.clone(), AccessMode::ReadWrite)), - Union::Char(value, _) => Self(Union::Char(value, AccessMode::ReadWrite)), - Union::Int(value, _) => Self(Union::Int(value, AccessMode::ReadWrite)), + Union::Unit(value, tag, _) => Self(Union::Unit(value, tag, AccessMode::ReadWrite)), + Union::Bool(value, tag, _) => Self(Union::Bool(value, tag, AccessMode::ReadWrite)), + Union::Str(ref value, tag, _) => { + Self(Union::Str(value.clone(), tag, AccessMode::ReadWrite)) + } + Union::Char(value, tag, _) => Self(Union::Char(value, tag, AccessMode::ReadWrite)), + Union::Int(value, tag, _) => Self(Union::Int(value, tag, AccessMode::ReadWrite)), #[cfg(not(feature = "no_float"))] - Union::Float(value, _) => Self(Union::Float(value, AccessMode::ReadWrite)), + Union::Float(value, tag, _) => Self(Union::Float(value, tag, AccessMode::ReadWrite)), #[cfg(feature = "decimal")] - Union::Decimal(ref value, _) => { - Self(Union::Decimal(value.clone(), AccessMode::ReadWrite)) + Union::Decimal(ref value, _, _) => { + Self(Union::Decimal(value.clone(), tag, AccessMode::ReadWrite)) } #[cfg(not(feature = "no_index"))] - Union::Array(ref value, _) => Self(Union::Array(value.clone(), AccessMode::ReadWrite)), + Union::Array(ref value, tag, _) => { + Self(Union::Array(value.clone(), tag, AccessMode::ReadWrite)) + } #[cfg(not(feature = "no_object"))] - Union::Map(ref value, _) => Self(Union::Map(value.clone(), AccessMode::ReadWrite)), - Union::FnPtr(ref value, _) => Self(Union::FnPtr(value.clone(), AccessMode::ReadWrite)), + Union::Map(ref value, tag, _) => { + Self(Union::Map(value.clone(), tag, AccessMode::ReadWrite)) + } + Union::FnPtr(ref value, tag, _) => { + Self(Union::FnPtr(value.clone(), tag, AccessMode::ReadWrite)) + } #[cfg(not(feature = "no_std"))] - Union::TimeStamp(ref value, _) => { - Self(Union::TimeStamp(value.clone(), AccessMode::ReadWrite)) + Union::TimeStamp(ref value, tag, _) => { + Self(Union::TimeStamp(value.clone(), tag, AccessMode::ReadWrite)) } - Union::Variant(ref value, _) => (***value).clone_into_dynamic(), + Union::Variant(ref value, tag, _) => { + let mut x = (***value).clone_into_dynamic(); + x.set_tag(tag); + x + } #[cfg(not(feature = "no_closure"))] - Union::Shared(ref cell, _) => Self(Union::Shared(cell.clone(), AccessMode::ReadWrite)), + Union::Shared(ref cell, tag, _) => { + Self(Union::Shared(cell.clone(), tag, AccessMode::ReadWrite)) + } } } } @@ -677,84 +747,87 @@ impl Default for Dynamic { impl Dynamic { /// A [`Dynamic`] containing a `()`. - pub const UNIT: Dynamic = Self(Union::Unit((), AccessMode::ReadWrite)); + pub const UNIT: Dynamic = Self(Union::Unit((), DEFAULT_TAG, AccessMode::ReadWrite)); /// A [`Dynamic`] containing a `true`. - pub const TRUE: Dynamic = Self(Union::Bool(true, AccessMode::ReadWrite)); + pub const TRUE: Dynamic = Self(Union::Bool(true, DEFAULT_TAG, AccessMode::ReadWrite)); /// A [`Dynamic`] containing a [`false`]. - pub const FALSE: Dynamic = Self(Union::Bool(false, AccessMode::ReadWrite)); + pub const FALSE: Dynamic = Self(Union::Bool(false, DEFAULT_TAG, AccessMode::ReadWrite)); /// A [`Dynamic`] containing the integer zero. - pub const ZERO: Dynamic = Self(Union::Int(0, AccessMode::ReadWrite)); + pub const ZERO: Dynamic = Self(Union::Int(0, DEFAULT_TAG, AccessMode::ReadWrite)); /// A [`Dynamic`] containing the integer one. - pub const ONE: Dynamic = Self(Union::Int(1, AccessMode::ReadWrite)); + pub const ONE: Dynamic = Self(Union::Int(1, DEFAULT_TAG, AccessMode::ReadWrite)); /// A [`Dynamic`] containing the integer negative one. - pub const NEGATIVE_ONE: Dynamic = Self(Union::Int(-1, AccessMode::ReadWrite)); + pub const NEGATIVE_ONE: Dynamic = Self(Union::Int(-1, DEFAULT_TAG, AccessMode::ReadWrite)); /// A [`Dynamic`] containing the floating-point zero. #[cfg(not(feature = "no_float"))] pub const FLOAT_ZERO: Dynamic = Self(Union::Float( FloatWrapper::const_new(0.0), + DEFAULT_TAG, AccessMode::ReadWrite, )); /// A [`Dynamic`] containing the floating-point one. #[cfg(not(feature = "no_float"))] pub const FLOAT_ONE: Dynamic = Self(Union::Float( FloatWrapper::const_new(1.0), + DEFAULT_TAG, AccessMode::ReadWrite, )); /// A [`Dynamic`] containing the floating-point negative one. #[cfg(not(feature = "no_float"))] pub const FLOAT_NEGATIVE_ONE: Dynamic = Self(Union::Float( FloatWrapper::const_new(-1.0), + DEFAULT_TAG, AccessMode::ReadWrite, )); /// Get the [`AccessMode`] for this [`Dynamic`]. pub(crate) fn access_mode(&self) -> AccessMode { match self.0 { - Union::Unit(_, access) - | Union::Bool(_, access) - | Union::Str(_, access) - | Union::Char(_, access) - | Union::Int(_, access) - | Union::FnPtr(_, access) - | Union::Variant(_, access) => access, + Union::Unit(_, _, access) + | Union::Bool(_, _, access) + | Union::Str(_, _, access) + | Union::Char(_, _, access) + | Union::Int(_, _, access) + | Union::FnPtr(_, _, access) + | Union::Variant(_, _, access) => access, #[cfg(not(feature = "no_float"))] - Union::Float(_, access) => access, + Union::Float(_, _, access) => access, #[cfg(feature = "decimal")] - Union::Decimal(_, access) => access, + Union::Decimal(_, _, access) => access, #[cfg(not(feature = "no_index"))] - Union::Array(_, access) => access, + Union::Array(_, _, access) => access, #[cfg(not(feature = "no_object"))] - Union::Map(_, access) => access, + Union::Map(_, _, access) => access, #[cfg(not(feature = "no_std"))] - Union::TimeStamp(_, access) => access, + Union::TimeStamp(_, _, access) => access, #[cfg(not(feature = "no_closure"))] - Union::Shared(_, access) => access, + Union::Shared(_, _, access) => access, } } /// Set the [`AccessMode`] for this [`Dynamic`]. pub(crate) fn set_access_mode(&mut self, typ: AccessMode) { match &mut self.0 { - Union::Unit(_, access) - | Union::Bool(_, access) - | Union::Str(_, access) - | Union::Char(_, access) - | Union::Int(_, access) - | Union::FnPtr(_, access) - | Union::Variant(_, access) => *access = typ, + Union::Unit(_, _, access) + | Union::Bool(_, _, access) + | Union::Str(_, _, access) + | Union::Char(_, _, access) + | Union::Int(_, _, access) + | Union::FnPtr(_, _, access) + | Union::Variant(_, _, access) => *access = typ, #[cfg(not(feature = "no_float"))] - Union::Float(_, access) => *access = typ, + Union::Float(_, _, access) => *access = typ, #[cfg(feature = "decimal")] - Union::Decimal(_, access) => *access = typ, + Union::Decimal(_, _, access) => *access = typ, #[cfg(not(feature = "no_index"))] - Union::Array(_, access) => *access = typ, + Union::Array(_, _, access) => *access = typ, #[cfg(not(feature = "no_object"))] - Union::Map(_, access) => *access = typ, + Union::Map(_, _, access) => *access = typ, #[cfg(not(feature = "no_std"))] - Union::TimeStamp(_, access) => *access = typ, + Union::TimeStamp(_, _, access) => *access = typ, #[cfg(not(feature = "no_closure"))] - Union::Shared(_, access) => *access = typ, + Union::Shared(_, _, access) => *access = typ, } } /// Is this [`Dynamic`] read-only? @@ -767,8 +840,8 @@ impl Dynamic { pub fn is_read_only(&self) -> bool { #[cfg(not(feature = "no_closure"))] match self.0 { - Union::Shared(_, AccessMode::ReadOnly) => return true, - Union::Shared(ref cell, _) => { + Union::Shared(_, _, AccessMode::ReadOnly) => return true, + Union::Shared(ref cell, _, _) => { #[cfg(not(feature = "sync"))] let value = cell.borrow(); #[cfg(feature = "sync")] @@ -790,21 +863,21 @@ impl Dynamic { /// Can this [`Dynamic`] be hashed? pub(crate) fn is_hashable(&self) -> bool { match &self.0 { - Union::Unit(_, _) - | Union::Bool(_, _) - | Union::Str(_, _) - | Union::Char(_, _) - | Union::Int(_, _) => true, + Union::Unit(_, _, _) + | Union::Bool(_, _, _) + | Union::Str(_, _, _) + | Union::Char(_, _, _) + | Union::Int(_, _, _) => true, #[cfg(not(feature = "no_float"))] - Union::Float(_, _) => true, + Union::Float(_, _, _) => true, #[cfg(not(feature = "no_index"))] - Union::Array(_, _) => true, + Union::Array(_, _, _) => true, #[cfg(not(feature = "no_object"))] - Union::Map(_, _) => true, + Union::Map(_, _, _) => true, #[cfg(not(feature = "no_closure"))] - Union::Shared(cell, _) => { + Union::Shared(cell, _, _) => { #[cfg(not(feature = "sync"))] let value = cell.borrow(); #[cfg(feature = "sync")] @@ -945,6 +1018,7 @@ impl Dynamic { Self(Union::Variant( Box::new(Box::new(value)), + DEFAULT_TAG, AccessMode::ReadWrite, )) } @@ -968,8 +1042,12 @@ impl Dynamic { let _access = self.access_mode(); match self.0 { - Union::Shared(_, _) => self, - _ => Self(Union::Shared(crate::Locked::new(self).into(), _access)), + Union::Shared(_, _, _) => self, + _ => Self(Union::Shared( + crate::Locked::new(self).into(), + DEFAULT_TAG, + _access, + )), } } /// Convert the [`Dynamic`] value into specific type. @@ -1000,7 +1078,7 @@ impl Dynamic { // Coded this way in order to maximally leverage potentials for dead-code removal. #[cfg(not(feature = "no_closure"))] - if let Union::Shared(_, _) = self.0 { + if let Union::Shared(_, _, _) = self.0 { return self.flatten().try_cast::(); } @@ -1010,7 +1088,7 @@ impl Dynamic { if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Int(value, _) => unsafe_try_cast(value).ok(), + Union::Int(value, _, _) => unsafe_try_cast(value).ok(), _ => None, }; } @@ -1018,7 +1096,7 @@ impl Dynamic { #[cfg(not(feature = "no_float"))] if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Float(value, _) => unsafe_try_cast(*value).ok(), + Union::Float(value, _, _) => unsafe_try_cast(*value).ok(), _ => None, }; } @@ -1026,35 +1104,35 @@ impl Dynamic { #[cfg(feature = "decimal")] if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Decimal(value, _) => unsafe_try_cast(*value).ok(), + Union::Decimal(value, _, _) => unsafe_try_cast(*value).ok(), _ => None, }; } if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Bool(value, _) => unsafe_try_cast(value).ok(), + Union::Bool(value, _, _) => unsafe_try_cast(value).ok(), _ => None, }; } if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Str(value, _) => unsafe_try_cast(value).ok(), + Union::Str(value, _, _) => unsafe_try_cast(value).ok(), _ => None, }; } if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Str(value, _) => unsafe_try_cast(value.into_owned()).ok(), + Union::Str(value, _, _) => unsafe_try_cast(value.into_owned()).ok(), _ => None, }; } if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Char(value, _) => unsafe_try_cast(value).ok(), + Union::Char(value, _, _) => unsafe_try_cast(value).ok(), _ => None, }; } @@ -1062,7 +1140,7 @@ impl Dynamic { #[cfg(not(feature = "no_index"))] if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Array(value, _) => unsafe_cast_box::<_, T>(value).ok().map(|v| *v), + Union::Array(value, _, _) => unsafe_cast_box::<_, T>(value).ok().map(|v| *v), _ => None, }; } @@ -1070,14 +1148,14 @@ impl Dynamic { #[cfg(not(feature = "no_object"))] if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Map(value, _) => unsafe_cast_box::<_, T>(value).ok().map(|v| *v), + Union::Map(value, _, _) => unsafe_cast_box::<_, T>(value).ok().map(|v| *v), _ => None, }; } if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::FnPtr(value, _) => unsafe_cast_box::<_, T>(value).ok().map(|v| *v), + Union::FnPtr(value, _, _) => unsafe_cast_box::<_, T>(value).ok().map(|v| *v), _ => None, }; } @@ -1085,22 +1163,22 @@ impl Dynamic { #[cfg(not(feature = "no_std"))] if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::TimeStamp(value, _) => unsafe_cast_box::<_, T>(value).ok().map(|v| *v), + Union::TimeStamp(value, _, _) => unsafe_cast_box::<_, T>(value).ok().map(|v| *v), _ => None, }; } if TypeId::of::() == TypeId::of::<()>() { return match self.0 { - Union::Unit(value, _) => unsafe_try_cast(value).ok(), + Union::Unit(value, _, _) => unsafe_try_cast(value).ok(), _ => None, }; } match self.0 { - Union::Variant(value, _) => (*value).as_box_any().downcast().map(|x| *x).ok(), + Union::Variant(value, _, _) => (*value).as_box_any().downcast().map(|x| *x).ok(), #[cfg(not(feature = "no_closure"))] - Union::Shared(_, _) => unreachable!("Union::Shared case should be already handled"), + Union::Shared(_, _, _) => unreachable!("Union::Shared case should be already handled"), _ => None, } } @@ -1190,7 +1268,7 @@ impl Dynamic { pub fn flatten_clone(&self) -> Self { #[cfg(not(feature = "no_closure"))] match &self.0 { - Union::Shared(cell, _) => { + Union::Shared(cell, _, _) => { #[cfg(not(feature = "sync"))] let value = cell.borrow(); #[cfg(feature = "sync")] @@ -1213,7 +1291,7 @@ impl Dynamic { pub fn flatten(self) -> Self { #[cfg(not(feature = "no_closure"))] match self.0 { - Union::Shared(cell, _) => { + Union::Shared(cell, _, _) => { return crate::fn_native::shared_try_take(cell).map_or_else( |cell| { #[cfg(not(feature = "sync"))] @@ -1246,8 +1324,8 @@ impl Dynamic { pub(crate) fn flatten_in_place(&mut self) { #[cfg(not(feature = "no_closure"))] match self.0 { - Union::Shared(_, _) => match std::mem::take(self).0 { - Union::Shared(cell, _) => { + Union::Shared(_, _, _) => match std::mem::take(self).0 { + Union::Shared(cell, _, _) => { *self = crate::fn_native::shared_try_take(cell).map_or_else( |cell| { #[cfg(not(feature = "sync"))] @@ -1284,7 +1362,7 @@ impl Dynamic { pub fn is_locked(&self) -> bool { #[cfg(not(feature = "no_closure"))] match self.0 { - Union::Shared(ref _cell, _) => { + Union::Shared(ref _cell, _, _) => { #[cfg(not(feature = "sync"))] return _cell.try_borrow().is_err(); @@ -1309,7 +1387,7 @@ impl Dynamic { pub fn read_lock(&self) -> Option> { match self.0 { #[cfg(not(feature = "no_closure"))] - Union::Shared(ref cell, _) => { + Union::Shared(ref cell, _, _) => { #[cfg(not(feature = "sync"))] let value = cell.borrow(); #[cfg(feature = "sync")] @@ -1342,7 +1420,7 @@ impl Dynamic { pub fn write_lock(&mut self) -> Option> { match self.0 { #[cfg(not(feature = "no_closure"))] - Union::Shared(ref cell, _) => { + Union::Shared(ref cell, _, _) => { #[cfg(not(feature = "sync"))] let value = cell.borrow_mut(); #[cfg(feature = "sync")] @@ -1372,72 +1450,72 @@ impl Dynamic { if TypeId::of::() == TypeId::of::() { return match &self.0 { - Union::Int(value, _) => ::downcast_ref::(value), + Union::Int(value, _, _) => ::downcast_ref::(value), _ => None, }; } #[cfg(not(feature = "no_float"))] if TypeId::of::() == TypeId::of::() { return match &self.0 { - Union::Float(value, _) => ::downcast_ref::(value.as_ref()), + Union::Float(value, _, _) => ::downcast_ref::(value.as_ref()), _ => None, }; } #[cfg(feature = "decimal")] if TypeId::of::() == TypeId::of::() { return match &self.0 { - Union::Decimal(value, _) => ::downcast_ref::(value.as_ref()), + Union::Decimal(value, _, _) => ::downcast_ref::(value.as_ref()), _ => None, }; } if TypeId::of::() == TypeId::of::() { return match &self.0 { - Union::Bool(value, _) => ::downcast_ref::(value), + Union::Bool(value, _, _) => ::downcast_ref::(value), _ => None, }; } if TypeId::of::() == TypeId::of::() { return match &self.0 { - Union::Str(value, _) => ::downcast_ref::(value), + Union::Str(value, _, _) => ::downcast_ref::(value), _ => None, }; } if TypeId::of::() == TypeId::of::() { return match &self.0 { - Union::Char(value, _) => ::downcast_ref::(value), + Union::Char(value, _, _) => ::downcast_ref::(value), _ => None, }; } #[cfg(not(feature = "no_index"))] if TypeId::of::() == TypeId::of::() { return match &self.0 { - Union::Array(value, _) => ::downcast_ref::(value.as_ref()), + Union::Array(value, _, _) => ::downcast_ref::(value.as_ref()), _ => None, }; } #[cfg(not(feature = "no_object"))] if TypeId::of::() == TypeId::of::() { return match &self.0 { - Union::Map(value, _) => ::downcast_ref::(value.as_ref()), + Union::Map(value, _, _) => ::downcast_ref::(value.as_ref()), _ => None, }; } if TypeId::of::() == TypeId::of::() { return match &self.0 { - Union::FnPtr(value, _) => ::downcast_ref::(value.as_ref()), + Union::FnPtr(value, _, _) => ::downcast_ref::(value.as_ref()), _ => None, }; } #[cfg(not(feature = "no_std"))] if TypeId::of::() == TypeId::of::() { return match &self.0 { - Union::TimeStamp(value, _) => ::downcast_ref::(value.as_ref()), + Union::TimeStamp(value, _, _) => ::downcast_ref::(value.as_ref()), _ => None, }; } if TypeId::of::() == TypeId::of::<()>() { return match &self.0 { - Union::Unit(value, _) => ::downcast_ref::(value), + Union::Unit(value, _, _) => ::downcast_ref::(value), _ => None, }; } @@ -1446,9 +1524,9 @@ impl Dynamic { } match &self.0 { - Union::Variant(value, _) => value.as_ref().as_ref().as_any().downcast_ref::(), + Union::Variant(value, _, _) => value.as_ref().as_ref().as_any().downcast_ref::(), #[cfg(not(feature = "no_closure"))] - Union::Shared(_, _) => None, + Union::Shared(_, _, _) => None, _ => None, } } @@ -1462,72 +1540,72 @@ impl Dynamic { if TypeId::of::() == TypeId::of::() { return match &mut self.0 { - Union::Int(value, _) => ::downcast_mut::(value), + Union::Int(value, _, _) => ::downcast_mut::(value), _ => None, }; } #[cfg(not(feature = "no_float"))] if TypeId::of::() == TypeId::of::() { return match &mut self.0 { - Union::Float(value, _) => ::downcast_mut::(value.as_mut()), + Union::Float(value, _, _) => ::downcast_mut::(value.as_mut()), _ => None, }; } #[cfg(feature = "decimal")] if TypeId::of::() == TypeId::of::() { return match &mut self.0 { - Union::Decimal(value, _) => ::downcast_mut::(value.as_mut()), + Union::Decimal(value, _, _) => ::downcast_mut::(value.as_mut()), _ => None, }; } if TypeId::of::() == TypeId::of::() { return match &mut self.0 { - Union::Bool(value, _) => ::downcast_mut::(value), + Union::Bool(value, _, _) => ::downcast_mut::(value), _ => None, }; } if TypeId::of::() == TypeId::of::() { return match &mut self.0 { - Union::Str(value, _) => ::downcast_mut::(value), + Union::Str(value, _, _) => ::downcast_mut::(value), _ => None, }; } if TypeId::of::() == TypeId::of::() { return match &mut self.0 { - Union::Char(value, _) => ::downcast_mut::(value), + Union::Char(value, _, _) => ::downcast_mut::(value), _ => None, }; } #[cfg(not(feature = "no_index"))] if TypeId::of::() == TypeId::of::() { return match &mut self.0 { - Union::Array(value, _) => ::downcast_mut::(value.as_mut()), + Union::Array(value, _, _) => ::downcast_mut::(value.as_mut()), _ => None, }; } #[cfg(not(feature = "no_object"))] if TypeId::of::() == TypeId::of::() { return match &mut self.0 { - Union::Map(value, _) => ::downcast_mut::(value.as_mut()), + Union::Map(value, _, _) => ::downcast_mut::(value.as_mut()), _ => None, }; } if TypeId::of::() == TypeId::of::() { return match &mut self.0 { - Union::FnPtr(value, _) => ::downcast_mut::(value.as_mut()), + Union::FnPtr(value, _, _) => ::downcast_mut::(value.as_mut()), _ => None, }; } #[cfg(not(feature = "no_std"))] if TypeId::of::() == TypeId::of::() { return match &mut self.0 { - Union::TimeStamp(value, _) => ::downcast_mut::(value.as_mut()), + Union::TimeStamp(value, _, _) => ::downcast_mut::(value.as_mut()), _ => None, }; } if TypeId::of::() == TypeId::of::<()>() { return match &mut self.0 { - Union::Unit(value, _) => ::downcast_mut::(value), + Union::Unit(value, _, _) => ::downcast_mut::(value), _ => None, }; } @@ -1536,9 +1614,9 @@ impl Dynamic { } match &mut self.0 { - Union::Variant(value, _) => value.as_mut().as_mut_any().downcast_mut::(), + Union::Variant(value, _, _) => value.as_mut().as_mut_any().downcast_mut::(), #[cfg(not(feature = "no_closure"))] - Union::Shared(_, _) => None, + Union::Shared(_, _, _) => None, _ => None, } } @@ -1547,9 +1625,9 @@ impl Dynamic { #[inline(always)] pub fn as_unit(&self) -> Result<(), &'static str> { match self.0 { - Union::Unit(value, _) => Ok(value), + Union::Unit(value, _, _) => Ok(value), #[cfg(not(feature = "no_closure"))] - Union::Shared(_, _) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()), + Union::Shared(_, _, _) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()), _ => Err(self.type_name()), } } @@ -1558,9 +1636,9 @@ impl Dynamic { #[inline(always)] pub fn as_int(&self) -> Result { match self.0 { - Union::Int(n, _) => Ok(n), + Union::Int(n, _, _) => Ok(n), #[cfg(not(feature = "no_closure"))] - Union::Shared(_, _) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()), + Union::Shared(_, _, _) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()), _ => Err(self.type_name()), } } @@ -1572,9 +1650,9 @@ impl Dynamic { #[inline(always)] pub fn as_float(&self) -> Result { match self.0 { - Union::Float(n, _) => Ok(*n), + Union::Float(n, _, _) => Ok(*n), #[cfg(not(feature = "no_closure"))] - Union::Shared(_, _) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()), + Union::Shared(_, _, _) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()), _ => Err(self.type_name()), } } @@ -1586,9 +1664,9 @@ impl Dynamic { #[inline(always)] pub fn as_decimal(&self) -> Result { match &self.0 { - Union::Decimal(n, _) => Ok(**n), + Union::Decimal(n, _, _) => Ok(**n), #[cfg(not(feature = "no_closure"))] - Union::Shared(_, _) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()), + Union::Shared(_, _, _) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()), _ => Err(self.type_name()), } } @@ -1597,9 +1675,9 @@ impl Dynamic { #[inline(always)] pub fn as_bool(&self) -> Result { match self.0 { - Union::Bool(b, _) => Ok(b), + Union::Bool(b, _, _) => Ok(b), #[cfg(not(feature = "no_closure"))] - Union::Shared(_, _) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()), + Union::Shared(_, _, _) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()), _ => Err(self.type_name()), } } @@ -1608,9 +1686,9 @@ impl Dynamic { #[inline(always)] pub fn as_char(&self) -> Result { match self.0 { - Union::Char(n, _) => Ok(n), + Union::Char(n, _, _) => Ok(n), #[cfg(not(feature = "no_closure"))] - Union::Shared(_, _) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()), + Union::Shared(_, _, _) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()), _ => Err(self.type_name()), } } @@ -1623,9 +1701,9 @@ impl Dynamic { #[inline(always)] pub(crate) fn as_str_ref(&self) -> Result<&str, &'static str> { match &self.0 { - Union::Str(s, _) => Ok(s), + Union::Str(s, _, _) => Ok(s), #[cfg(not(feature = "no_closure"))] - Union::Shared(_, _) => panic!("as_str() cannot be called on shared values"), + Union::Shared(_, _, _) => panic!("as_str() cannot be called on shared values"), _ => Err(self.type_name()), } } @@ -1642,16 +1720,16 @@ impl Dynamic { #[inline(always)] pub fn take_immutable_string(self) -> Result { match self.0 { - Union::Str(s, _) => Ok(s), + Union::Str(s, _, _) => Ok(s), #[cfg(not(feature = "no_closure"))] - Union::Shared(cell, _) => { + Union::Shared(cell, _, _) => { #[cfg(not(feature = "sync"))] let value = cell.borrow(); #[cfg(feature = "sync")] let value = cell.read().unwrap(); match &value.0 { - Union::Str(s, _) => Ok(s.clone()), + Union::Str(s, _, _) => Ok(s.clone()), _ => Err((*value).type_name()), } } @@ -1663,33 +1741,37 @@ impl Dynamic { impl From<()> for Dynamic { #[inline(always)] fn from(value: ()) -> Self { - Self(Union::Unit(value, AccessMode::ReadWrite)) + Self(Union::Unit(value, DEFAULT_TAG, AccessMode::ReadWrite)) } } impl From for Dynamic { #[inline(always)] fn from(value: bool) -> Self { - Self(Union::Bool(value, AccessMode::ReadWrite)) + Self(Union::Bool(value, DEFAULT_TAG, AccessMode::ReadWrite)) } } impl From for Dynamic { #[inline(always)] fn from(value: INT) -> Self { - Self(Union::Int(value, AccessMode::ReadWrite)) + Self(Union::Int(value, DEFAULT_TAG, AccessMode::ReadWrite)) } } #[cfg(not(feature = "no_float"))] impl From for Dynamic { #[inline(always)] fn from(value: FLOAT) -> Self { - Self(Union::Float(value.into(), AccessMode::ReadWrite)) + Self(Union::Float( + value.into(), + DEFAULT_TAG, + AccessMode::ReadWrite, + )) } } #[cfg(not(feature = "no_float"))] impl From> for Dynamic { #[inline(always)] fn from(value: FloatWrapper) -> Self { - Self(Union::Float(value, AccessMode::ReadWrite)) + Self(Union::Float(value, DEFAULT_TAG, AccessMode::ReadWrite)) } } #[cfg(feature = "decimal")] @@ -1698,6 +1780,7 @@ impl From for Dynamic { fn from(value: Decimal) -> Self { Self(Union::Decimal( Box::new(value.into()), + DEFAULT_TAG, AccessMode::ReadWrite, )) } @@ -1705,13 +1788,13 @@ impl From for Dynamic { impl From for Dynamic { #[inline(always)] fn from(value: char) -> Self { - Self(Union::Char(value, AccessMode::ReadWrite)) + Self(Union::Char(value, DEFAULT_TAG, AccessMode::ReadWrite)) } } impl> From for Dynamic { #[inline(always)] fn from(value: S) -> Self { - Self(Union::Str(value.into(), AccessMode::ReadWrite)) + Self(Union::Str(value.into(), DEFAULT_TAG, AccessMode::ReadWrite)) } } impl From<&ImmutableString> for Dynamic { @@ -1732,7 +1815,11 @@ impl Dynamic { /// Create a [`Dynamc`] from an [`Array`]. #[inline(always)] pub(crate) fn from_array(array: Array) -> Self { - Self(Union::Array(Box::new(array), AccessMode::ReadWrite)) + Self(Union::Array( + Box::new(array), + DEFAULT_TAG, + AccessMode::ReadWrite, + )) } } #[cfg(not(feature = "no_index"))] @@ -1741,6 +1828,7 @@ impl From> for Dynamic { fn from(value: Vec) -> Self { Self(Union::Array( Box::new(value.into_iter().map(Dynamic::from).collect()), + DEFAULT_TAG, AccessMode::ReadWrite, )) } @@ -1751,6 +1839,7 @@ impl From<&[T]> for Dynamic { fn from(value: &[T]) -> Self { Self(Union::Array( Box::new(value.iter().cloned().map(Dynamic::from).collect()), + DEFAULT_TAG, AccessMode::ReadWrite, )) } @@ -1761,6 +1850,7 @@ impl std::iter::FromIterator for Dynamic { fn from_iter>(iter: X) -> Self { Self(Union::Array( Box::new(iter.into_iter().map(Dynamic::from).collect()), + DEFAULT_TAG, AccessMode::ReadWrite, )) } @@ -1770,7 +1860,11 @@ impl Dynamic { /// Create a [`Dynamc`] from a [`Map`]. #[inline(always)] pub(crate) fn from_map(map: Map) -> Self { - Self(Union::Map(Box::new(map), AccessMode::ReadWrite)) + Self(Union::Map( + Box::new(map), + DEFAULT_TAG, + AccessMode::ReadWrite, + )) } } #[cfg(not(feature = "no_object"))] @@ -1787,6 +1881,7 @@ impl, T: Variant + Clone> From, T: Variant + Clone> From, T: Variant + Clone> From for Dynamic { #[inline(always)] fn from(value: FnPtr) -> Self { - Self(Union::FnPtr(Box::new(value), AccessMode::ReadWrite)) + Self(Union::FnPtr( + Box::new(value), + DEFAULT_TAG, + AccessMode::ReadWrite, + )) } } impl From> for Dynamic { #[inline(always)] fn from(value: Box) -> Self { - Self(Union::FnPtr(value, AccessMode::ReadWrite)) + Self(Union::FnPtr(value, DEFAULT_TAG, AccessMode::ReadWrite)) } } #[cfg(not(feature = "no_std"))] impl From for Dynamic { #[inline(always)] fn from(value: Instant) -> Self { - Self(Union::TimeStamp(Box::new(value), AccessMode::ReadWrite)) + Self(Union::TimeStamp( + Box::new(value), + DEFAULT_TAG, + AccessMode::ReadWrite, + )) } } diff --git a/src/engine.rs b/src/engine.rs index 1c696e02..786fe039 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -1676,7 +1676,7 @@ impl Engine { match target { #[cfg(not(feature = "no_index"))] - Dynamic(Union::Array(arr, _)) => { + Dynamic(Union::Array(arr, _, _)) => { // val_array[idx] let index = _idx .as_int() @@ -1718,7 +1718,7 @@ impl Engine { } #[cfg(not(feature = "no_object"))] - Dynamic(Union::Map(map, _)) => { + Dynamic(Union::Map(map, _, _)) => { // val_map[idx] let index = &*_idx.read_lock::().ok_or_else(|| { self.make_type_mismatch_err::(_idx.type_name(), idx_pos) @@ -1735,7 +1735,7 @@ impl Engine { } #[cfg(not(feature = "no_index"))] - Dynamic(Union::Str(s, _)) => { + Dynamic(Union::Str(s, _, _)) => { // val_string[idx] let index = _idx .as_int() @@ -2569,7 +2569,7 @@ impl Engine { Ok(_) => Ok(Dynamic::UNIT), Err(result_err) => match *result_err { // Re-throw exception - EvalAltResult::ErrorRuntime(Dynamic(Union::Unit(_, _)), pos) => { + EvalAltResult::ErrorRuntime(Dynamic(Union::Unit(_, _, _)), pos) => { err.set_position(pos); Err(err) } @@ -2777,18 +2777,18 @@ impl Engine { fn calc_size(value: &Dynamic) -> (usize, usize, usize) { match value { #[cfg(not(feature = "no_index"))] - Dynamic(Union::Array(arr, _)) => { + Dynamic(Union::Array(arr, _, _)) => { let mut arrays = 0; let mut maps = 0; arr.iter().for_each(|value| match value { - Dynamic(Union::Array(_, _)) => { + Dynamic(Union::Array(_, _, _)) => { let (a, m, _) = calc_size(value); arrays += a; maps += m; } #[cfg(not(feature = "no_object"))] - Dynamic(Union::Map(_, _)) => { + Dynamic(Union::Map(_, _, _)) => { let (a, m, _) = calc_size(value); arrays += a; maps += m; @@ -2799,18 +2799,18 @@ impl Engine { (arrays, maps, 0) } #[cfg(not(feature = "no_object"))] - Dynamic(Union::Map(map, _)) => { + Dynamic(Union::Map(map, _, _)) => { let mut arrays = 0; let mut maps = 0; map.values().for_each(|value| match value { #[cfg(not(feature = "no_index"))] - Dynamic(Union::Array(_, _)) => { + Dynamic(Union::Array(_, _, _)) => { let (a, m, _) = calc_size(value); arrays += a; maps += m; } - Dynamic(Union::Map(_, _)) => { + Dynamic(Union::Map(_, _, _)) => { let (a, m, _) = calc_size(value); arrays += a; maps += m; @@ -2820,7 +2820,7 @@ impl Engine { (arrays, maps, 0) } - Dynamic(Union::Str(s, _)) => (0, 0, s.len()), + Dynamic(Union::Str(s, _, _)) => (0, 0, s.len()), _ => (0, 0, 0), } } diff --git a/src/packages/lang_core.rs b/src/packages/lang_core.rs new file mode 100644 index 00000000..e20f76db --- /dev/null +++ b/src/packages/lang_core.rs @@ -0,0 +1,45 @@ +use crate::def_package; +use crate::dynamic::Tag; +use crate::plugin::*; +use crate::{Dynamic, EvalAltResult, INT}; +#[cfg(feature = "no_std")] +use std::prelude::v1::*; + +#[export_module] +mod core_functions { + #[rhai_fn(name = "tag", get = "tag", pure)] + pub fn get_tag(value: &mut Dynamic) -> INT { + value.tag() as INT + } + #[rhai_fn(name = "set_tag", set = "tag", return_raw)] + pub fn set_tag(value: &mut Dynamic, tag: INT) -> Result<(), Box> { + if tag < Tag::MIN as INT { + Err(Box::new(EvalAltResult::ErrorArithmetic( + format!( + "{} is too small to fit into a tag (must be between {} and {})", + tag, + Tag::MIN, + Tag::MAX + ), + Position::NONE, + ))) + } else if tag > Tag::MAX as INT { + Err(Box::new(EvalAltResult::ErrorArithmetic( + format!( + "{} is too large to fit into a tag (must be between {} and {})", + tag, + Tag::MIN, + Tag::MAX + ), + Position::NONE, + ))) + } else { + value.set_tag(tag as Tag); + Ok(()) + } + } +} + +def_package!(crate:LanguageCorePackage:"Language core functions.", lib, { + combine_with_exported_module!(lib, "language_core", core_functions); +}); diff --git a/src/packages/mod.rs b/src/packages/mod.rs index 145eabf0..3e3975e3 100644 --- a/src/packages/mod.rs +++ b/src/packages/mod.rs @@ -6,6 +6,7 @@ pub(crate) mod arithmetic; mod array_basic; mod fn_basic; mod iter_basic; +mod lang_core; mod logic; mod map_basic; mod math_basic; @@ -86,6 +87,7 @@ macro_rules! def_package { } impl $package { + #[allow(dead_code)] pub fn new() -> Self { let mut module = $root::Module::new(); ::init(&mut module); diff --git a/src/packages/pkg_core.rs b/src/packages/pkg_core.rs index 54dff2ca..7f79b3f4 100644 --- a/src/packages/pkg_core.rs +++ b/src/packages/pkg_core.rs @@ -1,6 +1,7 @@ use super::arithmetic::ArithmeticPackage; use super::fn_basic::BasicFnPackage; use super::iter_basic::BasicIteratorPackage; +use super::lang_core::LanguageCorePackage; use super::logic::LogicPackage; use super::string_basic::BasicStringPackage; #[cfg(feature = "no_std")] @@ -9,6 +10,7 @@ use std::prelude::v1::*; use crate::def_package; def_package!(crate:CorePackage:"_Core_ package containing basic facilities.", lib, { + LanguageCorePackage::init(lib); ArithmeticPackage::init(lib); LogicPackage::init(lib); BasicStringPackage::init(lib); diff --git a/src/parser.rs b/src/parser.rs index b33ae36e..7dc5816b 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -3135,22 +3135,22 @@ impl Engine { pub fn map_dynamic_to_expr(value: Dynamic, pos: Position) -> Option { match value.0 { #[cfg(not(feature = "no_float"))] - Union::Float(value, _) => Some(Expr::FloatConstant(value, pos)), + Union::Float(value, _, _) => Some(Expr::FloatConstant(value, pos)), #[cfg(feature = "decimal")] - Union::Decimal(value, _) => Some(Expr::DynamicConstant(Box::new((*value).into()), pos)), + Union::Decimal(value, _, _) => Some(Expr::DynamicConstant(Box::new((*value).into()), pos)), - Union::Unit(_, _) => Some(Expr::Unit(pos)), - Union::Int(value, _) => Some(Expr::IntegerConstant(value, pos)), - Union::Char(value, _) => Some(Expr::CharConstant(value, pos)), - Union::Str(value, _) => Some(Expr::StringConstant(value, pos)), - Union::Bool(value, _) => Some(Expr::BoolConstant(value, pos)), + Union::Unit(_, _, _) => Some(Expr::Unit(pos)), + Union::Int(value, _, _) => Some(Expr::IntegerConstant(value, pos)), + Union::Char(value, _, _) => Some(Expr::CharConstant(value, pos)), + Union::Str(value, _, _) => Some(Expr::StringConstant(value, pos)), + Union::Bool(value, _, _) => Some(Expr::BoolConstant(value, pos)), #[cfg(not(feature = "no_index"))] - Union::Array(array, _) => Some(Expr::DynamicConstant(Box::new((*array).into()), pos)), + Union::Array(array, _, _) => Some(Expr::DynamicConstant(Box::new((*array).into()), pos)), #[cfg(not(feature = "no_object"))] - Union::Map(map, _) => Some(Expr::DynamicConstant(Box::new((*map).into()), pos)), + Union::Map(map, _, _) => Some(Expr::DynamicConstant(Box::new((*map).into()), pos)), _ => None, } diff --git a/src/serde/de.rs b/src/serde/de.rs index 2d81cff9..c92cac19 100644 --- a/src/serde/de.rs +++ b/src/serde/de.rs @@ -126,53 +126,53 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { fn deserialize_any>(self, visitor: V) -> Result> { match &self.value.0 { - Union::Unit(_, _) => self.deserialize_unit(visitor), - Union::Bool(_, _) => self.deserialize_bool(visitor), - Union::Str(_, _) => self.deserialize_str(visitor), - Union::Char(_, _) => self.deserialize_char(visitor), + Union::Unit(_, _, _) => self.deserialize_unit(visitor), + Union::Bool(_, _, _) => self.deserialize_bool(visitor), + Union::Str(_, _, _) => self.deserialize_str(visitor), + Union::Char(_, _, _) => self.deserialize_char(visitor), #[cfg(not(feature = "only_i32"))] - Union::Int(_, _) => self.deserialize_i64(visitor), + Union::Int(_, _, _) => self.deserialize_i64(visitor), #[cfg(feature = "only_i32")] - Union::Int(_, _) => self.deserialize_i32(visitor), + Union::Int(_, _, _) => self.deserialize_i32(visitor), #[cfg(not(feature = "no_float"))] #[cfg(not(feature = "f32_float"))] - Union::Float(_, _) => self.deserialize_f64(visitor), + Union::Float(_, _, _) => self.deserialize_f64(visitor), #[cfg(not(feature = "no_float"))] #[cfg(feature = "f32_float")] - Union::Float(_, _) => self.deserialize_f32(visitor), + Union::Float(_, _, _) => self.deserialize_f32(visitor), #[cfg(feature = "decimal")] #[cfg(not(feature = "f32_float"))] - Union::Decimal(_, _) => self.deserialize_f64(visitor), + Union::Decimal(_, _, _) => self.deserialize_f64(visitor), #[cfg(feature = "decimal")] #[cfg(feature = "f32_float")] - Union::Decimal(_, _) => self.deserialize_f32(visitor), + Union::Decimal(_, _, _) => self.deserialize_f32(visitor), #[cfg(not(feature = "no_index"))] - Union::Array(_, _) => self.deserialize_seq(visitor), + Union::Array(_, _, _) => self.deserialize_seq(visitor), #[cfg(not(feature = "no_object"))] - Union::Map(_, _) => self.deserialize_map(visitor), - Union::FnPtr(_, _) => self.type_error(), + Union::Map(_, _, _) => self.deserialize_map(visitor), + Union::FnPtr(_, _, _) => self.type_error(), #[cfg(not(feature = "no_std"))] - Union::TimeStamp(_, _) => self.type_error(), + Union::TimeStamp(_, _, _) => self.type_error(), - Union::Variant(value, _) if value.is::() => self.deserialize_i8(visitor), - Union::Variant(value, _) if value.is::() => self.deserialize_i16(visitor), - Union::Variant(value, _) if value.is::() => self.deserialize_i32(visitor), - Union::Variant(value, _) if value.is::() => self.deserialize_i64(visitor), - Union::Variant(value, _) if value.is::() => self.deserialize_i128(visitor), - Union::Variant(value, _) if value.is::() => self.deserialize_u8(visitor), - Union::Variant(value, _) if value.is::() => self.deserialize_u16(visitor), - Union::Variant(value, _) if value.is::() => self.deserialize_u32(visitor), - Union::Variant(value, _) if value.is::() => self.deserialize_u64(visitor), - Union::Variant(value, _) if value.is::() => self.deserialize_u128(visitor), + Union::Variant(value, _, _) if value.is::() => self.deserialize_i8(visitor), + Union::Variant(value, _, _) if value.is::() => self.deserialize_i16(visitor), + Union::Variant(value, _, _) if value.is::() => self.deserialize_i32(visitor), + Union::Variant(value, _, _) if value.is::() => self.deserialize_i64(visitor), + Union::Variant(value, _, _) if value.is::() => self.deserialize_i128(visitor), + Union::Variant(value, _, _) if value.is::() => self.deserialize_u8(visitor), + Union::Variant(value, _, _) if value.is::() => self.deserialize_u16(visitor), + Union::Variant(value, _, _) if value.is::() => self.deserialize_u32(visitor), + Union::Variant(value, _, _) if value.is::() => self.deserialize_u64(visitor), + Union::Variant(value, _, _) if value.is::() => self.deserialize_u128(visitor), - Union::Variant(_, _) => self.type_error(), + Union::Variant(_, _, _) => self.type_error(), #[cfg(not(feature = "no_closure"))] - Union::Shared(_, _) => self.type_error(), + Union::Shared(_, _, _) => self.type_error(), } } diff --git a/src/serde/serialize.rs b/src/serde/serialize.rs index 43d5189a..be3625ac 100644 --- a/src/serde/serialize.rs +++ b/src/serde/serialize.rs @@ -12,26 +12,26 @@ use serde::ser::SerializeMap; impl Serialize for Dynamic { fn serialize(&self, ser: S) -> Result { match &self.0 { - Union::Unit(_, _) => ser.serialize_unit(), - Union::Bool(x, _) => ser.serialize_bool(*x), - Union::Str(s, _) => ser.serialize_str(s.as_str()), - Union::Char(c, _) => ser.serialize_str(&c.to_string()), + Union::Unit(_, _, _) => ser.serialize_unit(), + Union::Bool(x, _, _) => ser.serialize_bool(*x), + Union::Str(s, _, _) => ser.serialize_str(s.as_str()), + Union::Char(c, _, _) => ser.serialize_str(&c.to_string()), #[cfg(not(feature = "only_i32"))] - Union::Int(x, _) => ser.serialize_i64(*x), + Union::Int(x, _, _) => ser.serialize_i64(*x), #[cfg(feature = "only_i32")] - Union::Int(x, _) => ser.serialize_i32(*x), + Union::Int(x, _, _) => ser.serialize_i32(*x), #[cfg(not(feature = "no_float"))] #[cfg(not(feature = "f32_float"))] - Union::Float(x, _) => ser.serialize_f64(**x), + Union::Float(x, _, _) => ser.serialize_f64(**x), #[cfg(not(feature = "no_float"))] #[cfg(feature = "f32_float")] - Union::Float(x, _) => ser.serialize_f32(**x), + Union::Float(x, _, _) => ser.serialize_f32(**x), #[cfg(feature = "decimal")] #[cfg(not(feature = "f32_float"))] - Union::Decimal(x, _) => { + Union::Decimal(x, _, _) => { use rust_decimal::prelude::ToPrimitive; if let Some(v) = x.to_f64() { @@ -42,7 +42,7 @@ impl Serialize for Dynamic { } #[cfg(feature = "decimal")] #[cfg(feature = "f32_float")] - Union::Decimal(x, _) => { + Union::Decimal(x, _, _) => { use rust_decimal::prelude::ToPrimitive; if let Some(v) = x.to_f32() { @@ -53,27 +53,27 @@ impl Serialize for Dynamic { } #[cfg(not(feature = "no_index"))] - Union::Array(a, _) => (**a).serialize(ser), + Union::Array(a, _, _) => (**a).serialize(ser), #[cfg(not(feature = "no_object"))] - Union::Map(m, _) => { + Union::Map(m, _, _) => { let mut map = ser.serialize_map(Some(m.len()))?; for (k, v) in m.iter() { map.serialize_entry(k.as_str(), v)?; } map.end() } - Union::FnPtr(f, _) => ser.serialize_str(f.fn_name()), + Union::FnPtr(f, _, _) => ser.serialize_str(f.fn_name()), #[cfg(not(feature = "no_std"))] - Union::TimeStamp(x, _) => ser.serialize_str(x.as_ref().type_name()), + Union::TimeStamp(x, _, _) => ser.serialize_str(x.as_ref().type_name()), - Union::Variant(v, _) => ser.serialize_str((***v).type_name()), + Union::Variant(v, _, _) => ser.serialize_str((***v).type_name()), #[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "sync"))] - Union::Shared(cell, _) => cell.borrow().serialize(ser), + Union::Shared(cell, _, _) => cell.borrow().serialize(ser), #[cfg(not(feature = "no_closure"))] #[cfg(feature = "sync")] - Union::Shared(cell, _) => cell.read().unwrap().serialize(ser), + Union::Shared(cell, _, _) => cell.read().unwrap().serialize(ser), } } }