use crate::fn_native::SendSync;
use crate::r#unsafe::{unsafe_cast_box, unsafe_try_cast};
use crate::stdlib::{
any::{type_name, Any, TypeId},
boxed::Box,
fmt,
hash::{Hash, Hasher},
ops::{Deref, DerefMut},
string::String,
};
use crate::{FnPtr, ImmutableString, INT};
#[cfg(not(feature = "no_float"))]
use crate::{ast::FloatWrapper, FLOAT};
#[cfg(feature = "decimal")]
use rust_decimal::Decimal;
#[cfg(not(feature = "no_index"))]
use crate::Array;
#[cfg(not(feature = "no_object"))]
use crate::Map;
#[cfg(not(feature = "no_std"))]
#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
use crate::stdlib::time::Instant;
use fmt::Debug;
#[cfg(not(feature = "no_std"))]
#[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
use instant::Instant;
mod private {
use crate::fn_native::SendSync;
use crate::stdlib::any::Any;
pub trait Sealed {}
impl<T: Any + Clone + SendSync> Sealed for T {}
}
#[cfg(not(feature = "sync"))]
pub trait Variant: Any + private::Sealed {
fn as_any(&self) -> &dyn Any;
fn as_mut_any(&mut self) -> &mut dyn Any;
fn as_box_any(self: Box<Self>) -> Box<dyn Any>;
fn type_name(&self) -> &'static str;
fn into_dynamic(self) -> Dynamic;
fn clone_into_dynamic(&self) -> Dynamic;
}
#[cfg(feature = "sync")]
pub trait Variant: Any + Send + Sync + private::Sealed {
fn as_any(&self) -> &dyn Any;
fn as_mut_any(&mut self) -> &mut dyn Any;
fn as_box_any(self: Box<Self>) -> Box<dyn Any>;
fn type_name(&self) -> &'static str;
fn into_dynamic(self) -> Dynamic;
fn clone_into_dynamic(&self) -> Dynamic;
}
impl<T: Any + Clone + SendSync> Variant for T {
#[inline(always)]
fn as_any(&self) -> &dyn Any {
self
}
#[inline(always)]
fn as_mut_any(&mut self) -> &mut dyn Any {
self
}
#[inline(always)]
fn as_box_any(self: Box<Self>) -> Box<dyn Any> {
self
}
#[inline(always)]
fn type_name(&self) -> &'static str {
type_name::<T>()
}
#[inline(always)]
fn into_dynamic(self) -> Dynamic {
Dynamic::from(self)
}
#[inline(always)]
fn clone_into_dynamic(&self) -> Dynamic {
Dynamic::from(self.clone())
}
}
impl dyn Variant {
#[inline(always)]
pub fn is<T: Any>(&self) -> bool {
TypeId::of::<T>() == self.type_id()
}
}
#[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)]
pub enum AccessMode {
ReadWrite,
ReadOnly,
}
pub struct Dynamic(pub(crate) Union);
pub enum Union {
Unit((), AccessMode),
Bool(bool, AccessMode),
Str(ImmutableString, AccessMode),
Char(char, AccessMode),
Int(INT, AccessMode),
#[cfg(not(feature = "no_float"))]
Float(FloatWrapper, AccessMode),
#[cfg(feature = "decimal")]
Decimal(Box<Decimal>, AccessMode),
#[cfg(not(feature = "no_index"))]
Array(Box<Array>, AccessMode),
#[cfg(not(feature = "no_object"))]
Map(Box<Map>, AccessMode),
FnPtr(Box<FnPtr>, AccessMode),
#[cfg(not(feature = "no_std"))]
TimeStamp(Box<Instant>, AccessMode),
Variant(Box<Box<dyn Variant>>, AccessMode),
#[cfg(not(feature = "no_closure"))]
Shared(crate::Shared<crate::Locked<Dynamic>>, AccessMode),
}
#[derive(Debug)]
pub struct DynamicReadLock<'d, T: Variant + Clone>(DynamicReadLockInner<'d, T>);
#[derive(Debug)]
enum DynamicReadLockInner<'d, T: Variant + Clone> {
Reference(&'d T),
#[cfg(not(feature = "no_closure"))]
#[cfg(not(feature = "sync"))]
Guard(crate::stdlib::cell::Ref<'d, Dynamic>),
#[cfg(not(feature = "no_closure"))]
#[cfg(feature = "sync")]
Guard(crate::stdlib::sync::RwLockReadGuard<'d, Dynamic>),
}
impl<'d, T: Variant + Clone> Deref for DynamicReadLock<'d, T> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &Self::Target {
match &self.0 {
DynamicReadLockInner::Reference(reference) => *reference,
#[cfg(not(feature = "no_closure"))]
DynamicReadLockInner::Guard(guard) => guard.downcast_ref().unwrap(),
}
}
}
#[derive(Debug)]
pub struct DynamicWriteLock<'d, T: Variant + Clone>(DynamicWriteLockInner<'d, T>);
#[derive(Debug)]
enum DynamicWriteLockInner<'d, T: Variant + Clone> {
Reference(&'d mut T),
#[cfg(not(feature = "no_closure"))]
#[cfg(not(feature = "sync"))]
Guard(crate::stdlib::cell::RefMut<'d, Dynamic>),
#[cfg(not(feature = "no_closure"))]
#[cfg(feature = "sync")]
Guard(crate::stdlib::sync::RwLockWriteGuard<'d, Dynamic>),
}
impl<'d, T: Variant + Clone> Deref for DynamicWriteLock<'d, T> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &Self::Target {
match &self.0 {
DynamicWriteLockInner::Reference(reference) => *reference,
#[cfg(not(feature = "no_closure"))]
DynamicWriteLockInner::Guard(guard) => guard.downcast_ref().unwrap(),
}
}
}
impl<'d, T: Variant + Clone> DerefMut for DynamicWriteLock<'d, T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
match &mut self.0 {
DynamicWriteLockInner::Reference(reference) => *reference,
#[cfg(not(feature = "no_closure"))]
DynamicWriteLockInner::Guard(guard) => guard.downcast_mut().unwrap(),
}
}
}
impl Dynamic {
#[inline(always)]
pub fn is_variant(&self) -> bool {
match self.0 {
Union::Variant(_, _) => true,
_ => false,
}
}
#[inline(always)]
pub fn is_shared(&self) -> bool {
#[cfg(not(feature = "no_closure"))]
match self.0 {
Union::Shared(_, _) => return true,
_ => (),
}
false
}
#[inline(always)]
pub fn is<T: Variant + Clone>(&self) -> bool {
let mut target_type_id = TypeId::of::<T>();
if target_type_id == TypeId::of::<String>() {
target_type_id = TypeId::of::<ImmutableString>();
}
self.type_id() == target_type_id
}
pub fn type_id(&self) -> TypeId {
match &self.0 {
Union::Unit(_, _) => TypeId::of::<()>(),
Union::Bool(_, _) => TypeId::of::<bool>(),
Union::Str(_, _) => TypeId::of::<ImmutableString>(),
Union::Char(_, _) => TypeId::of::<char>(),
Union::Int(_, _) => TypeId::of::<INT>(),
#[cfg(not(feature = "no_float"))]
Union::Float(_, _) => TypeId::of::<FLOAT>(),
#[cfg(feature = "decimal")]
Union::Decimal(_, _) => TypeId::of::<Decimal>(),
#[cfg(not(feature = "no_index"))]
Union::Array(_, _) => TypeId::of::<Array>(),
#[cfg(not(feature = "no_object"))]
Union::Map(_, _) => TypeId::of::<Map>(),
Union::FnPtr(_, _) => TypeId::of::<FnPtr>(),
#[cfg(not(feature = "no_std"))]
Union::TimeStamp(_, _) => TypeId::of::<Instant>(),
Union::Variant(value, _) => (***value).type_id(),
#[cfg(not(feature = "no_closure"))]
Union::Shared(cell, _) => {
#[cfg(not(feature = "sync"))]
let value = cell.borrow();
#[cfg(feature = "sync")]
let value = cell.read().unwrap();
(*value).type_id()
}
}
}
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::<INT>(),
#[cfg(not(feature = "no_float"))]
Union::Float(_, _) => type_name::<FLOAT>(),
#[cfg(feature = "decimal")]
Union::Decimal(_, _) => "decimal",
#[cfg(not(feature = "no_index"))]
Union::Array(_, _) => "array",
#[cfg(not(feature = "no_object"))]
Union::Map(_, _) => "map",
Union::FnPtr(_, _) => "Fn",
#[cfg(not(feature = "no_std"))]
Union::TimeStamp(_, _) => "timestamp",
Union::Variant(value, _) => (***value).type_name(),
#[cfg(not(feature = "no_closure"))]
#[cfg(not(feature = "sync"))]
Union::Shared(cell, _) => cell
.try_borrow()
.map(|v| (*v).type_name())
.unwrap_or("<shared>"),
#[cfg(not(feature = "no_closure"))]
#[cfg(feature = "sync")]
Union::Shared(cell, _) => (*cell.read().unwrap()).type_name(),
}
}
}
impl Hash for Dynamic {
fn hash<H: Hasher>(&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),
#[cfg(not(feature = "no_float"))]
Union::Float(f, _) => f.hash(state),
#[cfg(not(feature = "no_index"))]
Union::Array(a, _) => (**a).hash(state),
#[cfg(not(feature = "no_object"))]
Union::Map(m, _) => {
let mut buf: crate::StaticVec<_> = m.iter().collect();
buf.sort_by(|(a, _), (b, _)| a.cmp(b));
buf.into_iter().for_each(|(key, value)| {
key.hash(state);
value.hash(state);
})
}
#[cfg(not(feature = "no_closure"))]
Union::Shared(cell, _) => {
#[cfg(not(feature = "sync"))]
let value = cell.borrow();
#[cfg(feature = "sync")]
let value = cell.read().unwrap();
(*value).hash(state)
}
_ => unimplemented!("{} cannot be hashed", self.type_name()),
}
}
}
#[inline(always)]
pub(crate) fn map_std_type_name(name: &str) -> &str {
if name == type_name::<String>() {
return "string";
}
if name == type_name::<ImmutableString>() {
return "string";
}
if name == type_name::<&str>() {
return "string";
}
if name == type_name::<FnPtr>() {
return "Fn";
}
#[cfg(feature = "decimal")]
if name == type_name::<Decimal>() {
return "decimal";
}
#[cfg(not(feature = "no_index"))]
if name == type_name::<Array>() {
return "array";
}
#[cfg(not(feature = "no_object"))]
if name == type_name::<Map>() {
return "map";
}
#[cfg(not(feature = "no_std"))]
if name == type_name::<Instant>() {
return "timestamp";
}
name
}
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),
#[cfg(not(feature = "no_float"))]
Union::Float(value, _) => fmt::Display::fmt(value, f),
#[cfg(feature = "decimal")]
Union::Decimal(value, _) => fmt::Display::fmt(value, f),
#[cfg(not(feature = "no_index"))]
Union::Array(value, _) => fmt::Debug::fmt(value, f),
#[cfg(not(feature = "no_object"))]
Union::Map(value, _) => {
f.write_str("#")?;
fmt::Debug::fmt(value, f)
}
Union::FnPtr(value, _) => fmt::Display::fmt(value, f),
#[cfg(not(feature = "no_std"))]
Union::TimeStamp(_, _) => f.write_str("<timestamp>"),
Union::Variant(value, _) => {
let _type_id = (***value).type_id();
#[cfg(not(feature = "only_i32"))]
#[cfg(not(feature = "only_i64"))]
if _type_id == TypeId::of::<u8>() {
return write!(f, "{}", (**value).as_any().downcast_ref::<u8>().unwrap());
} else if _type_id == TypeId::of::<u16>() {
return write!(f, "{}", (**value).as_any().downcast_ref::<u16>().unwrap());
} else if _type_id == TypeId::of::<u32>() {
return write!(f, "{}", (**value).as_any().downcast_ref::<u32>().unwrap());
} else if _type_id == TypeId::of::<u64>() {
return write!(f, "{}", (**value).as_any().downcast_ref::<u64>().unwrap());
} else if _type_id == TypeId::of::<i8>() {
return write!(f, "{}", (**value).as_any().downcast_ref::<i8>().unwrap());
} else if _type_id == TypeId::of::<i16>() {
return write!(f, "{}", (**value).as_any().downcast_ref::<i16>().unwrap());
} else if _type_id == TypeId::of::<i32>() {
return write!(f, "{}", (**value).as_any().downcast_ref::<i32>().unwrap());
} else if _type_id == TypeId::of::<i64>() {
return write!(f, "{}", (**value).as_any().downcast_ref::<i64>().unwrap());
}
#[cfg(not(feature = "no_float"))]
if _type_id == TypeId::of::<f32>() {
return write!(f, "{}", (**value).as_any().downcast_ref::<f32>().unwrap());
} else if _type_id == TypeId::of::<f64>() {
return write!(f, "{}", (**value).as_any().downcast_ref::<f64>().unwrap());
}
#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
if _type_id == TypeId::of::<u128>() {
return write!(f, "{}", (**value).as_any().downcast_ref::<u128>().unwrap());
} else if _type_id == TypeId::of::<i128>() {
return write!(f, "{}", (**value).as_any().downcast_ref::<i128>().unwrap());
}
f.write_str((***value).type_name())
}
#[cfg(not(feature = "no_closure"))]
#[cfg(not(feature = "sync"))]
Union::Shared(cell, _) => {
if let Ok(v) = cell.try_borrow() {
fmt::Display::fmt(&*v, f)
} else {
f.write_str("<shared>")
}
}
#[cfg(not(feature = "no_closure"))]
#[cfg(feature = "sync")]
Union::Shared(cell, _) => fmt::Display::fmt(&*cell.read().unwrap(), f),
}
}
}
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),
#[cfg(not(feature = "no_float"))]
Union::Float(value, _) => fmt::Debug::fmt(value, f),
#[cfg(feature = "decimal")]
Union::Decimal(value, _) => fmt::Debug::fmt(value, f),
#[cfg(not(feature = "no_index"))]
Union::Array(value, _) => fmt::Debug::fmt(value, f),
#[cfg(not(feature = "no_object"))]
Union::Map(value, _) => {
f.write_str("#")?;
fmt::Debug::fmt(value, f)
}
Union::FnPtr(value, _) => fmt::Debug::fmt(value, f),
#[cfg(not(feature = "no_std"))]
Union::TimeStamp(_, _) => write!(f, "<timestamp>"),
Union::Variant(value, _) => {
let _type_id = (***value).type_id();
#[cfg(not(feature = "only_i32"))]
#[cfg(not(feature = "only_i64"))]
if _type_id == TypeId::of::<u8>() {
return write!(f, "{:?}", (**value).as_any().downcast_ref::<u8>().unwrap());
} else if _type_id == TypeId::of::<u16>() {
return write!(f, "{:?}", (**value).as_any().downcast_ref::<u16>().unwrap());
} else if _type_id == TypeId::of::<u32>() {
return write!(f, "{:?}", (**value).as_any().downcast_ref::<u32>().unwrap());
} else if _type_id == TypeId::of::<u64>() {
return write!(f, "{:?}", (**value).as_any().downcast_ref::<u64>().unwrap());
} else if _type_id == TypeId::of::<i8>() {
return write!(f, "{:?}", (**value).as_any().downcast_ref::<i8>().unwrap());
} else if _type_id == TypeId::of::<i16>() {
return write!(f, "{:?}", (**value).as_any().downcast_ref::<i16>().unwrap());
} else if _type_id == TypeId::of::<i32>() {
return write!(f, "{:?}", (**value).as_any().downcast_ref::<i32>().unwrap());
} else if _type_id == TypeId::of::<i64>() {
return write!(f, "{:?}", (**value).as_any().downcast_ref::<i64>().unwrap());
}
#[cfg(not(feature = "no_float"))]
if _type_id == TypeId::of::<f32>() {
return write!(f, "{}", (**value).as_any().downcast_ref::<f32>().unwrap());
} else if _type_id == TypeId::of::<f64>() {
return write!(f, "{}", (**value).as_any().downcast_ref::<f64>().unwrap());
}
#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
if _type_id == TypeId::of::<u128>() {
return write!(
f,
"{:?}",
(**value).as_any().downcast_ref::<u128>().unwrap()
);
} else if _type_id == TypeId::of::<i128>() {
return write!(
f,
"{:?}",
(**value).as_any().downcast_ref::<i128>().unwrap()
);
}
write!(f, "{}", (*value).type_name())
}
#[cfg(not(feature = "no_closure"))]
#[cfg(not(feature = "sync"))]
Union::Shared(cell, _) => {
if let Ok(v) = cell.try_borrow() {
write!(f, "{:?} (shared)", *v)
} else {
f.write_str("<shared>")
}
}
#[cfg(not(feature = "no_closure"))]
#[cfg(feature = "sync")]
Union::Shared(cell, _) => fmt::Debug::fmt(&*cell.read().unwrap(), f),
}
}
}
impl Clone for Dynamic {
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)),
#[cfg(not(feature = "no_float"))]
Union::Float(value, _) => Self(Union::Float(value, AccessMode::ReadWrite)),
#[cfg(feature = "decimal")]
Union::Decimal(ref value, _) => {
Self(Union::Decimal(value.clone(), AccessMode::ReadWrite))
}
#[cfg(not(feature = "no_index"))]
Union::Array(ref value, _) => Self(Union::Array(value.clone(), 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)),
#[cfg(not(feature = "no_std"))]
Union::TimeStamp(ref value, _) => {
Self(Union::TimeStamp(value.clone(), AccessMode::ReadWrite))
}
Union::Variant(ref value, _) => (***value).clone_into_dynamic(),
#[cfg(not(feature = "no_closure"))]
Union::Shared(ref cell, _) => Self(Union::Shared(cell.clone(), AccessMode::ReadWrite)),
}
}
}
impl Default for Dynamic {
#[inline(always)]
fn default() -> Self {
Self::UNIT
}
}
impl Dynamic {
pub const UNIT: Dynamic = Self(Union::Unit((), AccessMode::ReadWrite));
pub const TRUE: Dynamic = Self(Union::Bool(true, AccessMode::ReadWrite));
pub const FALSE: Dynamic = Self(Union::Bool(false, AccessMode::ReadWrite));
pub const ZERO: Dynamic = Self(Union::Int(0, AccessMode::ReadWrite));
pub const ONE: Dynamic = Self(Union::Int(1, AccessMode::ReadWrite));
pub const NEGATIVE_ONE: Dynamic = Self(Union::Int(-1, AccessMode::ReadWrite));
#[cfg(not(feature = "no_float"))]
pub const FLOAT_ZERO: Dynamic =
Self(Union::Float(FloatWrapper::new(0.0), AccessMode::ReadWrite));
#[cfg(not(feature = "no_float"))]
pub const FLOAT_ONE: Dynamic =
Self(Union::Float(FloatWrapper::new(1.0), AccessMode::ReadWrite));
#[cfg(not(feature = "no_float"))]
pub const FLOAT_NEGATIVE_ONE: Dynamic =
Self(Union::Float(FloatWrapper::new(-1.0), AccessMode::ReadWrite));
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,
#[cfg(not(feature = "no_float"))]
Union::Float(_, access) => access,
#[cfg(feature = "decimal")]
Union::Decimal(_, access) => access,
#[cfg(not(feature = "no_index"))]
Union::Array(_, access) => access,
#[cfg(not(feature = "no_object"))]
Union::Map(_, access) => access,
#[cfg(not(feature = "no_std"))]
Union::TimeStamp(_, access) => access,
#[cfg(not(feature = "no_closure"))]
Union::Shared(_, access) => access,
}
}
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,
#[cfg(not(feature = "no_float"))]
Union::Float(_, access) => *access = typ,
#[cfg(feature = "decimal")]
Union::Decimal(_, access) => *access = typ,
#[cfg(not(feature = "no_index"))]
Union::Array(_, access) => *access = typ,
#[cfg(not(feature = "no_object"))]
Union::Map(_, access) => *access = typ,
#[cfg(not(feature = "no_std"))]
Union::TimeStamp(_, access) => *access = typ,
#[cfg(not(feature = "no_closure"))]
Union::Shared(_, access) => *access = typ,
}
}
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, _) => {
#[cfg(not(feature = "sync"))]
let value = cell.borrow();
#[cfg(feature = "sync")]
let value = cell.read().unwrap();
return match value.access_mode() {
AccessMode::ReadWrite => false,
AccessMode::ReadOnly => true,
};
}
_ => (),
}
match self.access_mode() {
AccessMode::ReadWrite => false,
AccessMode::ReadOnly => true,
}
}
pub(crate) fn is_hashable(&self) -> bool {
match &self.0 {
Union::Unit(_, _)
| Union::Bool(_, _)
| Union::Str(_, _)
| Union::Char(_, _)
| Union::Int(_, _) => true,
#[cfg(not(feature = "no_float"))]
Union::Float(_, _) => true,
#[cfg(not(feature = "no_index"))]
Union::Array(_, _) => true,
#[cfg(not(feature = "no_object"))]
Union::Map(_, _) => true,
#[cfg(not(feature = "no_closure"))]
Union::Shared(cell, _) => {
#[cfg(not(feature = "sync"))]
let value = cell.borrow();
#[cfg(feature = "sync")]
let value = cell.read().unwrap();
value.is_hashable()
}
_ => false,
}
}
#[inline(always)]
pub fn from<T: Variant + Clone>(mut value: T) -> Self {
if TypeId::of::<T>() == TypeId::of::<Dynamic>() {
return unsafe_try_cast::<_, Dynamic>(value).ok().unwrap();
}
if TypeId::of::<T>() == TypeId::of::<INT>() {
return <dyn Any>::downcast_ref::<INT>(&value)
.unwrap()
.clone()
.into();
}
#[cfg(not(feature = "no_float"))]
if TypeId::of::<T>() == TypeId::of::<FLOAT>() {
return <dyn Any>::downcast_ref::<FLOAT>(&value)
.unwrap()
.clone()
.into();
}
#[cfg(feature = "decimal")]
if TypeId::of::<T>() == TypeId::of::<Decimal>() {
return <dyn Any>::downcast_ref::<Decimal>(&value)
.unwrap()
.clone()
.into();
}
if TypeId::of::<T>() == TypeId::of::<bool>() {
return <dyn Any>::downcast_ref::<bool>(&value)
.unwrap()
.clone()
.into();
}
if TypeId::of::<T>() == TypeId::of::<char>() {
return <dyn Any>::downcast_ref::<char>(&value)
.unwrap()
.clone()
.into();
}
if TypeId::of::<T>() == TypeId::of::<ImmutableString>() {
return <dyn Any>::downcast_ref::<ImmutableString>(&value)
.unwrap()
.clone()
.into();
}
if TypeId::of::<T>() == TypeId::of::<&str>() {
return <dyn Any>::downcast_ref::<&str>(&value)
.unwrap()
.deref()
.into();
}
if TypeId::of::<T>() == TypeId::of::<()>() {
return ().into();
}
value = match unsafe_try_cast::<_, String>(value) {
Ok(s) => return (s).into(),
Err(val) => val,
};
#[cfg(not(feature = "no_index"))]
{
value = match unsafe_try_cast::<_, Array>(value) {
Ok(array) => return (array).into(),
Err(val) => val,
};
}
#[cfg(not(feature = "no_object"))]
{
value = match unsafe_try_cast::<_, Map>(value) {
Ok(map) => return (map).into(),
Err(val) => val,
};
}
value = match unsafe_try_cast::<_, FnPtr>(value) {
Ok(fn_ptr) => return (fn_ptr).into(),
Err(val) => val,
};
#[cfg(not(feature = "no_std"))]
{
value = match unsafe_try_cast::<_, Instant>(value) {
Ok(timestamp) => return (timestamp).into(),
Err(val) => val,
};
}
Self(Union::Variant(
Box::new(Box::new(value)),
AccessMode::ReadWrite,
))
}
#[cfg(not(feature = "no_closure"))]
#[inline(always)]
pub fn into_shared(self) -> Self {
let _access = self.access_mode();
match self.0 {
Union::Shared(_, _) => self,
_ => Self(Union::Shared(crate::Locked::new(self).into(), _access)),
}
}
#[inline(always)]
pub fn try_cast<T: Variant>(self) -> Option<T> {
#[cfg(not(feature = "no_closure"))]
if let Union::Shared(_, _) = self.0 {
return self.flatten().try_cast::<T>();
}
if TypeId::of::<T>() == TypeId::of::<Dynamic>() {
return unsafe_try_cast::<_, T>(self).ok();
}
if TypeId::of::<T>() == TypeId::of::<INT>() {
return match self.0 {
Union::Int(value, _) => unsafe_try_cast(value).ok(),
_ => None,
};
}
#[cfg(not(feature = "no_float"))]
if TypeId::of::<T>() == TypeId::of::<FLOAT>() {
return match self.0 {
Union::Float(value, _) => unsafe_try_cast(*value).ok(),
_ => None,
};
}
#[cfg(feature = "decimal")]
if TypeId::of::<T>() == TypeId::of::<Decimal>() {
return match self.0 {
Union::Decimal(value, _) => unsafe_try_cast(*value).ok(),
_ => None,
};
}
if TypeId::of::<T>() == TypeId::of::<bool>() {
return match self.0 {
Union::Bool(value, _) => unsafe_try_cast(value).ok(),
_ => None,
};
}
if TypeId::of::<T>() == TypeId::of::<ImmutableString>() {
return match self.0 {
Union::Str(value, _) => unsafe_try_cast(value).ok(),
_ => None,
};
}
if TypeId::of::<T>() == TypeId::of::<String>() {
return match self.0 {
Union::Str(value, _) => unsafe_try_cast(value.into_owned()).ok(),
_ => None,
};
}
if TypeId::of::<T>() == TypeId::of::<char>() {
return match self.0 {
Union::Char(value, _) => unsafe_try_cast(value).ok(),
_ => None,
};
}
#[cfg(not(feature = "no_index"))]
if TypeId::of::<T>() == TypeId::of::<Array>() {
return match self.0 {
Union::Array(value, _) => unsafe_cast_box::<_, T>(value).ok().map(|v| *v),
_ => None,
};
}
#[cfg(not(feature = "no_object"))]
if TypeId::of::<T>() == TypeId::of::<Map>() {
return match self.0 {
Union::Map(value, _) => unsafe_cast_box::<_, T>(value).ok().map(|v| *v),
_ => None,
};
}
if TypeId::of::<T>() == TypeId::of::<FnPtr>() {
return match self.0 {
Union::FnPtr(value, _) => unsafe_cast_box::<_, T>(value).ok().map(|v| *v),
_ => None,
};
}
#[cfg(not(feature = "no_std"))]
if TypeId::of::<T>() == TypeId::of::<Instant>() {
return match self.0 {
Union::TimeStamp(value, _) => unsafe_cast_box::<_, T>(value).ok().map(|v| *v),
_ => None,
};
}
if TypeId::of::<T>() == TypeId::of::<()>() {
return match self.0 {
Union::Unit(value, _) => unsafe_try_cast(value).ok(),
_ => None,
};
}
match self.0 {
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"),
_ => None,
}
}
#[inline(always)]
pub fn cast<T: Variant + Clone>(self) -> T {
let self_type_name = if self.is_shared() {
"<shared>"
} else {
self.type_name()
};
self.try_cast::<T>().unwrap_or_else(|| {
panic!(
"cannot cast {} value and to {}",
self_type_name,
type_name::<T>()
)
})
}
#[inline(always)]
pub fn clone_cast<T: Variant + Clone>(&self) -> T {
self.read_lock::<T>().unwrap().clone()
}
#[inline(always)]
pub fn flatten_clone(&self) -> Self {
#[cfg(not(feature = "no_closure"))]
match &self.0 {
Union::Shared(cell, _) => {
#[cfg(not(feature = "sync"))]
let value = cell.borrow();
#[cfg(feature = "sync")]
let value = cell.read().unwrap();
return value.clone();
}
_ => (),
}
self.clone()
}
#[inline(always)]
pub fn flatten(self) -> Self {
#[cfg(not(feature = "no_closure"))]
match self.0 {
Union::Shared(cell, _) => {
return crate::fn_native::shared_try_take(cell).map_or_else(
|cell| {
#[cfg(not(feature = "sync"))]
let value = cell.borrow();
#[cfg(feature = "sync")]
let value = cell.read().unwrap();
value.clone()
},
|value| {
#[cfg(not(feature = "sync"))]
return value.into_inner();
#[cfg(feature = "sync")]
return value.into_inner().unwrap();
},
)
}
_ => (),
}
self
}
#[inline(always)]
pub(crate) fn flatten_in_place(&mut self) {
#[cfg(not(feature = "no_closure"))]
match self.0 {
Union::Shared(_, _) => match crate::stdlib::mem::take(self).0 {
Union::Shared(cell, _) => {
*self = crate::fn_native::shared_try_take(cell).map_or_else(
|cell| {
#[cfg(not(feature = "sync"))]
let value = cell.borrow();
#[cfg(feature = "sync")]
let value = cell.read().unwrap();
value.clone()
},
|value| {
#[cfg(not(feature = "sync"))]
return value.into_inner();
#[cfg(feature = "sync")]
return value.into_inner().unwrap();
},
)
}
_ => unreachable!(),
},
_ => (),
}
}
#[inline(always)]
pub fn is_locked(&self) -> bool {
#[cfg(not(feature = "no_closure"))]
match self.0 {
Union::Shared(ref _cell, _) => {
#[cfg(not(feature = "sync"))]
return _cell.try_borrow().is_err();
#[cfg(feature = "sync")]
return false;
}
_ => (),
}
false
}
#[inline(always)]
pub fn read_lock<T: Variant + Clone>(&self) -> Option<DynamicReadLock<T>> {
match self.0 {
#[cfg(not(feature = "no_closure"))]
Union::Shared(ref cell, _) => {
#[cfg(not(feature = "sync"))]
let value = cell.borrow();
#[cfg(feature = "sync")]
let value = cell.read().unwrap();
let type_id = (*value).type_id();
if type_id != TypeId::of::<T>() && TypeId::of::<Dynamic>() != TypeId::of::<T>() {
return None;
} else {
return Some(DynamicReadLock(DynamicReadLockInner::Guard(value)));
}
}
_ => (),
}
self.downcast_ref()
.map(|r| DynamicReadLock(DynamicReadLockInner::Reference(r)))
}
#[inline(always)]
pub fn write_lock<T: Variant + Clone>(&mut self) -> Option<DynamicWriteLock<T>> {
match self.0 {
#[cfg(not(feature = "no_closure"))]
Union::Shared(ref cell, _) => {
#[cfg(not(feature = "sync"))]
let value = cell.borrow_mut();
#[cfg(feature = "sync")]
let value = cell.write().unwrap();
let type_id = (*value).type_id();
if type_id != TypeId::of::<T>() && TypeId::of::<Dynamic>() != TypeId::of::<T>() {
return None;
} else {
return Some(DynamicWriteLock(DynamicWriteLockInner::Guard(value)));
}
}
_ => (),
}
self.downcast_mut()
.map(|r| DynamicWriteLock(DynamicWriteLockInner::Reference(r)))
}
#[inline(always)]
pub(crate) fn downcast_ref<T: Variant + Clone>(&self) -> Option<&T> {
if TypeId::of::<T>() == TypeId::of::<INT>() {
return match &self.0 {
Union::Int(value, _) => <dyn Any>::downcast_ref::<T>(value),
_ => None,
};
}
#[cfg(not(feature = "no_float"))]
if TypeId::of::<T>() == TypeId::of::<FLOAT>() {
return match &self.0 {
Union::Float(value, _) => <dyn Any>::downcast_ref::<T>(value.as_ref()),
_ => None,
};
}
#[cfg(feature = "decimal")]
if TypeId::of::<T>() == TypeId::of::<Decimal>() {
return match &self.0 {
Union::Decimal(value, _) => <dyn Any>::downcast_ref::<T>(value.as_ref()),
_ => None,
};
}
if TypeId::of::<T>() == TypeId::of::<bool>() {
return match &self.0 {
Union::Bool(value, _) => <dyn Any>::downcast_ref::<T>(value),
_ => None,
};
}
if TypeId::of::<T>() == TypeId::of::<ImmutableString>() {
return match &self.0 {
Union::Str(value, _) => <dyn Any>::downcast_ref::<T>(value),
_ => None,
};
}
if TypeId::of::<T>() == TypeId::of::<String>() {
return match &self.0 {
Union::Str(value, _) => <dyn Any>::downcast_ref::<T>(value.as_ref() as &String),
_ => None,
};
}
if TypeId::of::<T>() == TypeId::of::<char>() {
return match &self.0 {
Union::Char(value, _) => <dyn Any>::downcast_ref::<T>(value),
_ => None,
};
}
#[cfg(not(feature = "no_index"))]
if TypeId::of::<T>() == TypeId::of::<Array>() {
return match &self.0 {
Union::Array(value, _) => <dyn Any>::downcast_ref::<T>(value.as_ref()),
_ => None,
};
}
#[cfg(not(feature = "no_object"))]
if TypeId::of::<T>() == TypeId::of::<Map>() {
return match &self.0 {
Union::Map(value, _) => <dyn Any>::downcast_ref::<T>(value.as_ref()),
_ => None,
};
}
if TypeId::of::<T>() == TypeId::of::<FnPtr>() {
return match &self.0 {
Union::FnPtr(value, _) => <dyn Any>::downcast_ref::<T>(value.as_ref()),
_ => None,
};
}
#[cfg(not(feature = "no_std"))]
if TypeId::of::<T>() == TypeId::of::<Instant>() {
return match &self.0 {
Union::TimeStamp(value, _) => <dyn Any>::downcast_ref::<T>(value.as_ref()),
_ => None,
};
}
if TypeId::of::<T>() == TypeId::of::<()>() {
return match &self.0 {
Union::Unit(value, _) => <dyn Any>::downcast_ref::<T>(value),
_ => None,
};
}
if TypeId::of::<T>() == TypeId::of::<Dynamic>() {
return <dyn Any>::downcast_ref::<T>(self);
}
match &self.0 {
Union::Variant(value, _) => value.as_ref().as_ref().as_any().downcast_ref::<T>(),
#[cfg(not(feature = "no_closure"))]
Union::Shared(_, _) => None,
_ => None,
}
}
#[inline(always)]
pub(crate) fn downcast_mut<T: Variant + Clone>(&mut self) -> Option<&mut T> {
if TypeId::of::<T>() == TypeId::of::<INT>() {
return match &mut self.0 {
Union::Int(value, _) => <dyn Any>::downcast_mut::<T>(value),
_ => None,
};
}
#[cfg(not(feature = "no_float"))]
if TypeId::of::<T>() == TypeId::of::<FLOAT>() {
return match &mut self.0 {
Union::Float(value, _) => <dyn Any>::downcast_mut::<T>(value.as_mut()),
_ => None,
};
}
#[cfg(feature = "decimal")]
if TypeId::of::<T>() == TypeId::of::<Decimal>() {
return match &mut self.0 {
Union::Decimal(value, _) => <dyn Any>::downcast_mut::<T>(value.as_mut()),
_ => None,
};
}
if TypeId::of::<T>() == TypeId::of::<bool>() {
return match &mut self.0 {
Union::Bool(value, _) => <dyn Any>::downcast_mut::<T>(value),
_ => None,
};
}
if TypeId::of::<T>() == TypeId::of::<ImmutableString>() {
return match &mut self.0 {
Union::Str(value, _) => <dyn Any>::downcast_mut::<T>(value),
_ => None,
};
}
if TypeId::of::<T>() == TypeId::of::<char>() {
return match &mut self.0 {
Union::Char(value, _) => <dyn Any>::downcast_mut::<T>(value),
_ => None,
};
}
#[cfg(not(feature = "no_index"))]
if TypeId::of::<T>() == TypeId::of::<Array>() {
return match &mut self.0 {
Union::Array(value, _) => <dyn Any>::downcast_mut::<T>(value.as_mut()),
_ => None,
};
}
#[cfg(not(feature = "no_object"))]
if TypeId::of::<T>() == TypeId::of::<Map>() {
return match &mut self.0 {
Union::Map(value, _) => <dyn Any>::downcast_mut::<T>(value.as_mut()),
_ => None,
};
}
if TypeId::of::<T>() == TypeId::of::<FnPtr>() {
return match &mut self.0 {
Union::FnPtr(value, _) => <dyn Any>::downcast_mut::<T>(value.as_mut()),
_ => None,
};
}
#[cfg(not(feature = "no_std"))]
if TypeId::of::<T>() == TypeId::of::<Instant>() {
return match &mut self.0 {
Union::TimeStamp(value, _) => <dyn Any>::downcast_mut::<T>(value.as_mut()),
_ => None,
};
}
if TypeId::of::<T>() == TypeId::of::<()>() {
return match &mut self.0 {
Union::Unit(value, _) => <dyn Any>::downcast_mut::<T>(value),
_ => None,
};
}
if TypeId::of::<T>() == TypeId::of::<Dynamic>() {
return <dyn Any>::downcast_mut::<T>(self);
}
match &mut self.0 {
Union::Variant(value, _) => value.as_mut().as_mut_any().downcast_mut::<T>(),
#[cfg(not(feature = "no_closure"))]
Union::Shared(_, _) => None,
_ => None,
}
}
#[inline(always)]
pub fn as_unit(&self) -> Result<(), &'static str> {
match self.0 {
Union::Unit(value, _) => Ok(value),
#[cfg(not(feature = "no_closure"))]
Union::Shared(_, _) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()),
_ => Err(self.type_name()),
}
}
#[inline(always)]
pub fn as_int(&self) -> Result<INT, &'static str> {
match self.0 {
Union::Int(n, _) => Ok(n),
#[cfg(not(feature = "no_closure"))]
Union::Shared(_, _) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()),
_ => Err(self.type_name()),
}
}
#[cfg(not(feature = "no_float"))]
#[inline(always)]
pub fn as_float(&self) -> Result<FLOAT, &'static str> {
match self.0 {
Union::Float(n, _) => Ok(*n),
#[cfg(not(feature = "no_closure"))]
Union::Shared(_, _) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()),
_ => Err(self.type_name()),
}
}
#[cfg(feature = "decimal")]
#[inline(always)]
pub fn as_decimal(&self) -> Result<Decimal, &'static str> {
match &self.0 {
Union::Decimal(n, _) => Ok(**n),
#[cfg(not(feature = "no_closure"))]
Union::Shared(_, _) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()),
_ => Err(self.type_name()),
}
}
#[inline(always)]
pub fn as_bool(&self) -> Result<bool, &'static str> {
match self.0 {
Union::Bool(b, _) => Ok(b),
#[cfg(not(feature = "no_closure"))]
Union::Shared(_, _) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()),
_ => Err(self.type_name()),
}
}
#[inline(always)]
pub fn as_char(&self) -> Result<char, &'static str> {
match self.0 {
Union::Char(n, _) => Ok(n),
#[cfg(not(feature = "no_closure"))]
Union::Shared(_, _) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()),
_ => Err(self.type_name()),
}
}
#[inline(always)]
pub(crate) fn as_str_ref(&self) -> Result<&str, &'static str> {
match &self.0 {
Union::Str(s, _) => Ok(s),
#[cfg(not(feature = "no_closure"))]
Union::Shared(_, _) => panic!("as_str() cannot be called on shared values"),
_ => Err(self.type_name()),
}
}
#[inline(always)]
pub fn take_string(self) -> Result<String, &'static str> {
self.take_immutable_string()
.map(ImmutableString::into_owned)
}
#[inline(always)]
pub fn take_immutable_string(self) -> Result<ImmutableString, &'static str> {
match self.0 {
Union::Str(s, _) => Ok(s),
#[cfg(not(feature = "no_closure"))]
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()),
_ => Err((*value).type_name()),
}
}
_ => Err(self.type_name()),
}
}
}
impl From<()> for Dynamic {
#[inline(always)]
fn from(value: ()) -> Self {
Self(Union::Unit(value, AccessMode::ReadWrite))
}
}
impl From<bool> for Dynamic {
#[inline(always)]
fn from(value: bool) -> Self {
Self(Union::Bool(value, AccessMode::ReadWrite))
}
}
impl From<INT> for Dynamic {
#[inline(always)]
fn from(value: INT) -> Self {
Self(Union::Int(value, AccessMode::ReadWrite))
}
}
#[cfg(not(feature = "no_float"))]
impl From<FLOAT> for Dynamic {
#[inline(always)]
fn from(value: FLOAT) -> Self {
Self(Union::Float(value.into(), AccessMode::ReadWrite))
}
}
#[cfg(not(feature = "no_float"))]
impl From<FloatWrapper> for Dynamic {
#[inline(always)]
fn from(value: FloatWrapper) -> Self {
Self(Union::Float(value, AccessMode::ReadWrite))
}
}
#[cfg(feature = "decimal")]
impl From<Decimal> for Dynamic {
#[inline(always)]
fn from(value: Decimal) -> Self {
Self(Union::Decimal(
Box::new(value.into()),
AccessMode::ReadWrite,
))
}
}
impl From<char> for Dynamic {
#[inline(always)]
fn from(value: char) -> Self {
Self(Union::Char(value, AccessMode::ReadWrite))
}
}
impl<S: Into<ImmutableString>> From<S> for Dynamic {
#[inline(always)]
fn from(value: S) -> Self {
Self(Union::Str(value.into(), AccessMode::ReadWrite))
}
}
impl From<&ImmutableString> for Dynamic {
#[inline(always)]
fn from(value: &ImmutableString) -> Self {
value.clone().into()
}
}
#[cfg(not(feature = "no_smartstring"))]
impl From<&crate::Identifier> for Dynamic {
#[inline(always)]
fn from(value: &crate::Identifier) -> Self {
crate::stdlib::string::ToString::to_string(value).into()
}
}
#[cfg(not(feature = "no_index"))]
impl<T: Variant + Clone> From<crate::stdlib::vec::Vec<T>> for Dynamic {
#[inline(always)]
fn from(value: crate::stdlib::vec::Vec<T>) -> Self {
Self(Union::Array(
Box::new(value.into_iter().map(Dynamic::from).collect()),
AccessMode::ReadWrite,
))
}
}
#[cfg(not(feature = "no_index"))]
impl<T: Variant + Clone> From<&[T]> for Dynamic {
#[inline(always)]
fn from(value: &[T]) -> Self {
Self(Union::Array(
Box::new(value.iter().cloned().map(Dynamic::from).collect()),
AccessMode::ReadWrite,
))
}
}
#[cfg(not(feature = "no_index"))]
impl<T: Variant + Clone> crate::stdlib::iter::FromIterator<T> for Dynamic {
#[inline(always)]
fn from_iter<X: IntoIterator<Item = T>>(iter: X) -> Self {
Self(Union::Array(
Box::new(iter.into_iter().map(Dynamic::from).collect()),
AccessMode::ReadWrite,
))
}
}
#[cfg(not(feature = "no_object"))]
#[cfg(not(feature = "no_std"))]
impl<K: Into<crate::Identifier>, T: Variant + Clone> From<crate::stdlib::collections::HashMap<K, T>>
for Dynamic
{
#[inline(always)]
fn from(value: crate::stdlib::collections::HashMap<K, T>) -> Self {
Self(Union::Map(
Box::new(
value
.into_iter()
.map(|(k, v)| (k.into(), Dynamic::from(v)))
.collect(),
),
AccessMode::ReadWrite,
))
}
}
#[cfg(not(feature = "no_object"))]
impl<K: Into<crate::Identifier>, T: Variant + Clone>
From<crate::stdlib::collections::BTreeMap<K, T>> for Dynamic
{
#[inline(always)]
fn from(value: crate::stdlib::collections::BTreeMap<K, T>) -> Self {
Self(Union::Map(
Box::new(
value
.into_iter()
.map(|(k, v)| (k.into(), Dynamic::from(v)))
.collect(),
),
AccessMode::ReadWrite,
))
}
}
impl From<FnPtr> for Dynamic {
#[inline(always)]
fn from(value: FnPtr) -> Self {
Self(Union::FnPtr(Box::new(value), AccessMode::ReadWrite))
}
}
impl From<Box<FnPtr>> for Dynamic {
#[inline(always)]
fn from(value: Box<FnPtr>) -> Self {
Self(Union::FnPtr(value, AccessMode::ReadWrite))
}
}
#[cfg(not(feature = "no_std"))]
impl From<Instant> for Dynamic {
#[inline(always)]
fn from(value: Instant) -> Self {
Self(Union::TimeStamp(Box::new(value), AccessMode::ReadWrite))
}
}