rhai/src/dynamic.rs

1341 lines
45 KiB
Rust
Raw Normal View History

2020-03-08 12:54:02 +01:00
//! Helper module which defines the `Any` trait to to allow dynamic value handling.
2020-06-25 12:07:57 +02:00
use crate::fn_native::{FnPtr, SendSync};
use crate::r#unsafe::{unsafe_cast_box, unsafe_try_cast};
2020-10-29 04:37:51 +01:00
use crate::utils::ImmutableString;
use crate::INT;
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
use crate::fn_native::{shared_try_take, Locked, Shared};
2020-04-12 17:00:06 +02:00
#[cfg(not(feature = "no_float"))]
2020-10-29 04:37:51 +01:00
use crate::FLOAT;
2020-04-12 17:00:06 +02:00
#[cfg(not(feature = "no_index"))]
use crate::engine::Array;
#[cfg(not(feature = "no_object"))]
use crate::{engine::Map, StaticVec};
2020-03-17 19:26:11 +01:00
use crate::stdlib::{
2020-04-12 17:00:06 +02:00
any::{type_name, Any, TypeId},
2020-03-17 19:26:11 +01:00
boxed::Box,
2020-05-15 15:40:54 +02:00
fmt,
2020-11-12 14:53:26 +01:00
hash::{Hash, Hasher},
2020-11-15 11:39:23 +01:00
mem,
ops::{Deref, DerefMut},
2020-10-07 05:44:06 +02:00
string::{String, ToString},
2020-03-10 03:07:44 +01:00
};
2017-12-20 12:16:14 +01:00
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
#[cfg(not(feature = "sync"))]
use crate::stdlib::cell::{Ref, RefMut};
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
#[cfg(feature = "sync")]
use crate::stdlib::sync::{RwLockReadGuard, RwLockWriteGuard};
2020-07-26 09:53:22 +02:00
#[cfg(not(feature = "no_object"))]
use crate::stdlib::collections::HashMap;
#[cfg(not(feature = "no_index"))]
use crate::stdlib::vec::Vec;
#[cfg(not(feature = "no_std"))]
2020-06-16 17:47:31 +02:00
#[cfg(not(target_arch = "wasm32"))]
use crate::stdlib::time::Instant;
2020-06-17 10:50:57 +02:00
#[cfg(not(feature = "no_std"))]
#[cfg(target_arch = "wasm32")]
use instant::Instant;
mod private {
use crate::fn_native::SendSync;
use crate::stdlib::any::Any;
2020-07-25 10:09:13 +02:00
/// A sealed trait that prevents other crates from implementing [`Variant`].
///
2020-07-25 10:09:13 +02:00
/// [`Variant`]: super::Variant
pub trait Sealed {}
impl<T: Any + Clone + SendSync> Sealed for T {}
}
2020-05-15 15:40:54 +02:00
/// Trait to represent any type.
2020-04-03 13:42:01 +02:00
///
/// Currently, `Variant` is not `Send` nor `Sync`, so it can practically be any type.
/// Turn on the `sync` feature to restrict it to only types that implement `Send + Sync`.
2020-04-12 17:00:06 +02:00
#[cfg(not(feature = "sync"))]
pub trait Variant: Any + private::Sealed {
2020-04-12 17:00:06 +02:00
/// Convert this `Variant` trait object to `&dyn Any`.
fn as_any(&self) -> &dyn Any;
2020-04-12 17:00:06 +02:00
/// Convert this `Variant` trait object to `&mut dyn Any`.
fn as_mut_any(&mut self) -> &mut dyn Any;
2017-12-20 12:16:14 +01:00
/// Convert this `Variant` trait object to an `Any` trait object.
fn as_box_any(self: Box<Self>) -> Box<dyn Any>;
2020-03-04 15:00:01 +01:00
/// Get the name of this type.
2020-03-03 09:24:03 +01:00
fn type_name(&self) -> &'static str;
2019-09-30 19:57:21 +02:00
2020-03-04 15:00:01 +01:00
/// Convert into `Dynamic`.
2020-04-12 17:00:06 +02:00
fn into_dynamic(self) -> Dynamic;
/// Clone into `Dynamic`.
fn clone_into_dynamic(&self) -> Dynamic;
2017-12-20 12:16:14 +01:00
}
2020-05-15 15:40:54 +02:00
/// Trait to represent any type.
///
/// `From<_>` is implemented for `i64` (`i32` if `only_i32`), `f64` (if not `no_float`),
/// `bool`, `String`, `char`, `Vec<T>` (into `Array`) and `HashMap<String, T>` (into `Map`).
2020-04-12 17:00:06 +02:00
#[cfg(feature = "sync")]
pub trait Variant: Any + Send + Sync + private::Sealed {
2020-04-12 17:00:06 +02:00
/// Convert this `Variant` trait object to `&dyn Any`.
fn as_any(&self) -> &dyn Any;
/// Convert this `Variant` trait object to `&mut dyn Any`.
fn as_mut_any(&mut self) -> &mut dyn Any;
/// Convert this `Variant` trait object to an `Any` trait object.
2020-05-12 10:32:22 +02:00
fn as_box_any(self: Box<Self>) -> Box<dyn Any>;
/// Get the name of this type.
fn type_name(&self) -> &'static str;
/// Convert into `Dynamic`.
2020-04-12 17:00:06 +02:00
fn into_dynamic(self) -> Dynamic;
/// Clone into `Dynamic`.
fn clone_into_dynamic(&self) -> Dynamic;
}
impl<T: Any + Clone + SendSync> Variant for T {
2020-04-12 17:00:06 +02:00
fn as_any(&self) -> &dyn Any {
2020-06-23 13:24:26 +02:00
self
2020-04-12 17:00:06 +02:00
}
fn as_mut_any(&mut self) -> &mut dyn Any {
2020-06-23 13:24:26 +02:00
self
2017-12-20 12:16:14 +01:00
}
fn as_box_any(self: Box<Self>) -> Box<dyn Any> {
2020-06-23 13:24:26 +02:00
self
}
2020-03-03 09:24:03 +01:00
fn type_name(&self) -> &'static str {
type_name::<T>()
2019-09-30 19:57:21 +02:00
}
2020-04-12 17:00:06 +02:00
fn into_dynamic(self) -> Dynamic {
Dynamic::from(self)
}
fn clone_into_dynamic(&self) -> Dynamic {
Dynamic::from(self.clone())
2017-12-20 12:16:14 +01:00
}
2019-09-18 12:21:07 +02:00
}
2017-12-20 12:16:14 +01:00
2020-04-12 17:00:06 +02:00
impl dyn Variant {
2020-03-04 15:00:01 +01:00
/// Is this `Variant` a specific type?
2020-08-08 05:46:30 +02:00
#[inline(always)]
pub fn is<T: Any>(&self) -> bool {
2020-04-12 17:00:06 +02:00
TypeId::of::<T>() == self.type_id()
2017-12-20 12:16:14 +01:00
}
2020-04-12 17:00:06 +02:00
}
2020-05-15 15:40:54 +02:00
/// Dynamic type containing any value.
2020-04-12 17:00:06 +02:00
pub struct Dynamic(pub(crate) Union);
/// Internal `Dynamic` representation.
2020-05-09 18:19:13 +02:00
///
/// Most variants are boxed to reduce the size.
2020-04-12 17:00:06 +02:00
pub enum Union {
Unit(()),
Bool(bool),
2020-05-25 07:44:28 +02:00
Str(ImmutableString),
2020-04-12 17:00:06 +02:00
Char(char),
Int(INT),
#[cfg(not(feature = "no_float"))]
Float(FLOAT),
#[cfg(not(feature = "no_index"))]
Array(Box<Array>),
#[cfg(not(feature = "no_object"))]
Map(Box<Map>),
2020-07-22 17:12:09 +02:00
FnPtr(Box<FnPtr>),
2020-09-27 16:15:35 +02:00
#[cfg(not(feature = "no_std"))]
TimeStamp(Box<Instant>),
2020-08-08 10:24:10 +02:00
Variant(Box<Box<dyn Variant>>),
2020-08-08 10:24:10 +02:00
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
Shared(Shared<Locked<Dynamic>>),
}
/// Underlying `Variant` read guard for `Dynamic`.
///
/// This data structure provides transparent interoperability between
/// normal `Dynamic` and shared Dynamic values.
#[derive(Debug)]
pub struct DynamicReadLock<'d, T: Variant + Clone>(DynamicReadLockInner<'d, T>);
/// Different types of read guards for `DynamicReadLock`.
#[derive(Debug)]
enum DynamicReadLockInner<'d, T: Variant + Clone> {
/// A simple reference to a non-shared value.
Reference(&'d T),
2020-08-08 10:24:10 +02:00
/// A read guard to a shared `RefCell`.
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
#[cfg(not(feature = "sync"))]
Guard(Ref<'d, Dynamic>),
/// A read guard to a shared `RwLock`.
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
#[cfg(feature = "sync")]
Guard(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,
// Unwrapping is safe because all checking is already done in its constructor
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
DynamicReadLockInner::Guard(guard) => guard.downcast_ref().unwrap(),
}
}
}
/// Underlying `Variant` write guard for `Dynamic`.
///
/// This data structure provides transparent interoperability between
/// normal `Dynamic` and shared Dynamic values.
#[derive(Debug)]
pub struct DynamicWriteLock<'d, T: Variant + Clone>(DynamicWriteLockInner<'d, T>);
/// Different types of write guards for `DynamicReadLock`.
#[derive(Debug)]
enum DynamicWriteLockInner<'d, T: Variant + Clone> {
/// A simple mutable reference to a non-shared value.
Reference(&'d mut T),
2020-08-08 10:24:10 +02:00
/// A write guard to a shared `RefCell`.
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
#[cfg(not(feature = "sync"))]
Guard(RefMut<'d, Dynamic>),
/// A write guard to a shared `RwLock`.
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
#[cfg(feature = "sync")]
Guard(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,
// Unwrapping is safe because all checking is already done in its constructor
2020-08-03 06:10:20 +02:00
#[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,
// Unwrapping is safe because all checking is already done in its constructor
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
DynamicWriteLockInner::Guard(guard) => guard.downcast_mut().unwrap(),
}
}
2020-04-12 17:00:06 +02:00
}
impl Dynamic {
2020-04-13 04:27:08 +02:00
/// Does this `Dynamic` hold a variant data type
/// instead of one of the support system primitive types?
2020-08-08 05:46:30 +02:00
#[inline(always)]
2020-04-13 04:27:08 +02:00
pub fn is_variant(&self) -> bool {
match self.0 {
Union::Variant(_) => true,
_ => false,
}
}
/// Does this `Dynamic` hold a shared data type
/// instead of one of the supported system primitive types?
2020-08-08 05:46:30 +02:00
#[inline(always)]
pub fn is_shared(&self) -> bool {
match self.0 {
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
Union::Shared(_) => true,
_ => false,
}
}
2020-04-12 17:00:06 +02:00
/// Is the value held by this `Dynamic` a particular type?
///
/// If the `Dynamic` is a Shared variant checking is performed on
/// top of it's internal value.
2020-08-08 05:46:30 +02:00
#[inline(always)]
2020-04-12 17:00:06 +02:00
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
2020-04-12 17:00:06 +02:00
}
/// Get the TypeId of the value held by this `Dynamic`.
2020-08-02 07:33:51 +02:00
///
2020-08-04 10:27:55 +02:00
/// # Panics or Deadlocks When Value is Shared
2020-08-02 07:33:51 +02:00
///
2020-08-04 10:27:55 +02:00
/// Under the `sync` feature, this call may deadlock, or [panic](https://doc.rust-lang.org/std/sync/struct.RwLock.html#panics-1).
2020-08-02 07:33:51 +02:00
/// Otherwise, this call panics if the data is currently borrowed for write.
2020-04-12 17:00:06 +02:00
pub fn type_id(&self) -> TypeId {
match &self.0 {
Union::Unit(_) => TypeId::of::<()>(),
Union::Bool(_) => TypeId::of::<bool>(),
2020-05-25 07:44:28 +02:00
Union::Str(_) => TypeId::of::<ImmutableString>(),
2020-04-12 17:00:06 +02:00
Union::Char(_) => TypeId::of::<char>(),
Union::Int(_) => TypeId::of::<INT>(),
#[cfg(not(feature = "no_float"))]
Union::Float(_) => TypeId::of::<FLOAT>(),
#[cfg(not(feature = "no_index"))]
2020-04-12 17:00:06 +02:00
Union::Array(_) => TypeId::of::<Array>(),
#[cfg(not(feature = "no_object"))]
2020-04-12 17:00:06 +02:00
Union::Map(_) => TypeId::of::<Map>(),
2020-06-25 12:07:57 +02:00
Union::FnPtr(_) => TypeId::of::<FnPtr>(),
2020-09-27 16:15:35 +02:00
#[cfg(not(feature = "no_std"))]
Union::TimeStamp(_) => TypeId::of::<Instant>(),
2020-08-08 05:46:30 +02:00
Union::Variant(value) => (***value).type_id(),
2020-08-08 05:46:30 +02:00
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
#[cfg(not(feature = "sync"))]
Union::Shared(cell) => (*cell.borrow()).type_id(),
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
#[cfg(feature = "sync")]
Union::Shared(cell) => (*cell.read().unwrap()).type_id(),
2020-04-12 17:00:06 +02:00
}
}
/// Get the name of the type of the value held by this `Dynamic`.
2020-08-02 07:33:51 +02:00
///
2020-08-04 10:27:55 +02:00
/// # Panics or Deadlocks When Value is Shared
2020-08-02 07:33:51 +02:00
///
2020-08-04 10:27:55 +02:00
/// Under the `sync` feature, this call may deadlock, or [panic](https://doc.rust-lang.org/std/sync/struct.RwLock.html#panics-1).
2020-08-02 07:33:51 +02:00
/// Otherwise, this call panics if the data is currently borrowed for write.
2020-04-12 17:00:06 +02:00
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(not(feature = "no_index"))]
2020-04-12 17:00:06 +02:00
Union::Array(_) => "array",
#[cfg(not(feature = "no_object"))]
2020-04-12 17:00:06 +02:00
Union::Map(_) => "map",
2020-06-25 12:07:57 +02:00
Union::FnPtr(_) => "Fn",
#[cfg(not(feature = "no_std"))]
2020-09-27 16:15:35 +02:00
Union::TimeStamp(_) => "timestamp",
Union::Variant(value) => (***value).type_name(),
2020-08-08 05:46:30 +02:00
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
#[cfg(not(feature = "sync"))]
2020-08-04 03:47:48 +02:00
Union::Shared(cell) => cell
.try_borrow()
.map(|v| (*v).type_name())
.unwrap_or("<shared>"),
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
#[cfg(feature = "sync")]
Union::Shared(cell) => (*cell.read().unwrap()).type_name(),
2017-12-20 12:16:14 +01:00
}
}
}
2020-11-12 14:53:26 +01:00
impl Hash for Dynamic {
fn hash<H: Hasher>(&self, state: &mut H) {
2020-11-15 11:39:23 +01:00
mem::discriminant(self).hash(state);
2020-11-12 14:53:26 +01:00
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"))]
2020-11-15 11:39:23 +01:00
Union::Float(f) => f.to_le_bytes().hash(state),
2020-11-12 14:53:26 +01:00
#[cfg(not(feature = "no_index"))]
2020-11-15 11:39:23 +01:00
Union::Array(a) => (**a).hash(state),
2020-11-12 14:53:26 +01:00
#[cfg(not(feature = "no_object"))]
2020-11-13 11:32:18 +01:00
Union::Map(m) => {
2020-11-15 11:39:23 +01:00
let mut buf: StaticVec<_> = m.iter().collect();
buf.sort_by(|(a, _), (b, _)| a.cmp(b));
2020-11-13 11:32:18 +01:00
2020-11-15 11:39:23 +01:00
buf.into_iter().for_each(|(key, value)| {
2020-11-13 11:32:18 +01:00
key.hash(state);
2020-11-15 11:39:23 +01:00
value.hash(state);
2020-11-13 11:32:18 +01:00
})
}
2020-11-12 14:53:26 +01:00
#[cfg(not(feature = "no_closure"))]
#[cfg(not(feature = "sync"))]
Union::Shared(cell) => (*cell.borrow()).hash(state),
#[cfg(not(feature = "no_closure"))]
#[cfg(feature = "sync")]
2020-11-12 16:09:27 +01:00
Union::Shared(cell) => (*cell.read().unwrap()).hash(state),
2020-11-12 14:53:26 +01:00
_ => unimplemented!(),
}
}
}
2020-07-03 04:45:01 +02:00
/// Map the name of a standard type into a friendly form.
2020-07-22 07:05:24 +02:00
#[inline]
2020-07-03 04:45:01 +02:00
pub(crate) fn map_std_type_name(name: &str) -> &str {
if name == type_name::<String>() {
"string"
} else if name == type_name::<ImmutableString>() {
"string"
} else if name == type_name::<&str>() {
"string"
} else if name == type_name::<FnPtr>() {
"Fn"
} else {
2020-07-03 16:42:56 +02:00
#[cfg(not(feature = "no_index"))]
if name == type_name::<Array>() {
return "array";
}
#[cfg(not(feature = "no_object"))]
if name == type_name::<Map>() {
return "map";
}
2020-09-27 16:15:35 +02:00
#[cfg(not(feature = "no_std"))]
if name == type_name::<Instant>() {
return "timestamp";
}
2020-07-03 16:42:56 +02:00
2020-07-03 04:45:01 +02:00
name
}
}
2020-04-12 17:00:06 +02:00
impl fmt::Display for Dynamic {
2019-09-18 12:21:07 +02:00
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2020-04-12 17:00:06 +02:00
match &self.0 {
Union::Unit(_) => write!(f, ""),
2020-06-11 16:18:30 +02:00
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),
2020-04-12 17:00:06 +02:00
#[cfg(not(feature = "no_float"))]
2020-06-11 16:18:30 +02:00
Union::Float(value) => fmt::Display::fmt(value, f),
#[cfg(not(feature = "no_index"))]
2020-06-11 16:18:30 +02:00
Union::Array(value) => fmt::Debug::fmt(value, f),
#[cfg(not(feature = "no_object"))]
Union::Map(value) => {
f.write_str("#")?;
fmt::Debug::fmt(value, f)
}
2020-06-25 12:07:57 +02:00
Union::FnPtr(value) => fmt::Display::fmt(value, f),
2020-05-05 14:54:56 +02:00
#[cfg(not(feature = "no_std"))]
2020-09-27 16:15:35 +02:00
Union::TimeStamp(_) => f.write_str("<timestamp>"),
2020-08-04 03:47:48 +02:00
Union::Variant(value) => f.write_str((*value).type_name()),
2020-08-08 10:24:10 +02:00
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
2020-08-04 03:47:48 +02:00
#[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")]
2020-08-05 16:53:01 +02:00
Union::Shared(cell) => fmt::Display::fmt(&*cell.read().unwrap(), f),
2020-04-12 17:00:06 +02:00
}
}
}
impl fmt::Debug for Dynamic {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.0 {
2020-06-11 16:18:30 +02:00
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),
2020-04-12 17:00:06 +02:00
#[cfg(not(feature = "no_float"))]
2020-06-11 16:18:30 +02:00
Union::Float(value) => fmt::Debug::fmt(value, f),
#[cfg(not(feature = "no_index"))]
2020-06-11 16:18:30 +02:00
Union::Array(value) => fmt::Debug::fmt(value, f),
#[cfg(not(feature = "no_object"))]
Union::Map(value) => {
f.write_str("#")?;
fmt::Debug::fmt(value, f)
}
2020-07-22 17:12:09 +02:00
Union::FnPtr(value) => fmt::Debug::fmt(value, f),
2020-05-05 14:54:56 +02:00
#[cfg(not(feature = "no_std"))]
2020-09-27 16:15:35 +02:00
Union::TimeStamp(_) => write!(f, "<timestamp>"),
Union::Variant(value) => write!(f, "{}", (*value).type_name()),
2020-08-08 10:24:10 +02:00
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
2020-08-04 03:47:48 +02:00
#[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")]
2020-08-05 16:53:01 +02:00
Union::Shared(cell) => fmt::Debug::fmt(&*cell.read().unwrap(), f),
2020-04-12 17:00:06 +02:00
}
2017-12-20 12:16:14 +01:00
}
}
2020-03-04 15:00:01 +01:00
impl Clone for Dynamic {
fn clone(&self) -> Self {
2020-05-03 16:17:28 +02:00
match self.0 {
Union::Unit(value) => Self(Union::Unit(value)),
Union::Bool(value) => Self(Union::Bool(value)),
Union::Str(ref value) => Self(Union::Str(value.clone())),
Union::Char(value) => Self(Union::Char(value)),
Union::Int(value) => Self(Union::Int(value)),
2020-04-12 17:00:06 +02:00
#[cfg(not(feature = "no_float"))]
2020-05-03 16:17:28 +02:00
Union::Float(value) => Self(Union::Float(value)),
#[cfg(not(feature = "no_index"))]
2020-05-03 16:17:28 +02:00
Union::Array(ref value) => Self(Union::Array(value.clone())),
#[cfg(not(feature = "no_object"))]
2020-05-03 16:17:28 +02:00
Union::Map(ref value) => Self(Union::Map(value.clone())),
2020-06-25 12:07:57 +02:00
Union::FnPtr(ref value) => Self(Union::FnPtr(value.clone())),
2020-09-27 16:15:35 +02:00
#[cfg(not(feature = "no_std"))]
Union::TimeStamp(ref value) => Self(Union::TimeStamp(value.clone())),
2020-08-08 05:46:30 +02:00
2020-05-03 16:17:28 +02:00
Union::Variant(ref value) => (***value).clone_into_dynamic(),
2020-08-08 05:46:30 +02:00
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
2020-07-31 16:30:23 +02:00
Union::Shared(ref cell) => Self(Union::Shared(cell.clone())),
2020-04-12 17:00:06 +02:00
}
2020-03-04 15:00:01 +01:00
}
}
2020-04-30 16:52:36 +02:00
impl Default for Dynamic {
2020-08-08 05:46:30 +02:00
#[inline(always)]
2020-04-30 16:52:36 +02:00
fn default() -> Self {
Self(Union::Unit(()))
}
}
2020-04-12 17:00:06 +02:00
impl Dynamic {
2020-04-13 04:27:08 +02:00
/// Create a `Dynamic` from any type. A `Dynamic` value is simply returned as is.
///
/// # Safety
///
/// This type uses some unsafe code, mainly for type casting.
///
/// # Notes
///
/// Beware that you need to pass in an `Array` type for it to be recognized as an `Array`.
/// A `Vec<T>` does not get automatically converted to an `Array`, but will be a generic
/// restricted trait object instead, because `Vec<T>` is not a supported standard type.
///
/// Similarly, passing in a `HashMap<String, T>` will not get a `Map` but a trait object.
///
2020-04-12 17:00:06 +02:00
/// # Examples
///
2020-04-12 17:00:06 +02:00
/// ```
/// use rhai::Dynamic;
///
/// let result = Dynamic::from(42_i64);
/// assert_eq!(result.type_name(), "i64");
/// assert_eq!(result.to_string(), "42");
///
2020-10-07 05:44:06 +02:00
/// let result = Dynamic::from("hello");
2020-04-12 17:00:06 +02:00
/// assert_eq!(result.type_name(), "string");
/// assert_eq!(result.to_string(), "hello");
2020-04-13 04:27:08 +02:00
///
/// let new_result = Dynamic::from(result);
/// assert_eq!(new_result.type_name(), "string");
/// assert_eq!(new_result.to_string(), "hello");
2020-04-12 17:00:06 +02:00
/// ```
2020-07-22 07:05:24 +02:00
#[inline(always)]
2020-04-12 17:00:06 +02:00
pub fn from<T: Variant + Clone>(value: T) -> Self {
2020-10-08 16:25:50 +02:00
// Coded this way in order to maximally leverage potentials for dead-code removal.
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<INT>() {
2020-07-22 07:05:24 +02:00
return <dyn Any>::downcast_ref::<INT>(&value)
.unwrap()
.clone()
.into();
}
2020-04-12 17:00:06 +02:00
#[cfg(not(feature = "no_float"))]
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<FLOAT>() {
2020-07-22 07:05:24 +02:00
return <dyn Any>::downcast_ref::<FLOAT>(&value)
.unwrap()
.clone()
.into();
}
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<bool>() {
2020-07-22 07:05:24 +02:00
return <dyn Any>::downcast_ref::<bool>(&value)
.unwrap()
.clone()
.into();
}
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<char>() {
2020-07-22 07:05:24 +02:00
return <dyn Any>::downcast_ref::<char>(&value)
.unwrap()
.clone()
.into();
}
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<ImmutableString>() {
2020-07-22 07:05:24 +02:00
return <dyn Any>::downcast_ref::<ImmutableString>(&value)
.unwrap()
.clone()
.into();
}
2020-10-06 15:25:05 +02:00
if TypeId::of::<T>() == TypeId::of::<&str>() {
return <dyn Any>::downcast_ref::<&str>(&value)
.unwrap()
.to_string()
.into();
}
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<()>() {
2020-07-22 07:05:24 +02:00
return ().into();
2020-04-12 17:00:06 +02:00
}
2020-06-23 13:24:26 +02:00
let mut boxed = Box::new(value);
2020-08-14 07:43:26 +02:00
boxed = match unsafe_cast_box::<_, Dynamic>(boxed) {
Ok(d) => return *d,
Err(val) => val,
};
2020-06-23 13:24:26 +02:00
boxed = match unsafe_cast_box::<_, String>(boxed) {
Ok(s) => return (*s).into(),
Err(val) => val,
};
#[cfg(not(feature = "no_index"))]
{
2020-06-23 13:24:26 +02:00
boxed = match unsafe_cast_box::<_, Array>(boxed) {
Ok(array) => return (*array).into(),
Err(val) => val,
};
}
#[cfg(not(feature = "no_object"))]
{
2020-06-23 13:24:26 +02:00
boxed = match unsafe_cast_box::<_, Map>(boxed) {
Ok(map) => return (*map).into(),
Err(val) => val,
}
}
2020-08-03 17:11:24 +02:00
boxed = match unsafe_cast_box::<_, FnPtr>(boxed) {
Ok(fn_ptr) => return (*fn_ptr).into(),
Err(val) => val,
};
2020-09-27 16:15:35 +02:00
#[cfg(not(feature = "no_std"))]
{
boxed = match unsafe_cast_box::<_, Instant>(boxed) {
Ok(timestamp) => return (*timestamp).into(),
Err(val) => val,
}
}
2020-06-23 13:24:26 +02:00
Self(Union::Variant(Box::new(boxed)))
2020-04-12 17:00:06 +02:00
}
/// Turn the `Dynamic` value into a shared `Dynamic` value backed by an `Rc<RefCell<Dynamic>>`
/// or `Arc<RwLock<Dynamic>>` depending on the `sync` feature.
2020-03-04 15:00:01 +01:00
///
/// Shared `Dynamic` values are relatively cheap to clone as they simply increment the
/// reference counts.
///
/// Shared `Dynamic` values can be converted seamlessly to and from ordinary `Dynamic` values.
///
/// If the `Dynamic` value is already shared, this method returns itself.
2020-07-31 16:30:23 +02:00
///
/// # Panics
///
2020-08-03 06:10:20 +02:00
/// Panics under the `no_closure` feature.
2020-08-04 12:39:24 +02:00
#[inline(always)]
pub fn into_shared(self) -> Self {
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
2020-07-31 16:30:23 +02:00
return match self.0 {
Union::Shared(..) => self,
_ => Self(Union::Shared(Locked::new(self).into())),
2020-07-31 16:30:23 +02:00
};
2020-08-03 06:10:20 +02:00
#[cfg(feature = "no_closure")]
2020-09-28 05:19:49 +02:00
panic!("converting into a shared value is not supported under 'no_closure'");
}
/// Convert the `Dynamic` value into specific type.
2020-07-31 10:39:38 +02:00
///
/// Casting to a `Dynamic` just returns as is, but if it contains a shared value,
/// it is cloned into a `Dynamic` with a normal value.
2020-03-04 15:00:01 +01:00
///
/// Returns `None` if types mismatched.
///
2020-08-04 10:27:55 +02:00
/// # Panics or Deadlocks
///
2020-08-04 10:27:55 +02:00
/// Under the `sync` feature, this call may deadlock, or [panic](https://doc.rust-lang.org/std/sync/struct.RwLock.html#panics-1).
/// Otherwise, this call panics if the data is currently borrowed for write.
///
/// These normally shouldn't occur since most operations in Rhai is single-threaded.
2020-04-12 17:00:06 +02:00
///
2020-03-04 15:00:01 +01:00
/// # Example
///
2020-03-19 06:52:10 +01:00
/// ```
2020-04-12 17:00:06 +02:00
/// use rhai::Dynamic;
2020-03-04 15:00:01 +01:00
///
2020-04-12 17:00:06 +02:00
/// let x = Dynamic::from(42_u32);
2020-03-04 15:00:01 +01:00
///
/// assert_eq!(x.try_cast::<u32>().unwrap(), 42);
2020-03-04 15:00:01 +01:00
/// ```
2020-07-22 07:05:24 +02:00
#[inline(always)]
pub fn try_cast<T: Variant>(self) -> Option<T> {
2020-10-08 16:25:50 +02:00
// Coded this way in order to maximally leverage potentials for dead-code removal.
2020-07-31 10:39:38 +02:00
match self.0 {
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
2020-07-31 10:39:38 +02:00
#[cfg(not(feature = "sync"))]
Union::Shared(cell) => return cell.borrow().clone().try_cast(),
2020-07-31 10:39:38 +02:00
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
2020-07-31 10:39:38 +02:00
#[cfg(feature = "sync")]
Union::Shared(cell) => return cell.read().unwrap().clone().try_cast(),
2020-07-31 10:39:38 +02:00
_ => (),
}
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<Dynamic>() {
return unsafe_cast_box::<_, T>(Box::new(self)).ok().map(|v| *v);
}
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<INT>() {
2020-07-22 07:05:24 +02:00
return match self.0 {
Union::Int(value) => unsafe_try_cast(value),
_ => None,
};
}
2020-07-22 07:05:24 +02:00
#[cfg(not(feature = "no_float"))]
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<FLOAT>() {
2020-07-22 07:05:24 +02:00
return match self.0 {
Union::Float(value) => unsafe_try_cast(value),
_ => None,
};
}
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<bool>() {
2020-07-22 07:05:24 +02:00
return match self.0 {
Union::Bool(value) => unsafe_try_cast(value),
_ => None,
};
}
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<ImmutableString>() {
2020-07-22 07:05:24 +02:00
return match self.0 {
Union::Str(value) => unsafe_try_cast(value),
_ => None,
};
}
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<String>() {
2020-07-22 07:05:24 +02:00
return match self.0 {
Union::Str(value) => unsafe_try_cast(value.into_owned()),
_ => None,
};
}
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<char>() {
2020-07-22 07:05:24 +02:00
return match self.0 {
Union::Char(value) => unsafe_try_cast(value),
_ => None,
};
}
2020-07-22 07:05:24 +02:00
#[cfg(not(feature = "no_index"))]
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<Array>() {
2020-07-22 07:05:24 +02:00
return match self.0 {
Union::Array(value) => unsafe_cast_box::<_, T>(value).ok().map(|v| *v),
_ => None,
};
}
2020-07-22 07:05:24 +02:00
#[cfg(not(feature = "no_object"))]
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<Map>() {
2020-07-22 07:05:24 +02:00
return match self.0 {
Union::Map(value) => unsafe_cast_box::<_, T>(value).ok().map(|v| *v),
_ => None,
};
}
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<FnPtr>() {
2020-07-22 07:05:24 +02:00
return match self.0 {
2020-07-22 17:12:09 +02:00
Union::FnPtr(value) => unsafe_cast_box::<_, T>(value).ok().map(|v| *v),
2020-07-22 07:05:24 +02:00
_ => None,
};
}
2020-09-27 16:15:35 +02:00
#[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,
};
}
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<()>() {
2020-07-22 07:05:24 +02:00
return match self.0 {
Union::Unit(value) => unsafe_try_cast(value),
_ => None,
};
}
2020-04-13 04:27:08 +02:00
2020-04-30 16:52:36 +02:00
match self.0 {
Union::Variant(value) => (*value).as_box_any().downcast().map(|x| *x).ok(),
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
2020-07-31 10:39:38 +02:00
Union::Shared(_) => unreachable!(),
2020-07-22 07:05:24 +02:00
_ => None,
2017-12-20 12:16:14 +01:00
}
}
/// Convert the `Dynamic` value into a specific type.
///
2020-07-31 10:39:38 +02:00
/// Casting to a `Dynamic` just returns as is, but if it contains a shared value,
/// it is cloned into a `Dynamic` with a normal value.
///
/// Returns `None` if types mismatched.
///
2020-08-04 10:27:55 +02:00
/// # Panics or Deadlocks
///
/// Panics if the cast fails (e.g. the type of the actual value is not the
/// same as the specified type).
///
2020-08-04 10:27:55 +02:00
/// Under the `sync` feature, this call may deadlock, or [panic](https://doc.rust-lang.org/std/sync/struct.RwLock.html#panics-1).
/// Otherwise, this call panics if the data is currently borrowed for write.
///
/// These normally shouldn't occur since most operations in Rhai is single-threaded.
///
/// # Example
///
/// ```
2020-04-12 17:00:06 +02:00
/// use rhai::Dynamic;
///
2020-04-12 17:00:06 +02:00
/// let x = Dynamic::from(42_u32);
///
/// assert_eq!(x.cast::<u32>(), 42);
/// ```
2020-07-22 07:05:24 +02:00
#[inline(always)]
2020-04-12 17:00:06 +02:00
pub fn cast<T: Variant + Clone>(self) -> T {
2020-09-27 05:14:50 +02:00
let self_type_name = if self.is_shared() {
// Avoid panics/deadlocks with shared values
"<shared>"
} else {
self.type_name()
};
self.try_cast::<T>().unwrap_or_else(|| {
panic!(
2020-09-28 05:19:49 +02:00
"cannot cast {} value and to {}",
2020-09-27 05:14:50 +02:00
self_type_name,
type_name::<T>()
)
})
}
2020-08-08 11:04:21 +02:00
/// Flatten the `Dynamic` and clone it.
///
2020-08-08 10:24:10 +02:00
/// If the `Dynamic` is not a shared value, it returns a cloned copy.
///
2020-08-08 10:24:10 +02:00
/// If the `Dynamic` is a shared value, it a cloned copy of the shared value.
#[inline(always)]
2020-08-08 11:04:21 +02:00
pub fn flatten_clone(&self) -> Self {
2020-08-08 10:24:10 +02:00
match &self.0 {
#[cfg(not(feature = "no_closure"))]
Union::Shared(cell) => {
#[cfg(not(feature = "sync"))]
return cell.borrow().clone();
#[cfg(feature = "sync")]
return cell.read().unwrap().clone();
}
_ => self.clone(),
}
}
/// Flatten the `Dynamic`.
///
2020-08-08 10:24:10 +02:00
/// If the `Dynamic` is not a shared value, it returns itself.
///
2020-08-08 10:24:10 +02:00
/// If the `Dynamic` is a shared value, it returns the shared value if there are
/// no outstanding references, or a cloned copy.
2020-07-22 07:05:24 +02:00
#[inline(always)]
2020-08-08 10:24:10 +02:00
pub fn flatten(self) -> Self {
match self.0 {
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
Union::Shared(cell) => shared_try_take(cell).map_or_else(
|cell| {
#[cfg(not(feature = "sync"))]
return cell.borrow().clone();
#[cfg(feature = "sync")]
return cell.read().unwrap().clone();
},
|value| {
#[cfg(not(feature = "sync"))]
return value.into_inner();
#[cfg(feature = "sync")]
return value.into_inner().unwrap();
},
),
2020-08-08 10:24:10 +02:00
_ => self,
}
}
2020-08-02 07:33:51 +02:00
/// Is the `Dynamic` a shared value that is locked?
///
/// ## Note
///
/// Under the `sync` feature, shared values use `RwLock` and they are never locked.
/// Access just waits until the `RwLock` is released.
/// So this method always returns `false` under `sync`.
#[inline(always)]
pub fn is_locked(&self) -> bool {
match self.0 {
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
2020-08-02 07:33:51 +02:00
Union::Shared(ref _cell) => {
#[cfg(not(feature = "sync"))]
return _cell.try_borrow().is_err();
#[cfg(feature = "sync")]
return false;
}
_ => false,
}
}
2020-04-12 17:00:06 +02:00
/// Get a reference of a specific type to the `Dynamic`.
2020-04-13 17:31:05 +02:00
/// Casting to `Dynamic` just returns a reference to it.
///
/// Returns `None` if the cast fails.
2020-08-03 06:10:20 +02:00
///
2020-08-04 10:27:55 +02:00
/// # Panics or Deadlocks When Value is Shared
2020-08-03 06:10:20 +02:00
///
2020-08-04 10:27:55 +02:00
/// Under the `sync` feature, this call may deadlock, or [panic](https://doc.rust-lang.org/std/sync/struct.RwLock.html#panics-1).
2020-08-03 06:10:20 +02:00
/// Otherwise, this call panics if the data is currently borrowed for write.
#[inline(always)]
pub fn read_lock<T: Variant + Clone>(&self) -> Option<DynamicReadLock<T>> {
match self.0 {
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
Union::Shared(ref cell) => {
#[cfg(not(feature = "sync"))]
2020-08-03 06:10:20 +02:00
let data = cell.borrow();
#[cfg(feature = "sync")]
2020-08-03 06:10:20 +02:00
let data = cell.read().unwrap();
let type_id = (*data).type_id();
if type_id != TypeId::of::<T>() && TypeId::of::<Dynamic>() != TypeId::of::<T>() {
None
} else {
Some(DynamicReadLock(DynamicReadLockInner::Guard(data)))
}
}
_ => self
.downcast_ref()
2020-08-03 06:10:20 +02:00
.map(|r| DynamicReadLock(DynamicReadLockInner::Reference(r))),
}
}
/// Get a mutable reference of a specific type to the `Dynamic`.
/// Casting to `Dynamic` just returns a mutable reference to it.
///
2020-04-12 17:00:06 +02:00
/// Returns `None` if the cast fails.
2020-08-03 06:10:20 +02:00
///
2020-08-04 10:27:55 +02:00
/// # Panics or Deadlocks When Value is Shared
2020-08-03 06:10:20 +02:00
///
2020-08-04 10:27:55 +02:00
/// Under the `sync` feature, this call may deadlock, or [panic](https://doc.rust-lang.org/std/sync/struct.RwLock.html#panics-1).
2020-08-03 06:10:20 +02:00
/// Otherwise, this call panics if the data is currently borrowed for write.
#[inline(always)]
pub fn write_lock<T: Variant + Clone>(&mut self) -> Option<DynamicWriteLock<T>> {
match self.0 {
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
Union::Shared(ref cell) => {
#[cfg(not(feature = "sync"))]
2020-08-03 06:10:20 +02:00
let data = cell.borrow_mut();
#[cfg(feature = "sync")]
2020-08-03 06:10:20 +02:00
let data = cell.write().unwrap();
let type_id = (*data).type_id();
if type_id != TypeId::of::<T>() && TypeId::of::<Dynamic>() != TypeId::of::<T>() {
None
} else {
Some(DynamicWriteLock(DynamicWriteLockInner::Guard(data)))
}
}
_ => self
.downcast_mut()
2020-08-03 06:10:20 +02:00
.map(|r| DynamicWriteLock(DynamicWriteLockInner::Reference(r))),
}
}
/// Get a reference of a specific type to the `Dynamic`.
/// Casting to `Dynamic` just returns a reference to it.
///
2020-08-04 03:47:48 +02:00
/// Returns `None` if the cast fails, or if the value is shared.
2020-07-22 07:05:24 +02:00
#[inline(always)]
2020-08-04 03:47:48 +02:00
pub(crate) fn downcast_ref<T: Variant + Clone>(&self) -> Option<&T> {
2020-10-08 16:25:50 +02:00
// Coded this way in order to maximally leverage potentials for dead-code removal.
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<INT>() {
2020-07-22 07:05:24 +02:00
return match &self.0 {
Union::Int(value) => <dyn Any>::downcast_ref::<T>(value),
_ => None,
};
}
#[cfg(not(feature = "no_float"))]
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<FLOAT>() {
2020-07-22 07:05:24 +02:00
return match &self.0 {
Union::Float(value) => <dyn Any>::downcast_ref::<T>(value),
_ => None,
};
}
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<bool>() {
2020-07-22 07:05:24 +02:00
return match &self.0 {
Union::Bool(value) => <dyn Any>::downcast_ref::<T>(value),
_ => None,
};
}
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<ImmutableString>() {
2020-07-22 07:05:24 +02:00
return match &self.0 {
Union::Str(value) => <dyn Any>::downcast_ref::<T>(value),
_ => None,
};
}
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<String>() {
2020-07-22 07:05:24 +02:00
return match &self.0 {
Union::Str(value) => <dyn Any>::downcast_ref::<T>(value.as_ref()),
_ => None,
};
}
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<char>() {
2020-07-22 07:05:24 +02:00
return match &self.0 {
Union::Char(value) => <dyn Any>::downcast_ref::<T>(value),
_ => None,
};
}
#[cfg(not(feature = "no_index"))]
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<Array>() {
2020-07-22 07:05:24 +02:00
return match &self.0 {
Union::Array(value) => <dyn Any>::downcast_ref::<T>(value.as_ref()),
_ => None,
};
}
#[cfg(not(feature = "no_object"))]
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<Map>() {
2020-07-22 07:05:24 +02:00
return match &self.0 {
Union::Map(value) => <dyn Any>::downcast_ref::<T>(value.as_ref()),
_ => None,
};
}
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<FnPtr>() {
2020-07-22 07:05:24 +02:00
return match &self.0 {
2020-07-22 17:12:09 +02:00
Union::FnPtr(value) => <dyn Any>::downcast_ref::<T>(value.as_ref()),
2020-07-22 07:05:24 +02:00
_ => None,
};
}
2020-09-27 16:15:35 +02:00
#[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,
};
}
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<()>() {
2020-07-22 07:05:24 +02:00
return match &self.0 {
Union::Unit(value) => <dyn Any>::downcast_ref::<T>(value),
_ => None,
};
}
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<Dynamic>() {
2020-06-23 13:24:26 +02:00
return <dyn Any>::downcast_ref::<T>(self);
2020-04-13 17:31:05 +02:00
}
2020-04-12 17:00:06 +02:00
match &self.0 {
2020-05-03 16:17:28 +02:00
Union::Variant(value) => value.as_ref().as_ref().as_any().downcast_ref::<T>(),
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
2020-08-04 03:47:48 +02:00
Union::Shared(_) => None,
2020-07-22 07:05:24 +02:00
_ => None,
2020-04-12 17:00:06 +02:00
}
}
/// Get a mutable reference of a specific type to the `Dynamic`.
2020-04-13 17:31:05 +02:00
/// Casting to `Dynamic` just returns a mutable reference to it.
///
2020-08-04 03:47:48 +02:00
/// Returns `None` if the cast fails, or if the value is shared.
2020-07-22 07:05:24 +02:00
#[inline(always)]
2020-08-04 03:47:48 +02:00
pub(crate) fn downcast_mut<T: Variant + Clone>(&mut self) -> Option<&mut T> {
2020-10-08 16:25:50 +02:00
// Coded this way in order to maximally leverage potentials for dead-code removal.
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<INT>() {
2020-07-22 07:05:24 +02:00
return match &mut self.0 {
Union::Int(value) => <dyn Any>::downcast_mut::<T>(value),
_ => None,
};
}
#[cfg(not(feature = "no_float"))]
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<FLOAT>() {
2020-07-22 07:05:24 +02:00
return match &mut self.0 {
Union::Float(value) => <dyn Any>::downcast_mut::<T>(value),
_ => None,
};
}
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<bool>() {
2020-07-22 07:05:24 +02:00
return match &mut self.0 {
Union::Bool(value) => <dyn Any>::downcast_mut::<T>(value),
_ => None,
};
}
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<ImmutableString>() {
2020-07-22 07:05:24 +02:00
return match &mut self.0 {
Union::Str(value) => <dyn Any>::downcast_mut::<T>(value),
_ => None,
};
}
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<char>() {
2020-07-22 07:05:24 +02:00
return match &mut self.0 {
Union::Char(value) => <dyn Any>::downcast_mut::<T>(value),
_ => None,
};
}
#[cfg(not(feature = "no_index"))]
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<Array>() {
2020-07-22 07:05:24 +02:00
return match &mut self.0 {
Union::Array(value) => <dyn Any>::downcast_mut::<T>(value.as_mut()),
_ => None,
};
}
#[cfg(not(feature = "no_object"))]
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<Map>() {
2020-07-22 07:05:24 +02:00
return match &mut self.0 {
Union::Map(value) => <dyn Any>::downcast_mut::<T>(value.as_mut()),
_ => None,
};
}
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<FnPtr>() {
2020-07-22 07:05:24 +02:00
return match &mut self.0 {
2020-07-22 17:12:09 +02:00
Union::FnPtr(value) => <dyn Any>::downcast_mut::<T>(value.as_mut()),
2020-07-22 07:05:24 +02:00
_ => None,
};
}
2020-09-27 16:15:35 +02:00
#[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,
};
}
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<()>() {
2020-07-22 07:05:24 +02:00
return match &mut self.0 {
Union::Unit(value) => <dyn Any>::downcast_mut::<T>(value),
_ => None,
};
}
2020-08-14 07:43:26 +02:00
if TypeId::of::<T>() == TypeId::of::<Dynamic>() {
2020-06-23 13:24:26 +02:00
return <dyn Any>::downcast_mut::<T>(self);
2020-04-13 17:31:05 +02:00
}
2020-04-12 17:00:06 +02:00
match &mut self.0 {
2020-05-03 16:17:28 +02:00
Union::Variant(value) => value.as_mut().as_mut_any().downcast_mut::<T>(),
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
2020-08-04 03:47:48 +02:00
Union::Shared(_) => None,
2020-07-22 07:05:24 +02:00
_ => None,
2020-04-12 17:00:06 +02:00
}
}
/// Cast the `Dynamic` as the system integer type `INT` and return it.
/// Returns the name of the actual type if the cast fails.
2020-08-08 05:46:30 +02:00
#[inline(always)]
pub fn as_int(&self) -> Result<INT, &'static str> {
2020-04-12 17:00:06 +02:00
match self.0 {
Union::Int(n) => Ok(n),
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
Union::Shared(_) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()),
2020-04-12 17:00:06 +02:00
_ => Err(self.type_name()),
}
}
2020-05-22 15:49:53 +02:00
/// Cast the `Dynamic` as the system floating-point type `FLOAT` and return it.
/// Returns the name of the actual type if the cast fails.
#[cfg(not(feature = "no_float"))]
2020-08-08 05:46:30 +02:00
#[inline(always)]
2020-05-22 15:49:53 +02:00
pub fn as_float(&self) -> Result<FLOAT, &'static str> {
match self.0 {
Union::Float(n) => Ok(n),
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
Union::Shared(_) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()),
2020-05-22 15:49:53 +02:00
_ => Err(self.type_name()),
}
}
2020-04-12 17:00:06 +02:00
/// Cast the `Dynamic` as a `bool` and return it.
/// Returns the name of the actual type if the cast fails.
2020-08-08 05:46:30 +02:00
#[inline(always)]
pub fn as_bool(&self) -> Result<bool, &'static str> {
2020-04-12 17:00:06 +02:00
match self.0 {
Union::Bool(b) => Ok(b),
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
Union::Shared(_) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()),
2020-04-12 17:00:06 +02:00
_ => Err(self.type_name()),
}
}
/// Cast the `Dynamic` as a `char` and return it.
/// Returns the name of the actual type if the cast fails.
2020-08-08 05:46:30 +02:00
#[inline(always)]
pub fn as_char(&self) -> Result<char, &'static str> {
2020-04-12 17:00:06 +02:00
match self.0 {
Union::Char(n) => Ok(n),
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
Union::Shared(_) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()),
2020-04-12 17:00:06 +02:00
_ => Err(self.type_name()),
}
}
/// Cast the `Dynamic` as a string and return the string slice.
/// Returns the name of the actual type if the cast fails.
///
/// Cast is failing if `self` is Shared Dynamic
2020-08-08 05:46:30 +02:00
#[inline(always)]
pub fn as_str(&self) -> Result<&str, &'static str> {
2020-04-12 17:00:06 +02:00
match &self.0 {
Union::Str(s) => Ok(s),
2020-06-29 17:55:28 +02:00
Union::FnPtr(f) => Ok(f.fn_name()),
2020-04-12 17:00:06 +02:00
_ => Err(self.type_name()),
}
}
/// Convert the `Dynamic` into `String` and return it.
/// If there are other references to the same string, a cloned copy is returned.
2020-04-12 17:00:06 +02:00
/// Returns the name of the actual type if the cast fails.
2020-08-08 05:46:30 +02:00
#[inline(always)]
pub fn take_string(self) -> Result<String, &'static str> {
self.take_immutable_string()
.map(ImmutableString::into_owned)
}
/// Convert the `Dynamic` into `ImmutableString` and return it.
/// Returns the name of the actual type if the cast fails.
#[inline]
pub fn take_immutable_string(self) -> Result<ImmutableString, &'static str> {
2020-04-12 17:00:06 +02:00
match self.0 {
Union::Str(s) => Ok(s),
2020-07-23 04:12:51 +02:00
Union::FnPtr(f) => Ok(f.take_data().0),
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
Union::Shared(cell) => {
#[cfg(not(feature = "sync"))]
{
let inner = cell.borrow();
match &inner.0 {
Union::Str(s) => Ok(s.clone()),
Union::FnPtr(f) => Ok(f.clone().take_data().0),
_ => Err((*inner).type_name()),
}
}
#[cfg(feature = "sync")]
{
let inner = cell.read().unwrap();
match &inner.0 {
Union::Str(s) => Ok(s.clone()),
Union::FnPtr(f) => Ok(f.clone().take_data().0),
_ => Err((*inner).type_name()),
}
}
}
2020-06-25 12:07:57 +02:00
_ => Err(self.type_name()),
}
}
}
2020-04-12 17:00:06 +02:00
impl From<()> for Dynamic {
2020-08-08 05:46:30 +02:00
#[inline(always)]
fn from(value: ()) -> Self {
Self(Union::Unit(value))
2020-04-12 17:00:06 +02:00
}
}
impl From<bool> for Dynamic {
2020-08-08 05:46:30 +02:00
#[inline(always)]
fn from(value: bool) -> Self {
2020-04-12 17:00:06 +02:00
Self(Union::Bool(value))
}
}
impl From<INT> for Dynamic {
2020-08-08 05:46:30 +02:00
#[inline(always)]
fn from(value: INT) -> Self {
2020-04-12 17:00:06 +02:00
Self(Union::Int(value))
}
}
#[cfg(not(feature = "no_float"))]
impl From<FLOAT> for Dynamic {
2020-08-08 05:46:30 +02:00
#[inline(always)]
fn from(value: FLOAT) -> Self {
2020-04-12 17:00:06 +02:00
Self(Union::Float(value))
}
}
impl From<char> for Dynamic {
2020-08-08 05:46:30 +02:00
#[inline(always)]
fn from(value: char) -> Self {
2020-04-12 17:00:06 +02:00
Self(Union::Char(value))
}
}
2020-06-23 13:24:26 +02:00
impl<S: Into<ImmutableString>> From<S> for Dynamic {
2020-08-08 05:46:30 +02:00
#[inline(always)]
2020-06-23 13:24:26 +02:00
fn from(value: S) -> Self {
2020-05-25 07:44:28 +02:00
Self(Union::Str(value.into()))
}
}
#[cfg(not(feature = "no_index"))]
impl<T: Variant + Clone> From<Vec<T>> for Dynamic {
2020-08-08 05:46:30 +02:00
#[inline(always)]
fn from(value: Vec<T>) -> Self {
Self(Union::Array(Box::new(
value.into_iter().map(Dynamic::from).collect(),
)))
}
}
#[cfg(not(feature = "no_index"))]
impl<T: Variant + Clone> From<&[T]> for Dynamic {
2020-08-08 05:46:30 +02:00
#[inline(always)]
fn from(value: &[T]) -> Self {
Self(Union::Array(Box::new(
value.iter().cloned().map(Dynamic::from).collect(),
)))
}
}
#[cfg(not(feature = "no_object"))]
2020-06-23 13:24:26 +02:00
impl<K: Into<ImmutableString>, T: Variant + Clone> From<HashMap<K, T>> for Dynamic {
2020-08-08 05:46:30 +02:00
#[inline(always)]
2020-06-23 13:24:26 +02:00
fn from(value: HashMap<K, T>) -> Self {
Self(Union::Map(Box::new(
value
.into_iter()
.map(|(k, v)| (k.into(), Dynamic::from(v)))
.collect(),
)))
}
}
2020-06-25 12:07:57 +02:00
impl From<FnPtr> for Dynamic {
2020-08-08 05:46:30 +02:00
#[inline(always)]
2020-06-25 12:07:57 +02:00
fn from(value: FnPtr) -> Self {
2020-08-03 17:11:24 +02:00
Self(Union::FnPtr(Box::new(value)))
2020-07-22 17:12:09 +02:00
}
}
impl From<Box<FnPtr>> for Dynamic {
2020-08-08 05:46:30 +02:00
#[inline(always)]
2020-07-22 17:12:09 +02:00
fn from(value: Box<FnPtr>) -> Self {
2020-06-25 12:07:57 +02:00
Self(Union::FnPtr(value))
}
}
2020-09-27 12:47:20 +02:00
#[cfg(not(feature = "no_std"))]
2020-09-26 13:41:04 +02:00
impl From<Instant> for Dynamic {
#[inline(always)]
fn from(value: Instant) -> Self {
2020-09-27 16:15:35 +02:00
Self(Union::TimeStamp(Box::new(value)))
2020-09-26 13:41:04 +02:00
}
}