rhai/src/types/dynamic.rs

2134 lines
80 KiB
Rust
Raw Normal View History

//! Helper module which defines the [`Dynamic`] data type and the
//! [`Any`] trait to to allow custom type handling.
2020-03-08 19:54:02 +08:00
2021-11-13 22:36:23 +08:00
use crate::func::native::SendSync;
2022-02-07 12:02:00 +08:00
use crate::{reify, ExclusiveRange, FnPtr, ImmutableString, InclusiveRange, INT};
2021-04-17 15:15:54 +08:00
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
use std::{
2020-04-12 23:00:06 +08:00
any::{type_name, Any, TypeId},
2020-05-15 21:40:54 +08:00
fmt,
2020-11-12 21:53:26 +08:00
hash::{Hash, Hasher},
2021-12-30 12:19:41 +08:00
mem,
ops::{Deref, DerefMut},
str::FromStr,
2020-03-10 10:07:44 +08:00
};
2020-11-16 23:10:14 +08:00
#[cfg(not(feature = "no_std"))]
2022-01-12 08:12:28 +08:00
#[cfg(not(target_family = "wasm"))]
2022-02-03 23:54:53 +08:00
pub use std::time::Instant;
2020-06-17 16:50:57 +08:00
#[cfg(not(feature = "no_std"))]
2022-01-12 08:12:28 +08:00
#[cfg(target_family = "wasm")]
2022-02-03 23:54:53 +08:00
pub use instant::Instant;
2020-06-17 16:50:57 +08:00
2021-08-26 23:58:41 +08:00
/// The message: data type was checked
const CHECKED: &str = "data type was checked";
2021-06-06 14:47:32 +08:00
mod private {
2021-11-13 22:36:23 +08:00
use crate::func::native::SendSync;
2021-04-17 15:15:54 +08:00
use std::any::Any;
2020-07-25 16:09:13 +08:00
/// A sealed trait that prevents other crates from implementing [`Variant`].
pub trait Sealed {}
impl<T: Any + Clone + SendSync> Sealed for T {}
}
2021-07-25 22:56:05 +08:00
/// _(internals)_ Trait to represent any type.
2021-03-05 14:18:36 +08:00
/// Exported under the `internals` feature only.
///
/// This trait is sealed and cannot be implemented.
2020-04-03 19:42:01 +08:00
///
2020-11-20 16:52:28 +08:00
/// Currently, [`Variant`] is not [`Send`] nor [`Sync`], so it can practically be any type.
2020-11-25 09:36:06 +08:00
/// Turn on the `sync` feature to restrict it to only types that implement [`Send`] `+` [`Sync`].
2020-04-12 23:00:06 +08:00
#[cfg(not(feature = "sync"))]
pub trait Variant: Any + private::Sealed {
2020-11-20 16:52:28 +08:00
/// Convert this [`Variant`] trait object to [`&dyn Any`][Any].
2021-06-12 22:47:43 +08:00
#[must_use]
2020-04-12 23:00:06 +08:00
fn as_any(&self) -> &dyn Any;
2020-11-20 16:52:28 +08:00
/// Convert this [`Variant`] trait object to [`&mut dyn Any`][Any].
2021-06-12 22:47:43 +08:00
#[must_use]
2022-01-03 23:11:06 +08:00
fn as_any_mut(&mut self) -> &mut dyn Any;
2017-12-20 12:16:14 +01:00
2022-01-01 19:54:46 +08:00
/// Convert this [`Variant`] trait object to [`Box<dyn Any>`].
2021-06-12 22:47:43 +08:00
#[must_use]
2022-01-03 23:11:06 +08:00
fn as_boxed_any(self: Box<Self>) -> Box<dyn Any>;
2020-03-04 22:00:01 +08:00
/// Get the name of this type.
2021-06-12 22:47:43 +08:00
#[must_use]
2020-03-03 16:24:03 +08:00
fn type_name(&self) -> &'static str;
2019-09-30 18:57:21 +01:00
2022-01-01 19:54:46 +08:00
/// Clone this [`Variant`] trait object.
2021-06-12 22:47:43 +08:00
#[must_use]
2022-01-01 19:54:46 +08:00
fn clone_object(&self) -> Box<dyn Variant>;
2017-12-20 12:16:14 +01:00
}
2021-07-25 22:56:05 +08:00
/// _(internals)_ Trait to represent any type.
2021-03-05 14:18:36 +08:00
/// Exported under the `internals` feature only.
///
/// This trait is sealed and cannot be implemented.
2020-04-12 23:00:06 +08:00
#[cfg(feature = "sync")]
pub trait Variant: Any + Send + Sync + private::Sealed {
2020-11-20 16:52:28 +08:00
/// Convert this [`Variant`] trait object to [`&dyn Any`][Any].
2021-06-12 22:47:43 +08:00
#[must_use]
2020-04-12 23:00:06 +08:00
fn as_any(&self) -> &dyn Any;
2020-11-20 16:52:28 +08:00
/// Convert this [`Variant`] trait object to [`&mut dyn Any`][Any].
2021-06-12 22:47:43 +08:00
#[must_use]
2022-01-03 23:11:06 +08:00
fn as_any_mut(&mut self) -> &mut dyn Any;
2022-01-01 19:54:46 +08:00
/// Convert this [`Variant`] trait object to [`Box<dyn Any>`].
2021-06-12 22:47:43 +08:00
#[must_use]
2022-01-03 23:11:06 +08:00
fn as_boxed_any(self: Box<Self>) -> Box<dyn Any>;
/// Get the name of this type.
2021-06-12 22:47:43 +08:00
#[must_use]
fn type_name(&self) -> &'static str;
2022-01-01 19:54:46 +08:00
/// Clone this [`Variant`] trait object.
2021-06-12 22:47:43 +08:00
#[must_use]
2022-01-01 19:54:46 +08:00
fn clone_object(&self) -> Box<dyn Variant>;
}
impl<T: Any + Clone + SendSync> Variant for T {
2020-12-29 10:41:20 +08:00
#[inline(always)]
2020-04-12 23:00:06 +08:00
fn as_any(&self) -> &dyn Any {
2020-06-23 19:24:26 +08:00
self
2020-04-12 23:00:06 +08:00
}
2020-12-29 10:41:20 +08:00
#[inline(always)]
2022-01-03 23:11:06 +08:00
fn as_any_mut(&mut self) -> &mut dyn Any {
2020-06-23 19:24:26 +08:00
self
2017-12-20 12:16:14 +01:00
}
2020-12-29 10:41:20 +08:00
#[inline(always)]
2022-01-03 23:11:06 +08:00
fn as_boxed_any(self: Box<Self>) -> Box<dyn Any> {
2020-06-23 19:24:26 +08:00
self
}
2020-12-29 10:41:20 +08:00
#[inline(always)]
2020-03-03 16:24:03 +08:00
fn type_name(&self) -> &'static str {
type_name::<T>()
2019-09-30 18:57:21 +01:00
}
2020-12-29 10:41:20 +08:00
#[inline(always)]
2022-01-01 19:54:46 +08:00
fn clone_object(&self) -> Box<dyn Variant> {
Box::new(self.clone()) as Box<dyn Variant>
2017-12-20 12:16:14 +01:00
}
2019-09-18 11:21:07 +01:00
}
2017-12-20 12:16:14 +01:00
2020-04-12 23:00:06 +08:00
impl dyn Variant {
2020-11-20 16:52:28 +08:00
/// Is this [`Variant`] a specific type?
2020-08-08 11:46:30 +08:00
#[inline(always)]
2021-06-12 22:47:43 +08:00
#[must_use]
pub fn is<T: Any>(&self) -> bool {
2020-04-12 23:00:06 +08:00
TypeId::of::<T>() == self.type_id()
2017-12-20 12:16:14 +01:00
}
2020-04-12 23:00:06 +08:00
}
2021-09-24 09:26:35 +08:00
/// _(internals)_ Modes of access.
/// Exported under the `internals` feature only.
2020-12-08 22:47:38 +08:00
#[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)]
pub enum AccessMode {
/// Mutable.
ReadWrite,
/// Immutable.
ReadOnly,
2020-12-08 22:47:38 +08:00
}
2021-05-02 23:57:35 +08:00
/// Arbitrary data attached to a [`Dynamic`] value.
2021-05-18 12:24:23 +08:00
#[cfg(target_pointer_width = "64")]
pub type Tag = i32;
/// Arbitrary data attached to a [`Dynamic`] value.
#[cfg(target_pointer_width = "32")]
2021-05-02 23:57:35 +08:00
pub type Tag = i16;
/// Default tag value for [`Dynamic`].
2021-06-28 18:06:05 +08:00
const DEFAULT_TAG_VALUE: Tag = 0;
2021-05-02 23:57:35 +08:00
2020-05-15 21:40:54 +08:00
/// Dynamic type containing any value.
2020-04-12 23:00:06 +08:00
pub struct Dynamic(pub(crate) Union);
2020-11-20 16:52:28 +08:00
/// Internal [`Dynamic`] representation.
2020-05-10 00:19:13 +08:00
///
/// Most variants are boxed to reduce the size.
2020-04-12 23:00:06 +08:00
pub enum Union {
2021-02-13 23:01:26 +08:00
/// The Unit value - ().
2021-05-02 23:57:35 +08:00
Unit((), Tag, AccessMode),
2021-02-13 23:01:26 +08:00
/// A boolean value.
2021-05-02 23:57:35 +08:00
Bool(bool, Tag, AccessMode),
2021-02-13 23:01:26 +08:00
/// An [`ImmutableString`] value.
2021-05-02 23:57:35 +08:00
Str(ImmutableString, Tag, AccessMode),
2021-02-13 23:01:26 +08:00
/// A character value.
2021-05-02 23:57:35 +08:00
Char(char, Tag, AccessMode),
2021-02-13 23:01:26 +08:00
/// An integer value.
2021-05-02 23:57:35 +08:00
Int(INT, Tag, AccessMode),
2021-02-13 23:01:26 +08:00
/// A floating-point value.
2020-04-12 23:00:06 +08:00
#[cfg(not(feature = "no_float"))]
2021-12-06 20:52:47 +08:00
Float(crate::ast::FloatWrapper<crate::FLOAT>, Tag, AccessMode),
2021-07-25 22:56:05 +08:00
/// _(decimal)_ A fixed-precision decimal value.
2021-05-10 11:07:19 +08:00
/// Exported under the `decimal` feature only.
2021-02-13 20:57:56 +08:00
#[cfg(feature = "decimal")]
2021-12-06 20:52:47 +08:00
Decimal(Box<rust_decimal::Decimal>, Tag, AccessMode),
2021-02-13 23:01:26 +08:00
/// An array value.
#[cfg(not(feature = "no_index"))]
2021-12-06 20:52:47 +08:00
Array(Box<crate::Array>, Tag, AccessMode),
2021-11-23 14:58:54 +08:00
/// An blob (byte array).
#[cfg(not(feature = "no_index"))]
2021-12-06 20:52:47 +08:00
Blob(Box<crate::Blob>, Tag, AccessMode),
2021-02-13 23:01:26 +08:00
/// An object map value.
#[cfg(not(feature = "no_object"))]
2021-12-06 20:52:47 +08:00
Map(Box<crate::Map>, Tag, AccessMode),
2021-02-13 23:01:26 +08:00
/// A function pointer.
2021-05-02 23:57:35 +08:00
FnPtr(Box<FnPtr>, Tag, AccessMode),
2021-02-13 23:01:26 +08:00
/// A timestamp value.
2020-09-27 22:15:35 +08:00
#[cfg(not(feature = "no_std"))]
2021-05-02 23:57:35 +08:00
TimeStamp(Box<Instant>, Tag, AccessMode),
2020-08-08 16:24:10 +08:00
2021-02-13 23:01:26 +08:00
/// Any type as a trait object.
2021-07-24 14:23:14 +08:00
#[allow(clippy::redundant_allocation)]
2021-05-02 23:57:35 +08:00
Variant(Box<Box<dyn Variant>>, Tag, AccessMode),
2020-08-08 16:24:10 +08:00
2021-02-13 23:01:26 +08:00
/// A _shared_ value of any type.
2020-08-03 12:10:20 +08:00
#[cfg(not(feature = "no_closure"))]
2021-05-02 23:57:35 +08:00
Shared(crate::Shared<crate::Locked<Dynamic>>, Tag, AccessMode),
}
2021-07-25 22:56:05 +08:00
/// _(internals)_ Lock guard for reading a [`Dynamic`].
2021-05-10 11:07:19 +08:00
/// Exported under the `internals` feature only.
///
/// This type provides transparent interoperability between normal [`Dynamic`] and shared
/// [`Dynamic`] values.
#[derive(Debug)]
2021-04-19 18:08:29 +08:00
pub struct DynamicReadLock<'d, T: Clone>(DynamicReadLockInner<'d, T>);
2020-11-20 16:52:28 +08:00
/// Different types of read guards for [`DynamicReadLock`].
#[derive(Debug)]
2021-04-19 18:08:29 +08:00
enum DynamicReadLockInner<'d, T: Clone> {
/// A simple reference to a non-shared value.
Reference(&'d T),
2020-08-08 16:24:10 +08:00
2022-03-03 13:02:57 +08:00
/// A read guard to a shared value.
2020-08-03 12:10:20 +08:00
#[cfg(not(feature = "no_closure"))]
2022-03-03 13:02:57 +08:00
Guard(crate::func::native::LockGuard<'d, Dynamic>),
}
2021-04-19 18:08:29 +08:00
impl<'d, T: Any + Clone> Deref for DynamicReadLock<'d, T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
2021-06-13 17:41:34 +08:00
match self.0 {
DynamicReadLockInner::Reference(ref reference) => *reference,
2020-08-03 12:10:20 +08:00
#[cfg(not(feature = "no_closure"))]
2021-08-26 23:58:41 +08:00
DynamicReadLockInner::Guard(ref guard) => guard.downcast_ref().expect(CHECKED),
}
}
}
2021-07-25 22:56:05 +08:00
/// _(internals)_ Lock guard for writing a [`Dynamic`].
2021-05-10 11:07:19 +08:00
/// Exported under the `internals` feature only.
///
/// This type provides transparent interoperability between normal [`Dynamic`] and shared
/// [`Dynamic`] values.
#[derive(Debug)]
2021-04-19 18:08:29 +08:00
pub struct DynamicWriteLock<'d, T: Clone>(DynamicWriteLockInner<'d, T>);
2020-11-20 16:52:28 +08:00
/// Different types of write guards for [`DynamicReadLock`].
#[derive(Debug)]
2021-04-19 18:08:29 +08:00
enum DynamicWriteLockInner<'d, T: Clone> {
/// A simple mutable reference to a non-shared value.
Reference(&'d mut T),
2020-08-08 16:24:10 +08:00
2021-11-08 11:35:46 +08:00
/// A write guard to a shared value.
2020-08-03 12:10:20 +08:00
#[cfg(not(feature = "no_closure"))]
2022-03-03 13:02:57 +08:00
Guard(crate::func::native::LockGuardMut<'d, Dynamic>),
}
2021-04-19 18:08:29 +08:00
impl<'d, T: Any + Clone> Deref for DynamicWriteLock<'d, T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
2021-06-13 17:41:34 +08:00
match self.0 {
DynamicWriteLockInner::Reference(ref reference) => *reference,
2020-08-03 12:10:20 +08:00
#[cfg(not(feature = "no_closure"))]
2021-08-26 23:58:41 +08:00
DynamicWriteLockInner::Guard(ref guard) => guard.downcast_ref().expect(CHECKED),
}
}
}
2021-04-19 18:08:29 +08:00
impl<'d, T: Any + Clone> DerefMut for DynamicWriteLock<'d, T> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
2021-06-13 17:41:34 +08:00
match self.0 {
DynamicWriteLockInner::Reference(ref mut reference) => *reference,
2020-08-03 12:10:20 +08:00
#[cfg(not(feature = "no_closure"))]
2021-08-26 23:58:41 +08:00
DynamicWriteLockInner::Guard(ref mut guard) => guard.downcast_mut().expect(CHECKED),
}
}
2020-04-12 23:00:06 +08:00
}
impl Dynamic {
2021-05-02 23:57:35 +08:00
/// Get the arbitrary data attached to this [`Dynamic`].
2021-06-12 22:47:43 +08:00
#[must_use]
2021-05-25 10:54:48 +08:00
pub const fn tag(&self) -> Tag {
2021-05-02 23:57:35 +08:00
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"))]
2021-11-23 14:58:54 +08:00
Union::Array(_, tag, _) | Union::Blob(_, tag, _) => tag,
2021-05-02 23:57:35 +08:00
#[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`].
2021-06-12 22:47:43 +08:00
pub fn set_tag(&mut self, value: Tag) -> &mut Self {
2021-06-13 17:41:34 +08:00
match self.0 {
Union::Unit(_, ref mut tag, _)
| Union::Bool(_, ref mut tag, _)
| Union::Str(_, ref mut tag, _)
| Union::Char(_, ref mut tag, _)
| Union::Int(_, ref mut tag, _)
| Union::FnPtr(_, ref mut tag, _)
| Union::Variant(_, ref mut tag, _) => *tag = value,
2021-05-02 23:57:35 +08:00
#[cfg(not(feature = "no_float"))]
2021-06-13 17:41:34 +08:00
Union::Float(_, ref mut tag, _) => *tag = value,
2021-05-02 23:57:35 +08:00
#[cfg(feature = "decimal")]
2021-06-13 17:41:34 +08:00
Union::Decimal(_, ref mut tag, _) => *tag = value,
2021-05-02 23:57:35 +08:00
#[cfg(not(feature = "no_index"))]
2021-11-23 14:58:54 +08:00
Union::Array(_, ref mut tag, _) | Union::Blob(_, ref mut tag, _) => *tag = value,
2021-05-02 23:57:35 +08:00
#[cfg(not(feature = "no_object"))]
2021-06-13 17:41:34 +08:00
Union::Map(_, ref mut tag, _) => *tag = value,
2021-05-02 23:57:35 +08:00
#[cfg(not(feature = "no_std"))]
2021-06-13 17:41:34 +08:00
Union::TimeStamp(_, ref mut tag, _) => *tag = value,
2021-05-02 23:57:35 +08:00
#[cfg(not(feature = "no_closure"))]
2021-06-13 17:41:34 +08:00
Union::Shared(_, ref mut tag, _) => *tag = value,
2021-05-02 23:57:35 +08:00
}
2021-06-12 22:47:43 +08:00
self
2021-05-02 23:57:35 +08:00
}
2022-02-24 10:36:20 +08:00
/// Does this [`Dynamic`] hold a variant data type instead of one of the supported system
/// primitive types?
2020-08-08 11:46:30 +08:00
#[inline(always)]
2021-06-12 22:47:43 +08:00
#[must_use]
2021-05-25 10:54:48 +08:00
pub const fn is_variant(&self) -> bool {
2022-02-08 09:02:15 +08:00
matches!(self.0, Union::Variant(..))
2020-04-13 10:27:08 +08:00
}
2021-01-02 23:30:10 +08:00
/// Is the value held by this [`Dynamic`] shared?
2021-01-11 23:09:33 +08:00
///
/// Not available under `no_closure`.
#[cfg(not(feature = "no_closure"))]
2020-08-08 11:46:30 +08:00
#[inline(always)]
2021-06-12 22:47:43 +08:00
#[must_use]
2021-05-25 10:54:48 +08:00
pub const fn is_shared(&self) -> bool {
#[cfg(not(feature = "no_closure"))]
2022-02-08 09:02:15 +08:00
return matches!(self.0, Union::Shared(..));
#[cfg(feature = "no_closure")]
return false;
}
2020-11-20 16:52:28 +08:00
/// Is the value held by this [`Dynamic`] a particular type?
///
2022-02-24 10:36:20 +08:00
/// If the [`Dynamic`] is a shared variant checking is performed on top of its internal value.
#[inline]
2021-06-12 22:47:43 +08:00
#[must_use]
2021-04-19 18:08:29 +08:00
pub fn is<T: Any + Clone>(&self) -> bool {
if TypeId::of::<T>() == TypeId::of::<String>() {
self.type_id() == TypeId::of::<ImmutableString>()
} else {
self.type_id() == TypeId::of::<T>()
}
2020-04-12 23:00:06 +08:00
}
2020-11-20 16:52:28 +08:00
/// Get the [`TypeId`] of the value held by this [`Dynamic`].
2020-08-02 13:33:51 +08:00
///
2020-08-04 16:27:55 +08:00
/// # Panics or Deadlocks When Value is Shared
2020-08-02 13:33:51 +08:00
///
2020-11-25 09:36:06 +08: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 13:33:51 +08:00
/// Otherwise, this call panics if the data is currently borrowed for write.
2021-06-12 22:47:43 +08:00
#[must_use]
2020-04-12 23:00:06 +08:00
pub fn type_id(&self) -> TypeId {
2021-06-13 17:41:34 +08:00
match self.0 {
2022-02-08 09:02:15 +08:00
Union::Unit(..) => TypeId::of::<()>(),
Union::Bool(..) => TypeId::of::<bool>(),
Union::Str(..) => TypeId::of::<ImmutableString>(),
Union::Char(..) => TypeId::of::<char>(),
Union::Int(..) => TypeId::of::<INT>(),
2020-04-12 23:00:06 +08:00
#[cfg(not(feature = "no_float"))]
2022-02-08 09:02:15 +08:00
Union::Float(..) => TypeId::of::<crate::FLOAT>(),
2021-02-13 20:57:56 +08:00
#[cfg(feature = "decimal")]
2022-02-08 09:02:15 +08:00
Union::Decimal(..) => TypeId::of::<rust_decimal::Decimal>(),
#[cfg(not(feature = "no_index"))]
2022-02-08 09:02:15 +08:00
Union::Array(..) => TypeId::of::<crate::Array>(),
2021-11-23 14:58:54 +08:00
#[cfg(not(feature = "no_index"))]
2022-02-08 09:02:15 +08:00
Union::Blob(..) => TypeId::of::<crate::Blob>(),
#[cfg(not(feature = "no_object"))]
2022-02-08 09:02:15 +08:00
Union::Map(..) => TypeId::of::<crate::Map>(),
Union::FnPtr(..) => TypeId::of::<FnPtr>(),
2020-09-27 22:15:35 +08:00
#[cfg(not(feature = "no_std"))]
2022-02-08 09:02:15 +08:00
Union::TimeStamp(..) => TypeId::of::<Instant>(),
2020-08-08 11:46:30 +08:00
2022-02-08 09:25:53 +08:00
Union::Variant(ref v, ..) => (***v).type_id(),
2020-08-08 11:46:30 +08:00
2020-08-03 12:10:20 +08:00
#[cfg(not(feature = "no_closure"))]
2021-06-13 17:41:34 +08:00
#[cfg(not(feature = "sync"))]
2022-02-08 09:25:53 +08:00
Union::Shared(ref cell, ..) => (*cell.borrow()).type_id(),
2021-03-05 14:18:36 +08:00
2021-06-13 17:41:34 +08:00
#[cfg(not(feature = "no_closure"))]
#[cfg(feature = "sync")]
2022-02-08 09:25:53 +08:00
Union::Shared(ref cell, ..) => (*cell.read().unwrap()).type_id(),
2020-04-12 23:00:06 +08:00
}
}
2020-11-20 16:52:28 +08:00
/// Get the name of the type of the value held by this [`Dynamic`].
2020-08-02 13:33:51 +08:00
///
2020-08-04 16:27:55 +08:00
/// # Panics or Deadlocks When Value is Shared
2020-08-02 13:33:51 +08:00
///
2020-11-25 09:36:06 +08: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 13:33:51 +08:00
/// Otherwise, this call panics if the data is currently borrowed for write.
2021-06-12 22:47:43 +08:00
#[must_use]
2020-04-12 23:00:06 +08:00
pub fn type_name(&self) -> &'static str {
2021-06-13 17:41:34 +08:00
match self.0 {
2022-02-08 09:02:15 +08:00
Union::Unit(..) => "()",
Union::Bool(..) => "bool",
Union::Str(..) => "string",
Union::Char(..) => "char",
Union::Int(..) => type_name::<INT>(),
2020-04-12 23:00:06 +08:00
#[cfg(not(feature = "no_float"))]
2022-02-08 09:02:15 +08:00
Union::Float(..) => type_name::<crate::FLOAT>(),
2021-02-13 20:57:56 +08:00
#[cfg(feature = "decimal")]
2022-02-08 09:02:15 +08:00
Union::Decimal(..) => "decimal",
#[cfg(not(feature = "no_index"))]
2022-02-08 09:02:15 +08:00
Union::Array(..) => "array",
2021-11-23 14:58:54 +08:00
#[cfg(not(feature = "no_index"))]
2022-02-08 09:02:15 +08:00
Union::Blob(..) => "blob",
#[cfg(not(feature = "no_object"))]
2022-02-08 09:02:15 +08:00
Union::Map(..) => "map",
Union::FnPtr(..) => "Fn",
#[cfg(not(feature = "no_std"))]
2022-02-08 09:02:15 +08:00
Union::TimeStamp(..) => "timestamp",
2020-09-27 22:15:35 +08:00
2022-02-08 09:25:53 +08:00
Union::Variant(ref v, ..) => (***v).type_name(),
2020-08-08 11:46:30 +08:00
2020-08-03 12:10:20 +08:00
#[cfg(not(feature = "no_closure"))]
#[cfg(not(feature = "sync"))]
2022-02-08 09:25:53 +08:00
Union::Shared(ref cell, ..) => cell
2020-08-04 09:47:48 +08:00
.try_borrow()
.map(|v| (*v).type_name())
.unwrap_or("<shared>"),
2020-08-03 12:10:20 +08:00
#[cfg(not(feature = "no_closure"))]
#[cfg(feature = "sync")]
2022-02-08 09:25:53 +08:00
Union::Shared(ref cell, ..) => (*cell.read().unwrap()).type_name(),
2017-12-20 12:16:14 +01:00
}
}
}
2020-11-12 21:53:26 +08:00
impl Hash for Dynamic {
2021-06-06 14:47:32 +08:00
/// Hash the [`Dynamic`] value.
///
/// # Panics
///
/// Panics if the [`Dynamic`] value contains an unrecognized trait object.
2020-11-12 21:53:26 +08:00
fn hash<H: Hasher>(&self, state: &mut H) {
2021-12-30 12:19:41 +08:00
mem::discriminant(&self.0).hash(state);
2021-06-06 14:47:32 +08:00
2021-06-13 17:41:34 +08:00
match self.0 {
2022-02-08 09:02:15 +08:00
Union::Unit(..) => ().hash(state),
2022-02-08 09:25:53 +08:00
Union::Bool(ref b, ..) => b.hash(state),
Union::Str(ref s, ..) => s.hash(state),
Union::Char(ref c, ..) => c.hash(state),
Union::Int(ref i, ..) => i.hash(state),
2020-11-12 21:53:26 +08:00
#[cfg(not(feature = "no_float"))]
2022-02-08 09:25:53 +08:00
Union::Float(ref f, ..) => f.hash(state),
2021-07-04 16:51:05 +08:00
#[cfg(feature = "decimal")]
2022-02-08 09:25:53 +08:00
Union::Decimal(ref d, ..) => d.hash(state),
2020-11-12 21:53:26 +08:00
#[cfg(not(feature = "no_index"))]
2022-02-08 09:25:53 +08:00
Union::Array(ref a, ..) => a.as_ref().hash(state),
2021-11-23 14:58:54 +08:00
#[cfg(not(feature = "no_index"))]
2022-02-08 09:25:53 +08:00
Union::Blob(ref a, ..) => a.as_ref().hash(state),
2020-11-12 21:53:26 +08:00
#[cfg(not(feature = "no_object"))]
2022-02-08 09:25:53 +08:00
Union::Map(ref m, ..) => m.as_ref().hash(state),
Union::FnPtr(ref f, ..) => f.hash(state),
2020-11-12 21:53:26 +08:00
#[cfg(not(feature = "no_closure"))]
2021-06-13 17:41:34 +08:00
#[cfg(not(feature = "sync"))]
2022-02-08 09:25:53 +08:00
Union::Shared(ref cell, ..) => (*cell.borrow()).hash(state),
2021-03-05 14:18:36 +08:00
2021-06-13 17:41:34 +08:00
#[cfg(not(feature = "no_closure"))]
#[cfg(feature = "sync")]
2022-02-08 09:25:53 +08:00
Union::Shared(ref cell, ..) => (*cell.read().unwrap()).hash(state),
2020-11-12 21:53:26 +08:00
2022-02-08 09:25:53 +08:00
Union::Variant(ref v, ..) => {
2022-01-03 23:11:06 +08:00
let _v = v;
2021-07-04 16:51:05 +08:00
#[cfg(not(feature = "only_i32"))]
#[cfg(not(feature = "only_i64"))]
{
2022-01-03 23:11:06 +08:00
let value_any = (***_v).as_any();
2021-07-04 16:51:05 +08:00
let type_id = value_any.type_id();
if type_id == TypeId::of::<u8>() {
TypeId::of::<u8>().hash(state);
value_any.downcast_ref::<u8>().expect(CHECKED).hash(state);
} else if type_id == TypeId::of::<u16>() {
TypeId::of::<u16>().hash(state);
value_any.downcast_ref::<u16>().expect(CHECKED).hash(state);
} else if type_id == TypeId::of::<u32>() {
TypeId::of::<u32>().hash(state);
value_any.downcast_ref::<u32>().expect(CHECKED).hash(state);
} else if type_id == TypeId::of::<u64>() {
TypeId::of::<u64>().hash(state);
value_any.downcast_ref::<u64>().expect(CHECKED).hash(state);
} else if type_id == TypeId::of::<i8>() {
TypeId::of::<i8>().hash(state);
value_any.downcast_ref::<i8>().expect(CHECKED).hash(state);
} else if type_id == TypeId::of::<i16>() {
TypeId::of::<i16>().hash(state);
value_any.downcast_ref::<i16>().expect(CHECKED).hash(state);
} else if type_id == TypeId::of::<i32>() {
TypeId::of::<i32>().hash(state);
value_any.downcast_ref::<i32>().expect(CHECKED).hash(state);
} else if type_id == TypeId::of::<i64>() {
TypeId::of::<i64>().hash(state);
value_any.downcast_ref::<i64>().expect(CHECKED).hash(state);
}
2022-01-12 08:12:28 +08:00
#[cfg(not(target_family = "wasm"))]
2021-07-04 16:51:05 +08:00
if type_id == TypeId::of::<u128>() {
TypeId::of::<u128>().hash(state);
value_any.downcast_ref::<u128>().expect(CHECKED).hash(state);
} else if type_id == TypeId::of::<i128>() {
TypeId::of::<i128>().hash(state);
value_any.downcast_ref::<i128>().expect(CHECKED).hash(state);
}
2021-06-06 14:47:32 +08:00
}
2021-07-04 16:51:05 +08:00
unimplemented!("a custom type cannot be hashed")
2021-06-06 14:47:32 +08:00
}
2021-07-04 16:40:15 +08:00
#[cfg(not(feature = "no_std"))]
2022-02-08 09:02:15 +08:00
Union::TimeStamp(..) => unimplemented!("{} cannot be hashed", self.type_name()),
2020-11-12 21:53:26 +08:00
}
}
}
2020-04-12 23:00:06 +08:00
impl fmt::Display for Dynamic {
2019-09-18 11:21:07 +01:00
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2021-06-13 17:41:34 +08:00
match self.0 {
2022-02-08 09:02:15 +08:00
Union::Unit(..) => write!(f, ""),
2022-02-08 09:25:53 +08:00
Union::Bool(ref v, ..) => fmt::Display::fmt(v, f),
Union::Str(ref v, ..) => fmt::Display::fmt(v, f),
Union::Char(ref v, ..) => fmt::Display::fmt(v, f),
Union::Int(ref v, ..) => fmt::Display::fmt(v, f),
2020-04-12 23:00:06 +08:00
#[cfg(not(feature = "no_float"))]
2022-02-08 09:25:53 +08:00
Union::Float(ref v, ..) => fmt::Display::fmt(v, f),
2021-02-13 20:57:56 +08:00
#[cfg(feature = "decimal")]
2022-02-08 09:25:53 +08:00
Union::Decimal(ref v, ..) => fmt::Display::fmt(v, f),
#[cfg(not(feature = "no_index"))]
2022-02-08 09:02:15 +08:00
Union::Array(..) => fmt::Debug::fmt(self, f),
2021-11-23 14:58:54 +08:00
#[cfg(not(feature = "no_index"))]
2022-02-08 09:02:15 +08:00
Union::Blob(..) => fmt::Debug::fmt(self, f),
#[cfg(not(feature = "no_object"))]
2022-02-08 09:02:15 +08:00
Union::Map(..) => fmt::Debug::fmt(self, f),
2022-02-08 09:25:53 +08:00
Union::FnPtr(ref v, ..) => fmt::Display::fmt(v, f),
2020-05-05 20:54:56 +08:00
#[cfg(not(feature = "no_std"))]
2022-02-08 09:02:15 +08:00
Union::TimeStamp(..) => f.write_str("<timestamp>"),
2020-09-27 22:15:35 +08:00
2022-02-08 09:25:53 +08:00
Union::Variant(ref v, ..) => {
2022-01-03 23:11:06 +08:00
let _value_any = (***v).as_any();
2021-06-13 17:41:34 +08:00
let _type_id = _value_any.type_id();
#[cfg(not(feature = "only_i32"))]
#[cfg(not(feature = "only_i64"))]
if _type_id == TypeId::of::<u8>() {
2021-05-25 10:54:48 +08:00
return fmt::Display::fmt(_value_any.downcast_ref::<u8>().expect(CHECKED), f);
} else if _type_id == TypeId::of::<u16>() {
2021-05-25 10:54:48 +08:00
return fmt::Display::fmt(_value_any.downcast_ref::<u16>().expect(CHECKED), f);
} else if _type_id == TypeId::of::<u32>() {
2021-05-25 10:54:48 +08:00
return fmt::Display::fmt(_value_any.downcast_ref::<u32>().expect(CHECKED), f);
} else if _type_id == TypeId::of::<u64>() {
2021-05-25 10:54:48 +08:00
return fmt::Display::fmt(_value_any.downcast_ref::<u64>().expect(CHECKED), f);
} else if _type_id == TypeId::of::<i8>() {
2021-05-25 10:54:48 +08:00
return fmt::Display::fmt(_value_any.downcast_ref::<i8>().expect(CHECKED), f);
} else if _type_id == TypeId::of::<i16>() {
2021-05-25 10:54:48 +08:00
return fmt::Display::fmt(_value_any.downcast_ref::<i16>().expect(CHECKED), f);
} else if _type_id == TypeId::of::<i32>() {
2021-05-25 10:54:48 +08:00
return fmt::Display::fmt(_value_any.downcast_ref::<i32>().expect(CHECKED), f);
} else if _type_id == TypeId::of::<i64>() {
2021-05-25 10:54:48 +08:00
return fmt::Display::fmt(_value_any.downcast_ref::<i64>().expect(CHECKED), f);
}
#[cfg(not(feature = "no_float"))]
2022-01-04 22:16:20 +08:00
#[cfg(not(feature = "f32_float"))]
if _type_id == TypeId::of::<f32>() {
2021-05-25 10:54:48 +08:00
return fmt::Display::fmt(_value_any.downcast_ref::<f32>().expect(CHECKED), f);
2022-01-04 22:16:20 +08:00
}
#[cfg(not(feature = "no_float"))]
#[cfg(feature = "f32_float")]
if _type_id == TypeId::of::<f64>() {
2021-05-25 10:54:48 +08:00
return fmt::Display::fmt(_value_any.downcast_ref::<f64>().expect(CHECKED), f);
}
2022-01-04 22:16:20 +08:00
#[cfg(not(feature = "only_i32"))]
#[cfg(not(feature = "only_i64"))]
2022-01-12 08:12:28 +08:00
#[cfg(not(target_family = "wasm"))]
if _type_id == TypeId::of::<u128>() {
2021-05-25 10:54:48 +08:00
return fmt::Display::fmt(_value_any.downcast_ref::<u128>().expect(CHECKED), f);
} else if _type_id == TypeId::of::<i128>() {
2021-05-25 10:54:48 +08:00
return fmt::Display::fmt(_value_any.downcast_ref::<i128>().expect(CHECKED), f);
}
2021-12-15 12:06:17 +08:00
if _type_id == TypeId::of::<ExclusiveRange>() {
let range = _value_any.downcast_ref::<ExclusiveRange>().expect(CHECKED);
return write!(f, "{}..{}", range.start, range.end);
} else if _type_id == TypeId::of::<InclusiveRange>() {
let range = _value_any.downcast_ref::<InclusiveRange>().expect(CHECKED);
return write!(f, "{}..={}", range.start(), range.end());
}
2022-01-03 23:11:06 +08:00
f.write_str((***v).type_name())
}
2020-08-08 16:24:10 +08:00
2020-08-03 12:10:20 +08:00
#[cfg(not(feature = "no_closure"))]
2020-08-04 09:47:48 +08:00
#[cfg(not(feature = "sync"))]
2022-02-08 09:25:53 +08:00
Union::Shared(ref cell, ..) => {
2020-08-04 09:47:48 +08:00
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")]
2022-02-08 09:25:53 +08:00
Union::Shared(ref cell, ..) => fmt::Display::fmt(&*cell.read().unwrap(), f),
2020-04-12 23:00:06 +08:00
}
}
}
impl fmt::Debug for Dynamic {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2021-06-13 17:41:34 +08:00
match self.0 {
2022-02-08 09:25:53 +08:00
Union::Unit(ref v, ..) => fmt::Debug::fmt(v, f),
Union::Bool(ref v, ..) => fmt::Debug::fmt(v, f),
Union::Str(ref v, ..) => fmt::Debug::fmt(v, f),
Union::Char(ref v, ..) => fmt::Debug::fmt(v, f),
Union::Int(ref v, ..) => fmt::Debug::fmt(v, f),
2020-04-12 23:00:06 +08:00
#[cfg(not(feature = "no_float"))]
2022-02-08 09:25:53 +08:00
Union::Float(ref v, ..) => fmt::Debug::fmt(v, f),
2021-02-13 20:57:56 +08:00
#[cfg(feature = "decimal")]
2022-02-08 09:25:53 +08:00
Union::Decimal(ref v, ..) => fmt::Debug::fmt(v, f),
#[cfg(not(feature = "no_index"))]
2022-02-08 09:25:53 +08:00
Union::Array(ref v, ..) => fmt::Debug::fmt(v, f),
2021-11-23 14:58:54 +08:00
#[cfg(not(feature = "no_index"))]
2022-02-08 09:25:53 +08:00
Union::Blob(ref v, ..) => {
2021-12-13 09:40:43 +08:00
f.write_str("[")?;
2022-01-03 23:11:06 +08:00
v.iter().enumerate().try_for_each(|(i, v)| {
2021-12-13 09:40:43 +08:00
if i > 0 && i % 8 == 0 {
f.write_str(" ")?;
}
write!(f, "{:02x}", v)
})?;
f.write_str("]")
}
#[cfg(not(feature = "no_object"))]
2022-02-08 09:25:53 +08:00
Union::Map(ref v, ..) => {
f.write_str("#")?;
2022-01-03 23:11:06 +08:00
fmt::Debug::fmt(v, f)
}
2022-02-08 09:25:53 +08:00
Union::FnPtr(ref v, ..) => fmt::Debug::fmt(v, f),
2020-05-05 20:54:56 +08:00
#[cfg(not(feature = "no_std"))]
2022-02-08 09:02:15 +08:00
Union::TimeStamp(..) => write!(f, "<timestamp>"),
2020-09-27 22:15:35 +08:00
2022-02-08 09:25:53 +08:00
Union::Variant(ref v, ..) => {
2022-01-03 23:11:06 +08:00
let _value_any = (***v).as_any();
2021-06-13 17:41:34 +08:00
let _type_id = _value_any.type_id();
#[cfg(not(feature = "only_i32"))]
#[cfg(not(feature = "only_i64"))]
if _type_id == TypeId::of::<u8>() {
2021-05-25 10:54:48 +08:00
return fmt::Debug::fmt(_value_any.downcast_ref::<u8>().expect(CHECKED), f);
} else if _type_id == TypeId::of::<u16>() {
2021-05-25 10:54:48 +08:00
return fmt::Debug::fmt(_value_any.downcast_ref::<u16>().expect(CHECKED), f);
} else if _type_id == TypeId::of::<u32>() {
2021-05-25 10:54:48 +08:00
return fmt::Debug::fmt(_value_any.downcast_ref::<u32>().expect(CHECKED), f);
} else if _type_id == TypeId::of::<u64>() {
2021-05-25 10:54:48 +08:00
return fmt::Debug::fmt(_value_any.downcast_ref::<u64>().expect(CHECKED), f);
} else if _type_id == TypeId::of::<i8>() {
2021-05-25 10:54:48 +08:00
return fmt::Debug::fmt(_value_any.downcast_ref::<i8>().expect(CHECKED), f);
} else if _type_id == TypeId::of::<i16>() {
2021-05-25 10:54:48 +08:00
return fmt::Debug::fmt(_value_any.downcast_ref::<i16>().expect(CHECKED), f);
} else if _type_id == TypeId::of::<i32>() {
2021-05-25 10:54:48 +08:00
return fmt::Debug::fmt(_value_any.downcast_ref::<i32>().expect(CHECKED), f);
} else if _type_id == TypeId::of::<i64>() {
2021-05-25 10:54:48 +08:00
return fmt::Debug::fmt(_value_any.downcast_ref::<i64>().expect(CHECKED), f);
}
#[cfg(not(feature = "no_float"))]
2022-01-04 22:16:20 +08:00
#[cfg(not(feature = "f32_float"))]
if _type_id == TypeId::of::<f32>() {
2021-05-25 10:54:48 +08:00
return fmt::Debug::fmt(_value_any.downcast_ref::<f32>().expect(CHECKED), f);
2022-01-04 22:16:20 +08:00
}
#[cfg(not(feature = "no_float"))]
#[cfg(feature = "f32_float")]
if _type_id == TypeId::of::<f64>() {
2021-05-25 10:54:48 +08:00
return fmt::Debug::fmt(_value_any.downcast_ref::<f64>().expect(CHECKED), f);
}
2022-01-04 22:16:20 +08:00
#[cfg(not(feature = "only_i32"))]
#[cfg(not(feature = "only_i64"))]
2022-01-12 08:12:28 +08:00
#[cfg(not(target_family = "wasm"))]
if _type_id == TypeId::of::<u128>() {
2021-05-25 10:54:48 +08:00
return fmt::Debug::fmt(_value_any.downcast_ref::<u128>().expect(CHECKED), f);
} else if _type_id == TypeId::of::<i128>() {
2021-05-25 10:54:48 +08:00
return fmt::Debug::fmt(_value_any.downcast_ref::<i128>().expect(CHECKED), f);
}
2021-12-15 12:06:17 +08:00
if _type_id == TypeId::of::<ExclusiveRange>() {
let range = _value_any.downcast_ref::<ExclusiveRange>().expect(CHECKED);
return write!(f, "{}..{}", range.start, range.end);
} else if _type_id == TypeId::of::<InclusiveRange>() {
let range = _value_any.downcast_ref::<InclusiveRange>().expect(CHECKED);
return write!(f, "{}..={}", range.start(), range.end());
}
2022-01-03 23:11:06 +08:00
f.write_str((***v).type_name())
}
2020-08-08 16:24:10 +08:00
2020-08-03 12:10:20 +08:00
#[cfg(not(feature = "no_closure"))]
2020-08-04 09:47:48 +08:00
#[cfg(not(feature = "sync"))]
2022-02-08 09:25:53 +08:00
Union::Shared(ref cell, ..) => {
2020-08-04 09:47:48 +08:00
if let Ok(v) = cell.try_borrow() {
write!(f, "{:?} (shared)", *v)
} else {
f.write_str("<shared>")
}
}
#[cfg(not(feature = "no_closure"))]
#[cfg(feature = "sync")]
2022-02-08 09:25:53 +08:00
Union::Shared(ref cell, ..) => fmt::Debug::fmt(&*cell.read().unwrap(), f),
2020-04-12 23:00:06 +08:00
}
2017-12-20 12:16:14 +01:00
}
}
2021-05-29 18:33:29 +08:00
use AccessMode::*;
2020-03-04 22:00:01 +08:00
impl Clone for Dynamic {
2020-12-08 22:47:38 +08:00
/// Clone the [`Dynamic`] value.
///
2021-01-02 23:30:10 +08:00
/// # WARNING
2020-12-08 22:47:38 +08:00
///
/// The cloned copy is marked read-write even if the original is read-only.
2020-03-04 22:00:01 +08:00
fn clone(&self) -> Self {
2020-05-03 22:17:28 +08:00
match self.0 {
2022-02-08 09:02:15 +08:00
Union::Unit(v, tag, ..) => Self(Union::Unit(v, tag, ReadWrite)),
Union::Bool(v, tag, ..) => Self(Union::Bool(v, tag, ReadWrite)),
Union::Str(ref v, tag, ..) => Self(Union::Str(v.clone(), tag, ReadWrite)),
Union::Char(v, tag, ..) => Self(Union::Char(v, tag, ReadWrite)),
Union::Int(v, tag, ..) => Self(Union::Int(v, tag, ReadWrite)),
2020-04-12 23:00:06 +08:00
#[cfg(not(feature = "no_float"))]
2022-02-08 09:02:15 +08:00
Union::Float(v, tag, ..) => Self(Union::Float(v, tag, ReadWrite)),
2021-02-13 20:57:56 +08:00
#[cfg(feature = "decimal")]
2022-02-08 09:02:15 +08:00
Union::Decimal(ref v, tag, ..) => Self(Union::Decimal(v.clone(), tag, ReadWrite)),
#[cfg(not(feature = "no_index"))]
2022-02-08 09:02:15 +08:00
Union::Array(ref v, tag, ..) => Self(Union::Array(v.clone(), tag, ReadWrite)),
2021-11-23 14:58:54 +08:00
#[cfg(not(feature = "no_index"))]
2022-02-08 09:02:15 +08:00
Union::Blob(ref v, tag, ..) => Self(Union::Blob(v.clone(), tag, ReadWrite)),
#[cfg(not(feature = "no_object"))]
2022-02-08 09:02:15 +08:00
Union::Map(ref v, tag, ..) => Self(Union::Map(v.clone(), tag, ReadWrite)),
Union::FnPtr(ref v, tag, ..) => Self(Union::FnPtr(v.clone(), tag, ReadWrite)),
2020-09-27 22:15:35 +08:00
#[cfg(not(feature = "no_std"))]
2022-02-08 09:02:15 +08:00
Union::TimeStamp(ref v, tag, ..) => Self(Union::TimeStamp(v.clone(), tag, ReadWrite)),
2020-08-08 11:46:30 +08:00
2022-02-08 09:02:15 +08:00
Union::Variant(ref v, tag, ..) => Self(Union::Variant(
2022-01-03 23:11:06 +08:00
v.as_ref().as_ref().clone_object().into(),
2022-01-01 19:54:46 +08:00
tag,
ReadWrite,
)),
2020-08-08 11:46:30 +08:00
2020-08-03 12:10:20 +08:00
#[cfg(not(feature = "no_closure"))]
2022-02-08 09:02:15 +08:00
Union::Shared(ref cell, tag, ..) => Self(Union::Shared(cell.clone(), tag, ReadWrite)),
2020-04-12 23:00:06 +08:00
}
2020-03-04 22:00:01 +08:00
}
}
2020-04-30 22:52:36 +08:00
impl Default for Dynamic {
2020-08-08 11:46:30 +08:00
#[inline(always)]
2021-06-12 22:47:43 +08:00
#[must_use]
2020-04-30 22:52:36 +08:00
fn default() -> Self {
2020-11-15 23:14:29 +08:00
Self::UNIT
2020-04-30 22:52:36 +08:00
}
}
2021-12-15 12:06:17 +08:00
#[cfg(not(feature = "no_float"))]
#[cfg(feature = "f32_float")]
use std::f32::consts as FloatConstants;
#[cfg(not(feature = "no_float"))]
#[cfg(not(feature = "f32_float"))]
use std::f64::consts as FloatConstants;
2020-04-12 23:00:06 +08:00
impl Dynamic {
2020-11-20 16:52:28 +08:00
/// A [`Dynamic`] containing a `()`.
pub const UNIT: Self = Self(Union::Unit((), DEFAULT_TAG_VALUE, ReadWrite));
2020-11-20 16:52:28 +08:00
/// A [`Dynamic`] containing a `true`.
pub const TRUE: Self = Self::from_bool(true);
2020-11-20 16:52:28 +08:00
/// A [`Dynamic`] containing a [`false`].
pub const FALSE: Self = Self::from_bool(false);
2020-11-20 16:52:28 +08:00
/// A [`Dynamic`] containing the integer zero.
pub const ZERO: Self = Self::from_int(0);
2021-12-15 12:06:17 +08:00
/// A [`Dynamic`] containing the integer 1.
pub const ONE: Self = Self::from_int(1);
2021-12-15 12:06:17 +08:00
/// A [`Dynamic`] containing the integer 2.
pub const TWO: Self = Self::from_int(2);
2021-12-15 12:06:17 +08:00
/// A [`Dynamic`] containing the integer 3.
pub const THREE: Self = Self::from_int(3);
2021-12-15 12:06:17 +08:00
/// A [`Dynamic`] containing the integer 10.
pub const TEN: Self = Self::from_int(10);
2021-12-15 12:06:17 +08:00
/// A [`Dynamic`] containing the integer 100.
pub const HUNDRED: Self = Self::from_int(100);
2021-12-15 12:06:17 +08:00
/// A [`Dynamic`] containing the integer 1,000.
pub const THOUSAND: Self = Self::from_int(1000);
2021-12-15 12:06:17 +08:00
/// A [`Dynamic`] containing the integer 1,000,000.
pub const MILLION: Self = Self::from_int(1000000);
/// A [`Dynamic`] containing the integer -1.
pub const NEGATIVE_ONE: Self = Self::from_int(-1);
2021-12-15 12:06:17 +08:00
/// A [`Dynamic`] containing the integer -2.
pub const NEGATIVE_TWO: Self = Self::from_int(-2);
2021-05-10 11:07:19 +08:00
/// A [`Dynamic`] containing `0.0`.
///
/// Not available under `no_float`.
2020-11-16 13:56:07 +08:00
#[cfg(not(feature = "no_float"))]
pub const FLOAT_ZERO: Self = Self::from_float(0.0);
2021-05-10 11:07:19 +08:00
/// A [`Dynamic`] containing `1.0`.
///
/// Not available under `no_float`.
2020-11-16 13:56:07 +08:00
#[cfg(not(feature = "no_float"))]
pub const FLOAT_ONE: Self = Self::from_float(1.0);
/// A [`Dynamic`] containing `2.0`.
///
/// Not available under `no_float`.
#[cfg(not(feature = "no_float"))]
pub const FLOAT_TWO: Self = Self::from_float(2.0);
/// A [`Dynamic`] containing `10.0`.
///
/// Not available under `no_float`.
#[cfg(not(feature = "no_float"))]
pub const FLOAT_TEN: Self = Self::from_float(10.0);
2021-07-25 11:50:31 +08:00
/// A [`Dynamic`] containing `100.0`.
///
/// Not available under `no_float`.
#[cfg(not(feature = "no_float"))]
pub const FLOAT_HUNDRED: Self = Self::from_float(100.0);
2021-07-25 11:50:31 +08:00
/// A [`Dynamic`] containing `1000.0`.
///
/// Not available under `no_float`.
#[cfg(not(feature = "no_float"))]
pub const FLOAT_THOUSAND: Self = Self::from_float(1000.0);
2021-12-15 12:06:17 +08:00
/// A [`Dynamic`] containing `1000000.0`.
///
/// Not available under `no_float`.
#[cfg(not(feature = "no_float"))]
pub const FLOAT_MILLION: Self = Self::from_float(1000000.0);
2021-07-25 11:50:31 +08:00
/// A [`Dynamic`] containing `-1.0`.
2021-05-10 11:07:19 +08:00
///
/// Not available under `no_float`.
2020-11-16 13:56:07 +08:00
#[cfg(not(feature = "no_float"))]
pub const FLOAT_NEGATIVE_ONE: Self = Self::from_float(-1.0);
2021-12-15 12:06:17 +08:00
/// A [`Dynamic`] containing `-2.0`.
///
/// Not available under `no_float`.
#[cfg(not(feature = "no_float"))]
pub const FLOAT_NEGATIVE_TWO: Self = Self::from_float(-2.0);
/// A [`Dynamic`] containing `0.5`.
///
/// Not available under `no_float`.
#[cfg(not(feature = "no_float"))]
pub const FLOAT_HALF: Self = Self::from_float(0.5);
/// A [`Dynamic`] containing `0.25`.
///
/// Not available under `no_float`.
#[cfg(not(feature = "no_float"))]
pub const FLOAT_QUARTER: Self = Self::from_float(0.25);
/// A [`Dynamic`] containing `0.2`.
///
/// Not available under `no_float`.
#[cfg(not(feature = "no_float"))]
pub const FLOAT_FIFTH: Self = Self::from_float(0.2);
/// A [`Dynamic`] containing `0.1`.
///
/// Not available under `no_float`.
#[cfg(not(feature = "no_float"))]
pub const FLOAT_TENTH: Self = Self::from_float(0.1);
/// A [`Dynamic`] containing `0.01`.
///
/// Not available under `no_float`.
#[cfg(not(feature = "no_float"))]
pub const FLOAT_HUNDREDTH: Self = Self::from_float(0.01);
/// A [`Dynamic`] containing `0.001`.
///
/// Not available under `no_float`.
#[cfg(not(feature = "no_float"))]
pub const FLOAT_THOUSANDTH: Self = Self::from_float(0.001);
/// A [`Dynamic`] containing `0.000001`.
///
/// Not available under `no_float`.
#[cfg(not(feature = "no_float"))]
pub const FLOAT_MILLIONTH: Self = Self::from_float(0.000001);
2021-07-25 11:50:31 +08:00
/// A [`Dynamic`] containing π.
///
/// Not available under `no_float`.
#[cfg(not(feature = "no_float"))]
2021-12-15 12:06:17 +08:00
pub const FLOAT_PI: Self = Self::from_float(FloatConstants::PI);
2021-07-25 11:50:31 +08:00
/// A [`Dynamic`] containing π/2.
///
/// Not available under `no_float`.
#[cfg(not(feature = "no_float"))]
2021-12-15 12:06:17 +08:00
pub const FLOAT_HALF_PI: Self = Self::from_float(FloatConstants::FRAC_PI_2);
/// A [`Dynamic`] containing π/4.
///
/// Not available under `no_float`.
#[cfg(not(feature = "no_float"))]
pub const FLOAT_QUARTER_PI: Self = Self::from_float(FloatConstants::FRAC_PI_4);
2021-07-25 11:50:31 +08:00
/// A [`Dynamic`] containing 2π.
///
/// Not available under `no_float`.
#[cfg(not(feature = "no_float"))]
2021-12-15 12:06:17 +08:00
pub const FLOAT_TWO_PI: Self = Self::from_float(FloatConstants::TAU);
/// A [`Dynamic`] containing 1/π.
///
/// Not available under `no_float`.
#[cfg(not(feature = "no_float"))]
pub const FLOAT_INVERSE_PI: Self = Self::from_float(FloatConstants::FRAC_1_PI);
/// A [`Dynamic`] containing _e_.
///
/// Not available under `no_float`.
#[cfg(not(feature = "no_float"))]
pub const FLOAT_E: Self = Self::from_float(FloatConstants::E);
/// A [`Dynamic`] containing `log` _e_.
///
/// Not available under `no_float`.
#[cfg(not(feature = "no_float"))]
pub const FLOAT_LOG_E: Self = Self::from_float(FloatConstants::LOG10_E);
/// A [`Dynamic`] containing `ln 10`.
///
/// Not available under `no_float`.
#[cfg(not(feature = "no_float"))]
pub const FLOAT_LN_10: Self = Self::from_float(FloatConstants::LN_10);
/// Create a new [`Dynamic`] from a [`bool`].
#[inline(always)]
pub const fn from_bool(value: bool) -> Self {
Self(Union::Bool(value, DEFAULT_TAG_VALUE, ReadWrite))
}
/// Create a new [`Dynamic`] from an [`INT`].
#[inline(always)]
pub const fn from_int(value: INT) -> Self {
Self(Union::Int(value, DEFAULT_TAG_VALUE, ReadWrite))
}
/// Create a new [`Dynamic`] from a [`char`].
#[inline(always)]
pub const fn from_char(value: char) -> Self {
Self(Union::Char(value, DEFAULT_TAG_VALUE, ReadWrite))
}
2021-12-06 20:52:47 +08:00
/// Create a new [`Dynamic`] from a [`FLOAT`][crate::FLOAT].
///
/// Not available under `no_float`.
#[cfg(not(feature = "no_float"))]
#[inline(always)]
2021-12-06 20:52:47 +08:00
pub const fn from_float(value: crate::FLOAT) -> Self {
Self(Union::Float(
2021-12-06 20:52:47 +08:00
crate::ast::FloatWrapper::new_const(value),
DEFAULT_TAG_VALUE,
ReadWrite,
))
}
/// Create a new [`Dynamic`] from a [`Decimal`](https://docs.rs/rust_decimal).
///
/// Exported under the `decimal` feature only.
#[cfg(feature = "decimal")]
#[inline(always)]
2021-12-06 20:52:47 +08:00
pub fn from_decimal(value: rust_decimal::Decimal) -> Self {
Self(Union::Decimal(value.into(), DEFAULT_TAG_VALUE, ReadWrite))
}
2021-12-18 12:28:56 +08:00
/// Create a [`Dynamic`] from an [`Array`][crate::Array].
#[cfg(not(feature = "no_index"))]
#[inline(always)]
pub fn from_array(array: crate::Array) -> Self {
Self(Union::Array(array.into(), DEFAULT_TAG_VALUE, ReadWrite))
}
/// Create a [`Dynamic`] from a [`Blob`][crate::Blob].
#[cfg(not(feature = "no_index"))]
#[inline(always)]
pub fn from_blob(blob: crate::Blob) -> Self {
Self(Union::Blob(blob.into(), DEFAULT_TAG_VALUE, ReadWrite))
}
/// Create a [`Dynamic`] from a [`Map`][crate::Map].
#[cfg(not(feature = "no_object"))]
#[inline(always)]
pub fn from_map(map: crate::Map) -> Self {
Self(Union::Map(map.into(), DEFAULT_TAG_VALUE, ReadWrite))
}
/// Create a new [`Dynamic`] from an [`Instant`].
///
/// Not available under `no-std`.
#[cfg(not(feature = "no_std"))]
#[inline(always)]
pub fn from_timestamp(value: Instant) -> Self {
Self(Union::TimeStamp(value.into(), DEFAULT_TAG_VALUE, ReadWrite))
}
2020-11-15 23:14:29 +08:00
/// Get the [`AccessMode`] for this [`Dynamic`].
2021-06-12 22:47:43 +08:00
#[must_use]
2021-05-25 10:54:48 +08:00
pub(crate) const fn access_mode(&self) -> AccessMode {
2020-12-08 22:47:38 +08:00
match self.0 {
2022-02-08 09:25:53 +08:00
Union::Unit(.., access)
| Union::Bool(.., access)
| Union::Str(.., access)
| Union::Char(.., access)
| Union::Int(.., access)
| Union::FnPtr(.., access)
| Union::Variant(.., access) => access,
2020-12-08 23:09:12 +08:00
#[cfg(not(feature = "no_float"))]
2022-02-08 09:25:53 +08:00
Union::Float(.., access) => access,
2021-02-13 20:57:56 +08:00
#[cfg(feature = "decimal")]
2022-02-08 09:25:53 +08:00
Union::Decimal(.., access) => access,
2020-12-08 23:09:12 +08:00
#[cfg(not(feature = "no_index"))]
2022-02-08 09:25:53 +08:00
Union::Array(.., access) | Union::Blob(.., access) => access,
2020-12-08 23:09:12 +08:00
#[cfg(not(feature = "no_object"))]
2022-02-08 09:25:53 +08:00
Union::Map(.., access) => access,
2020-12-08 23:09:12 +08:00
#[cfg(not(feature = "no_std"))]
2022-02-08 09:25:53 +08:00
Union::TimeStamp(.., access) => access,
2020-12-08 23:09:12 +08:00
#[cfg(not(feature = "no_closure"))]
2022-02-08 09:25:53 +08:00
Union::Shared(.., access) => access,
2020-12-08 22:47:38 +08:00
}
}
/// Set the [`AccessMode`] for this [`Dynamic`].
2021-06-12 22:47:43 +08:00
pub(crate) fn set_access_mode(&mut self, typ: AccessMode) -> &mut Self {
2021-06-13 17:41:34 +08:00
match self.0 {
2022-02-08 09:25:53 +08:00
Union::Unit(.., ref mut access)
| Union::Bool(.., ref mut access)
| Union::Str(.., ref mut access)
| Union::Char(.., ref mut access)
| Union::Int(.., ref mut access)
| Union::FnPtr(.., ref mut access)
| Union::Variant(.., ref mut access) => *access = typ,
2020-12-08 23:09:12 +08:00
#[cfg(not(feature = "no_float"))]
2022-02-08 09:25:53 +08:00
Union::Float(.., ref mut access) => *access = typ,
2021-02-13 20:57:56 +08:00
#[cfg(feature = "decimal")]
2022-02-08 09:25:53 +08:00
Union::Decimal(.., ref mut access) => *access = typ,
2020-12-08 23:09:12 +08:00
#[cfg(not(feature = "no_index"))]
2021-06-13 17:41:34 +08:00
Union::Array(ref mut a, _, ref mut access) => {
*access = typ;
2022-01-28 18:59:18 +08:00
for v in a.iter_mut() {
2021-06-12 22:47:43 +08:00
v.set_access_mode(typ);
2022-01-28 18:59:18 +08:00
}
}
2021-11-23 14:58:54 +08:00
#[cfg(not(feature = "no_index"))]
2022-02-08 09:25:53 +08:00
Union::Blob(.., ref mut access) => *access = typ,
2020-12-08 23:09:12 +08:00
#[cfg(not(feature = "no_object"))]
2021-06-13 17:41:34 +08:00
Union::Map(ref mut m, _, ref mut access) => {
*access = typ;
2022-01-28 18:59:18 +08:00
for v in m.values_mut() {
2021-06-12 22:47:43 +08:00
v.set_access_mode(typ);
2022-01-28 18:59:18 +08:00
}
}
2020-12-08 23:09:12 +08:00
#[cfg(not(feature = "no_std"))]
2022-02-08 09:25:53 +08:00
Union::TimeStamp(.., ref mut access) => *access = typ,
2020-12-08 23:09:12 +08:00
#[cfg(not(feature = "no_closure"))]
2022-02-08 09:25:53 +08:00
Union::Shared(.., ref mut access) => *access = typ,
2020-12-08 22:47:38 +08:00
}
2021-06-12 22:47:43 +08:00
self
2020-12-08 22:47:38 +08:00
}
2020-12-08 23:09:12 +08:00
/// Is this [`Dynamic`] read-only?
///
2022-02-24 10:36:20 +08:00
/// Constant [`Dynamic`] values are read-only.
///
/// If a [`&mut Dynamic`][Dynamic] to such a constant is passed to a Rust function, the function
/// can use this information to return an error of
/// [`ErrorAssignmentToConstant`][crate::EvalAltResult::ErrorAssignmentToConstant] if its value
/// is going to be modified.
///
/// This safe-guards constant values from being modified from within Rust functions.
2021-06-12 22:47:43 +08:00
#[must_use]
2020-12-08 23:09:12 +08:00
pub fn is_read_only(&self) -> bool {
#[cfg(not(feature = "no_closure"))]
2020-12-09 21:06:36 +08:00
match self.0 {
2022-02-08 09:25:53 +08:00
Union::Shared(.., ReadOnly) => return true,
2020-12-09 21:06:36 +08:00
2021-06-13 17:41:34 +08:00
#[cfg(not(feature = "sync"))]
2022-02-08 09:25:53 +08:00
Union::Shared(ref cell, ..) => {
2021-06-13 17:41:34 +08:00
return match cell.borrow().access_mode() {
ReadWrite => false,
ReadOnly => true,
}
}
#[cfg(feature = "sync")]
2022-02-08 09:25:53 +08:00
Union::Shared(ref cell, ..) => {
2021-06-13 17:41:34 +08:00
return match cell.read().unwrap().access_mode() {
2021-05-29 18:33:29 +08:00
ReadWrite => false,
ReadOnly => true,
2021-06-13 17:41:34 +08:00
}
2021-03-05 13:34:58 +08:00
}
2021-06-13 17:41:34 +08:00
_ => (),
}
2020-12-09 21:06:36 +08:00
match self.access_mode() {
2021-05-29 18:33:29 +08:00
ReadWrite => false,
ReadOnly => true,
2020-12-09 21:06:36 +08:00
}
2020-12-08 22:47:38 +08:00
}
2021-03-05 10:33:48 +08:00
/// Can this [`Dynamic`] be hashed?
2021-06-12 22:47:43 +08:00
#[must_use]
2021-03-05 10:33:48 +08:00
pub(crate) fn is_hashable(&self) -> bool {
2021-06-13 17:41:34 +08:00
match self.0 {
2022-02-08 09:02:15 +08:00
Union::Unit(..)
| Union::Bool(..)
| Union::Str(..)
| Union::Char(..)
| Union::Int(..) => true,
2021-03-05 10:33:48 +08:00
#[cfg(not(feature = "no_float"))]
2022-02-08 09:02:15 +08:00
Union::Float(..) => true,
2021-03-05 10:33:48 +08:00
#[cfg(not(feature = "no_index"))]
2022-02-08 09:02:15 +08:00
Union::Array(..) => true,
2021-03-05 10:33:48 +08:00
#[cfg(not(feature = "no_object"))]
2022-02-08 09:02:15 +08:00
Union::Map(..) => true,
2021-03-05 10:33:48 +08:00
#[cfg(not(feature = "no_closure"))]
2021-06-13 17:41:34 +08:00
#[cfg(not(feature = "sync"))]
2022-02-08 09:25:53 +08:00
Union::Shared(ref cell, ..) => cell.borrow().is_hashable(),
2021-03-05 14:18:36 +08:00
2021-06-13 17:41:34 +08:00
#[cfg(not(feature = "no_closure"))]
#[cfg(feature = "sync")]
2022-02-08 09:25:53 +08:00
Union::Shared(ref cell, ..) => cell.read().unwrap().is_hashable(),
2021-03-05 10:33:48 +08:00
_ => false,
}
}
2020-11-20 16:52:28 +08:00
/// Create a [`Dynamic`] from any type. A [`Dynamic`] value is simply returned as is.
///
/// # Notes
///
2022-02-24 10:36:20 +08:00
/// Beware that you need to pass in an [`Array`][crate::Array] type for it to be recognized as
/// an [`Array`][crate::Array]. A [`Vec<T>`][Vec] does not get automatically converted to an
/// [`Array`][crate::Array], but will be a custom type instead (stored as a trait object). Use
/// `Into<Dynamic>` to convert a [`Vec<T>`][Vec] into a [`Dynamic`] as an
/// [`Array`][crate::Array] value.
///
2021-03-23 12:13:53 +08:00
/// Similarly, passing in a [`HashMap<String, T>`][std::collections::HashMap] or
2022-02-24 10:36:20 +08:00
/// [`BTreeMap<String, T>`][std::collections::BTreeMap] will not get a [`Map`][crate::Map] but a
/// custom type. Again, use `Into<Dynamic>` to get a [`Dynamic`] with a [`Map`][crate::Map]
/// value.
///
2020-04-12 23:00:06 +08:00
/// # Examples
///
2020-04-12 23:00:06 +08: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 11:44:06 +08:00
/// let result = Dynamic::from("hello");
2020-04-12 23:00:06 +08:00
/// assert_eq!(result.type_name(), "string");
/// assert_eq!(result.to_string(), "hello");
2020-04-13 10:27:08 +08:00
///
/// let new_result = Dynamic::from(result);
/// assert_eq!(new_result.type_name(), "string");
/// assert_eq!(new_result.to_string(), "hello");
2020-04-12 23:00:06 +08:00
/// ```
#[inline]
2021-06-12 22:47:43 +08:00
#[must_use]
pub fn from<T: Variant + Clone>(value: T) -> Self {
2020-10-08 22:25:50 +08:00
// Coded this way in order to maximally leverage potentials for dead-code removal.
reify!(value, |v: Dynamic| return v);
reify!(value, |v: INT| return v.into());
2021-05-25 10:54:48 +08:00
2020-04-12 23:00:06 +08:00
#[cfg(not(feature = "no_float"))]
reify!(value, |v: crate::FLOAT| return v.into());
2021-02-13 20:57:56 +08:00
#[cfg(feature = "decimal")]
reify!(value, |v: rust_decimal::Decimal| return v.into());
2020-04-12 23:00:06 +08:00
reify!(value, |v: bool| return v.into());
reify!(value, |v: char| return v.into());
reify!(value, |v: ImmutableString| return v.into());
2022-02-06 23:02:59 +08:00
reify!(value, |v: String| return v.into());
reify!(value, |v: &str| return v.into());
reify!(value, |v: ()| return v.into());
#[cfg(not(feature = "no_index"))]
reify!(value, |v: crate::Array| return v.into());
2021-11-23 14:58:54 +08:00
#[cfg(not(feature = "no_index"))]
reify!(value, |v: crate::Blob| {
// don't use blob.into() because it'll be converted into an Array
return Dynamic::from_blob(v);
});
#[cfg(not(feature = "no_object"))]
reify!(value, |v: crate::Map| return v.into());
reify!(value, |v: FnPtr| return v.into());
2020-08-03 23:11:24 +08:00
2020-09-27 22:15:35 +08:00
#[cfg(not(feature = "no_std"))]
reify!(value, |v: Instant| return v.into());
2021-05-11 21:38:07 +08:00
#[cfg(not(feature = "no_closure"))]
2022-02-06 23:02:59 +08:00
reify!(value, |v: crate::Shared<crate::Locked<Dynamic>>| return v
.into());
2020-09-27 22:15:35 +08:00
2021-03-22 11:18:09 +08:00
Self(Union::Variant(
Box::new(Box::new(value)),
2021-06-28 18:06:05 +08:00
DEFAULT_TAG_VALUE,
2021-05-29 18:33:29 +08:00
ReadWrite,
2021-03-22 11:18:09 +08:00
))
2020-04-12 23:00:06 +08:00
}
2020-12-26 13:05:57 +08:00
/// Turn the [`Dynamic`] value into a shared [`Dynamic`] value backed by an
2021-12-18 12:28:56 +08:00
/// [`Rc<RefCell<Dynamic>>`][std::rc::Rc] or [`Arc<RwLock<Dynamic>>`][std::sync::Arc]
2020-12-26 13:05:57 +08:00
/// depending on the `sync` feature.
2020-03-04 22:00:01 +08:00
///
2021-02-19 15:50:48 +08:00
/// Not available under `no_closure`.
///
2020-11-20 16:52:28 +08:00
/// Shared [`Dynamic`] values are relatively cheap to clone as they simply increment the
/// reference counts.
///
2020-12-26 13:05:57 +08:00
/// Shared [`Dynamic`] values can be converted seamlessly to and from ordinary [`Dynamic`]
/// values.
///
2020-11-20 16:52:28 +08:00
/// If the [`Dynamic`] value is already shared, this method returns itself.
#[cfg(not(feature = "no_closure"))]
#[inline]
2021-06-12 22:47:43 +08:00
#[must_use]
pub fn into_shared(self) -> Self {
let _access = self.access_mode();
2020-12-08 22:47:38 +08:00
match self.0 {
2022-02-08 09:02:15 +08:00
Union::Shared(..) => self,
2021-05-02 23:57:35 +08:00
_ => Self(Union::Shared(
crate::Locked::new(self).into(),
2021-06-28 18:06:05 +08:00
DEFAULT_TAG_VALUE,
2021-05-02 23:57:35 +08:00
_access,
)),
}
}
2020-11-20 16:52:28 +08:00
/// Convert the [`Dynamic`] value into specific type.
2020-07-31 16:39:38 +08:00
///
2020-11-20 16:52:28 +08: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 22:00:01 +08:00
///
2020-11-20 16:52:28 +08:00
/// Returns [`None`] if types mismatched.
///
2020-08-04 16:27:55 +08:00
/// # Panics or Deadlocks
///
2020-11-25 09:36:06 +08: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 23:00:06 +08:00
///
2020-03-04 22:00:01 +08:00
/// # Example
///
2020-03-19 13:52:10 +08:00
/// ```
2020-04-12 23:00:06 +08:00
/// use rhai::Dynamic;
2020-03-04 22:00:01 +08:00
///
2020-04-12 23:00:06 +08:00
/// let x = Dynamic::from(42_u32);
2020-03-04 22:00:01 +08:00
///
2021-08-26 23:58:41 +08:00
/// assert_eq!(x.try_cast::<u32>().expect("x should be u32"), 42);
2020-03-04 22:00:01 +08:00
/// ```
#[inline]
2021-06-12 22:47:43 +08:00
#[must_use]
2021-04-19 18:08:29 +08:00
pub fn try_cast<T: Any>(self) -> Option<T> {
2020-10-08 22:25:50 +08:00
// Coded this way in order to maximally leverage potentials for dead-code removal.
2021-03-04 10:50:45 +08:00
#[cfg(not(feature = "no_closure"))]
2022-02-08 09:02:15 +08:00
if let Union::Shared(..) = self.0 {
2021-03-04 10:24:14 +08:00
return self.flatten().try_cast::<T>();
2020-07-31 16:39:38 +08:00
}
2022-02-07 12:02:00 +08:00
reify!(self, |v: T| return Some(v));
2020-04-13 10:27:08 +08:00
2020-04-30 22:52:36 +08:00
match self.0 {
2022-02-08 09:25:53 +08:00
Union::Int(v, ..) => reify!(v => Option<T>),
#[cfg(not(feature = "no_float"))]
2022-02-08 09:25:53 +08:00
Union::Float(v, ..) => reify!(*v => Option<T>),
#[cfg(feature = "decimal")]
2022-02-08 09:25:53 +08:00
Union::Decimal(v, ..) => reify!(*v => Option<T>),
Union::Bool(v, ..) => reify!(v => Option<T>),
Union::Str(v, ..) => {
2022-02-08 09:25:53 +08:00
reify!(v, |v: T| Some(v), || reify!(v.to_string() => Option<T>))
2022-02-06 23:02:59 +08:00
}
2022-02-08 09:25:53 +08:00
Union::Char(v, ..) => reify!(v => Option<T>),
#[cfg(not(feature = "no_index"))]
2022-02-08 09:25:53 +08:00
Union::Array(v, ..) => reify!(*v => Option<T>),
#[cfg(not(feature = "no_index"))]
2022-02-08 09:25:53 +08:00
Union::Blob(v, ..) => reify!(*v => Option<T>),
#[cfg(not(feature = "no_object"))]
2022-02-08 09:25:53 +08:00
Union::Map(v, ..) => reify!(*v => Option<T>),
Union::FnPtr(v, ..) => reify!(*v => Option<T>),
#[cfg(not(feature = "no_std"))]
2022-02-08 09:25:53 +08:00
Union::TimeStamp(v, ..) => reify!(*v => Option<T>),
Union::Unit(v, ..) => reify!(v => Option<T>),
Union::Variant(v, ..) => (*v).as_boxed_any().downcast().ok().map(|x| *x),
2020-08-03 12:10:20 +08:00
#[cfg(not(feature = "no_closure"))]
2022-02-08 09:25:53 +08:00
Union::Shared(..) => unreachable!("Union::Shared case should be already handled"),
2017-12-20 12:16:14 +01:00
}
}
2020-11-20 16:52:28 +08:00
/// Convert the [`Dynamic`] value into a specific type.
///
2020-11-20 16:52:28 +08: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-08-04 16:27:55 +08:00
/// # Panics or Deadlocks
///
2022-01-06 10:19:25 +08:00
/// Panics if the cast fails (e.g. the type of the actual value is not the same as the specified type).
///
2020-11-25 09:36:06 +08: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 23:00:06 +08:00
/// use rhai::Dynamic;
///
2020-04-12 23:00:06 +08:00
/// let x = Dynamic::from(42_u32);
///
/// assert_eq!(x.cast::<u32>(), 42);
/// ```
#[inline]
2021-06-12 22:47:43 +08:00
#[must_use]
2021-04-19 18:08:29 +08:00
pub fn cast<T: Any + Clone>(self) -> T {
#[cfg(not(feature = "no_closure"))]
2020-09-27 11:14:50 +08:00
let self_type_name = if self.is_shared() {
// Avoid panics/deadlocks with shared values
"<shared>"
} else {
self.type_name()
};
#[cfg(feature = "no_closure")]
let self_type_name = self.type_name();
2020-09-27 11:14:50 +08:00
2022-02-06 23:02:59 +08:00
self.try_cast::<T>()
.unwrap_or_else(|| panic!("cannot cast {} to {}", self_type_name, type_name::<T>()))
}
2021-03-30 18:57:16 +08:00
/// Clone the [`Dynamic`] value and convert it into a specific type.
///
/// 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.
///
/// # Panics or Deadlocks
///
/// Panics if the cast fails (e.g. the type of the actual value is not the
/// same as the specified type).
///
/// 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
///
/// ```
/// use rhai::Dynamic;
///
/// let x = Dynamic::from(42_u32);
/// let y = &x;
///
/// assert_eq!(y.clone_cast::<u32>(), 42);
/// ```
#[inline(always)]
2021-06-12 22:47:43 +08:00
#[must_use]
2021-04-19 18:08:29 +08:00
pub fn clone_cast<T: Any + Clone>(&self) -> T {
self.flatten_clone().cast::<T>()
2021-03-30 18:57:16 +08:00
}
2020-11-20 16:52:28 +08:00
/// Flatten the [`Dynamic`] and clone it.
///
2020-11-20 16:52:28 +08:00
/// If the [`Dynamic`] is not a shared value, it returns a cloned copy.
///
/// If the [`Dynamic`] is a shared value, it returns a cloned copy of the shared value.
#[inline]
2021-06-12 22:47:43 +08:00
#[must_use]
2020-08-08 17:04:21 +08:00
pub fn flatten_clone(&self) -> Self {
2021-06-13 17:41:34 +08:00
match self.0 {
#[cfg(not(feature = "no_closure"))]
#[cfg(not(feature = "sync"))]
2022-02-08 09:25:53 +08:00
Union::Shared(ref cell, ..) => cell.borrow().clone(),
2021-06-13 17:41:34 +08:00
#[cfg(not(feature = "no_closure"))]
#[cfg(feature = "sync")]
2022-02-08 09:25:53 +08:00
Union::Shared(ref cell, ..) => cell.read().unwrap().clone(),
2021-06-13 17:41:34 +08:00
_ => self.clone(),
2020-08-08 16:24:10 +08:00
}
}
2020-11-20 16:52:28 +08:00
/// Flatten the [`Dynamic`].
///
2020-11-20 16:52:28 +08:00
/// If the [`Dynamic`] is not a shared value, it returns itself.
///
2020-12-26 13:05:57 +08:00
/// If the [`Dynamic`] is a shared value, it returns the shared value if there are no
/// outstanding references, or a cloned copy.
#[inline]
2021-06-12 22:47:43 +08:00
#[must_use]
2020-08-08 16:24:10 +08:00
pub fn flatten(self) -> Self {
match self.0 {
2021-06-13 17:41:34 +08:00
#[cfg(not(feature = "no_closure"))]
2022-02-08 09:25:53 +08:00
Union::Shared(cell, ..) => crate::func::native::shared_try_take(cell).map_or_else(
2021-06-13 17:41:34 +08:00
#[cfg(not(feature = "sync"))]
|cell| cell.borrow().clone(),
#[cfg(feature = "sync")]
|cell| cell.read().unwrap().clone(),
#[cfg(not(feature = "sync"))]
|value| value.into_inner(),
#[cfg(feature = "sync")]
|value| value.into_inner().unwrap(),
),
_ => self,
}
}
/// Flatten the [`Dynamic`] in place.
///
/// If the [`Dynamic`] is not a shared value, it does nothing.
///
/// If the [`Dynamic`] is a shared value, it is set to the shared value if there are no
/// outstanding references, or a cloned copy otherwise.
#[inline]
2021-06-12 22:47:43 +08:00
pub(crate) fn flatten_in_place(&mut self) -> &mut Self {
match self.0 {
2021-06-13 17:41:34 +08:00
#[cfg(not(feature = "no_closure"))]
2022-02-08 09:25:53 +08:00
Union::Shared(ref mut cell, ..) => {
2021-12-30 12:19:41 +08:00
let cell = mem::take(cell);
*self = crate::func::native::shared_try_take(cell).map_or_else(
#[cfg(not(feature = "sync"))]
|cell| cell.borrow().clone(),
#[cfg(feature = "sync")]
|cell| cell.read().unwrap().clone(),
#[cfg(not(feature = "sync"))]
|value| value.into_inner(),
#[cfg(feature = "sync")]
|value| value.into_inner().unwrap(),
);
}
_ => (),
}
2021-06-12 22:47:43 +08:00
self
}
2020-11-20 16:52:28 +08:00
/// Is the [`Dynamic`] a shared value that is locked?
2020-08-02 13:33:51 +08:00
///
/// Not available under `no_closure`.
///
2020-08-02 13:33:51 +08:00
/// ## Note
///
2020-11-25 09:36:06 +08:00
/// Under the `sync` feature, shared values use [`RwLock`][std::sync::RwLock] and they are never locked.
2020-11-20 16:52:28 +08:00
/// Access just waits until the [`RwLock`][std::sync::RwLock] is released.
/// So this method always returns [`false`] under [`Sync`].
#[cfg(not(feature = "no_closure"))]
#[inline]
2021-06-12 22:47:43 +08:00
#[must_use]
2020-08-02 13:33:51 +08:00
pub fn is_locked(&self) -> bool {
#[cfg(not(feature = "no_closure"))]
2020-08-02 13:33:51 +08:00
match self.0 {
2022-02-08 09:25:53 +08:00
Union::Shared(ref _cell, ..) => {
2020-08-02 13:33:51 +08:00
#[cfg(not(feature = "sync"))]
return _cell.try_borrow().is_err();
#[cfg(feature = "sync")]
return false;
}
_ => (),
2020-08-02 13:33:51 +08:00
}
false
2020-08-02 13:33:51 +08:00
}
2020-11-20 16:52:28 +08:00
/// Get a reference of a specific type to the [`Dynamic`].
/// Casting to [`Dynamic`] just returns a reference to it.
///
2020-11-20 16:52:28 +08:00
/// Returns [`None`] if the cast fails.
2020-08-03 12:10:20 +08:00
///
2020-08-04 16:27:55 +08:00
/// # Panics or Deadlocks When Value is Shared
2020-08-03 12:10:20 +08:00
///
2020-11-25 09:36:06 +08: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 12:10:20 +08:00
/// Otherwise, this call panics if the data is currently borrowed for write.
#[inline]
2021-06-12 22:47:43 +08:00
#[must_use]
2021-04-19 18:08:29 +08:00
pub fn read_lock<T: Any + Clone>(&self) -> Option<DynamicReadLock<T>> {
match self.0 {
2020-08-03 12:10:20 +08:00
#[cfg(not(feature = "no_closure"))]
2022-02-08 09:25:53 +08:00
Union::Shared(ref cell, ..) => {
#[cfg(not(feature = "sync"))]
2021-03-05 14:18:36 +08:00
let value = cell.borrow();
#[cfg(feature = "sync")]
2021-03-05 14:18:36 +08:00
let value = cell.read().unwrap();
2020-08-03 12:10:20 +08:00
2021-05-22 19:14:24 +08:00
if (*value).type_id() != TypeId::of::<T>()
&& TypeId::of::<Dynamic>() != TypeId::of::<T>()
{
return None;
2020-08-03 12:10:20 +08:00
} else {
return Some(DynamicReadLock(DynamicReadLockInner::Guard(value)));
2020-08-03 12:10:20 +08:00
}
}
_ => (),
}
self.downcast_ref()
2022-01-03 23:11:06 +08:00
.map(DynamicReadLockInner::Reference)
.map(DynamicReadLock)
}
2020-11-20 16:52:28 +08:00
/// Get a mutable reference of a specific type to the [`Dynamic`].
/// Casting to [`Dynamic`] just returns a mutable reference to it.
///
2020-11-20 16:52:28 +08:00
/// Returns [`None`] if the cast fails.
2020-08-03 12:10:20 +08:00
///
2020-08-04 16:27:55 +08:00
/// # Panics or Deadlocks When Value is Shared
2020-08-03 12:10:20 +08:00
///
2020-11-25 09:36:06 +08: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 12:10:20 +08:00
/// Otherwise, this call panics if the data is currently borrowed for write.
#[inline]
2021-06-12 22:47:43 +08:00
#[must_use]
2021-04-19 18:08:29 +08:00
pub fn write_lock<T: Any + Clone>(&mut self) -> Option<DynamicWriteLock<T>> {
match self.0 {
2020-08-03 12:10:20 +08:00
#[cfg(not(feature = "no_closure"))]
2022-02-08 09:25:53 +08:00
Union::Shared(ref cell, ..) => {
2022-01-28 18:59:18 +08:00
let guard = crate::func::native::locked_write(cell);
2020-08-03 12:10:20 +08:00
2022-01-28 18:59:18 +08:00
if (*guard).type_id() != TypeId::of::<T>()
2021-05-22 19:14:24 +08:00
&& TypeId::of::<Dynamic>() != TypeId::of::<T>()
{
return None;
2020-08-03 12:10:20 +08:00
} else {
2022-01-28 18:59:18 +08:00
return Some(DynamicWriteLock(DynamicWriteLockInner::Guard(guard)));
2020-08-03 12:10:20 +08:00
}
}
_ => (),
}
self.downcast_mut()
2022-01-03 23:11:06 +08:00
.map(DynamicWriteLockInner::Reference)
.map(DynamicWriteLock)
}
2020-11-20 16:52:28 +08:00
/// Get a reference of a specific type to the [`Dynamic`].
/// Casting to [`Dynamic`] just returns a reference to it.
///
2020-11-20 16:52:28 +08:00
/// Returns [`None`] if the cast fails, or if the value is shared.
#[inline]
2021-06-12 22:47:43 +08:00
#[must_use]
pub(crate) fn downcast_ref<T: Any + Clone + ?Sized>(&self) -> Option<&T> {
2020-10-08 22:25:50 +08:00
// Coded this way in order to maximally leverage potentials for dead-code removal.
2020-08-14 13:43:26 +08:00
if TypeId::of::<T>() == TypeId::of::<INT>() {
2021-06-13 17:41:34 +08:00
return match self.0 {
2022-02-08 09:25:53 +08:00
Union::Int(ref v, ..) => v.as_any().downcast_ref::<T>(),
2020-07-22 13:05:24 +08:00
_ => None,
};
}
#[cfg(not(feature = "no_float"))]
2021-12-06 20:52:47 +08:00
if TypeId::of::<T>() == TypeId::of::<crate::FLOAT>() {
2021-06-13 17:41:34 +08:00
return match self.0 {
2022-02-08 09:25:53 +08:00
Union::Float(ref v, ..) => v.as_ref().as_any().downcast_ref::<T>(),
2020-07-22 13:05:24 +08:00
_ => None,
};
}
2021-02-13 20:57:56 +08:00
#[cfg(feature = "decimal")]
2021-12-06 20:52:47 +08:00
if TypeId::of::<T>() == TypeId::of::<rust_decimal::Decimal>() {
2021-06-13 17:41:34 +08:00
return match self.0 {
2022-02-08 09:25:53 +08:00
Union::Decimal(ref v, ..) => v.as_ref().as_any().downcast_ref::<T>(),
2021-02-13 20:57:56 +08:00
_ => None,
};
}
2020-08-14 13:43:26 +08:00
if TypeId::of::<T>() == TypeId::of::<bool>() {
2021-06-13 17:41:34 +08:00
return match self.0 {
2022-02-08 09:25:53 +08:00
Union::Bool(ref v, ..) => v.as_any().downcast_ref::<T>(),
2020-07-22 13:05:24 +08:00
_ => None,
};
}
2020-08-14 13:43:26 +08:00
if TypeId::of::<T>() == TypeId::of::<ImmutableString>() {
2021-06-13 17:41:34 +08:00
return match self.0 {
2022-02-08 09:25:53 +08:00
Union::Str(ref v, ..) => v.as_any().downcast_ref::<T>(),
2020-07-22 13:05:24 +08:00
_ => None,
};
}
2020-08-14 13:43:26 +08:00
if TypeId::of::<T>() == TypeId::of::<char>() {
2021-06-13 17:41:34 +08:00
return match self.0 {
2022-02-08 09:25:53 +08:00
Union::Char(ref v, ..) => v.as_any().downcast_ref::<T>(),
2020-07-22 13:05:24 +08:00
_ => None,
};
}
#[cfg(not(feature = "no_index"))]
2021-12-06 20:52:47 +08:00
if TypeId::of::<T>() == TypeId::of::<crate::Array>() {
2021-06-13 17:41:34 +08:00
return match self.0 {
2022-02-08 09:25:53 +08:00
Union::Array(ref v, ..) => v.as_ref().as_any().downcast_ref::<T>(),
2020-07-22 13:05:24 +08:00
_ => None,
};
}
2021-11-23 14:58:54 +08:00
#[cfg(not(feature = "no_index"))]
2021-12-06 20:52:47 +08:00
if TypeId::of::<T>() == TypeId::of::<crate::Blob>() {
2021-11-23 14:58:54 +08:00
return match self.0 {
2022-02-08 09:25:53 +08:00
Union::Blob(ref v, ..) => v.as_ref().as_any().downcast_ref::<T>(),
2021-11-23 14:58:54 +08:00
_ => None,
};
}
2020-07-22 13:05:24 +08:00
#[cfg(not(feature = "no_object"))]
2021-12-06 20:52:47 +08:00
if TypeId::of::<T>() == TypeId::of::<crate::Map>() {
2021-06-13 17:41:34 +08:00
return match self.0 {
2022-02-08 09:25:53 +08:00
Union::Map(ref v, ..) => v.as_ref().as_any().downcast_ref::<T>(),
2020-07-22 13:05:24 +08:00
_ => None,
};
}
2020-08-14 13:43:26 +08:00
if TypeId::of::<T>() == TypeId::of::<FnPtr>() {
2021-06-13 17:41:34 +08:00
return match self.0 {
2022-02-08 09:25:53 +08:00
Union::FnPtr(ref v, ..) => v.as_ref().as_any().downcast_ref::<T>(),
2020-07-22 13:05:24 +08:00
_ => None,
};
}
2020-09-27 22:15:35 +08:00
#[cfg(not(feature = "no_std"))]
if TypeId::of::<T>() == TypeId::of::<Instant>() {
2021-06-13 17:41:34 +08:00
return match self.0 {
2022-02-08 09:25:53 +08:00
Union::TimeStamp(ref v, ..) => v.as_ref().as_any().downcast_ref::<T>(),
2020-09-27 22:15:35 +08:00
_ => None,
};
}
2020-08-14 13:43:26 +08:00
if TypeId::of::<T>() == TypeId::of::<()>() {
2021-06-13 17:41:34 +08:00
return match self.0 {
2022-02-08 09:25:53 +08:00
Union::Unit(ref v, ..) => v.as_any().downcast_ref::<T>(),
2020-07-22 13:05:24 +08:00
_ => None,
};
}
2020-08-14 13:43:26 +08:00
if TypeId::of::<T>() == TypeId::of::<Dynamic>() {
2021-05-25 10:54:48 +08:00
return self.as_any().downcast_ref::<T>();
2020-04-13 23:31:05 +08:00
}
2021-06-13 17:41:34 +08:00
match self.0 {
2022-02-08 09:25:53 +08:00
Union::Variant(ref v, ..) => (***v).as_any().downcast_ref::<T>(),
2020-08-03 12:10:20 +08:00
#[cfg(not(feature = "no_closure"))]
2022-02-08 09:02:15 +08:00
Union::Shared(..) => None,
2020-07-22 13:05:24 +08:00
_ => None,
2020-04-12 23:00:06 +08:00
}
}
2020-11-20 16:52:28 +08:00
/// Get a mutable reference of a specific type to the [`Dynamic`].
/// Casting to [`Dynamic`] just returns a mutable reference to it.
///
2020-11-20 16:52:28 +08:00
/// Returns [`None`] if the cast fails, or if the value is shared.
#[inline]
2021-06-12 22:47:43 +08:00
#[must_use]
2021-04-19 18:08:29 +08:00
pub(crate) fn downcast_mut<T: Any + Clone>(&mut self) -> Option<&mut T> {
2020-10-08 22:25:50 +08:00
// Coded this way in order to maximally leverage potentials for dead-code removal.
2020-08-14 13:43:26 +08:00
if TypeId::of::<T>() == TypeId::of::<INT>() {
2021-06-13 17:41:34 +08:00
return match self.0 {
2022-02-08 09:25:53 +08:00
Union::Int(ref mut v, ..) => v.as_any_mut().downcast_mut::<T>(),
2020-07-22 13:05:24 +08:00
_ => None,
};
}
#[cfg(not(feature = "no_float"))]
2021-12-06 20:52:47 +08:00
if TypeId::of::<T>() == TypeId::of::<crate::FLOAT>() {
2021-06-13 17:41:34 +08:00
return match self.0 {
2022-02-08 09:25:53 +08:00
Union::Float(ref mut v, ..) => v.as_mut().as_any_mut().downcast_mut::<T>(),
2020-07-22 13:05:24 +08:00
_ => None,
};
}
2021-02-13 20:57:56 +08:00
#[cfg(feature = "decimal")]
2021-12-06 20:52:47 +08:00
if TypeId::of::<T>() == TypeId::of::<rust_decimal::Decimal>() {
2021-06-13 17:41:34 +08:00
return match self.0 {
2022-02-08 09:25:53 +08:00
Union::Decimal(ref mut v, ..) => v.as_mut().as_any_mut().downcast_mut::<T>(),
2021-02-13 20:57:56 +08:00
_ => None,
};
}
2020-08-14 13:43:26 +08:00
if TypeId::of::<T>() == TypeId::of::<bool>() {
2021-06-13 17:41:34 +08:00
return match self.0 {
2022-02-08 09:25:53 +08:00
Union::Bool(ref mut v, ..) => v.as_any_mut().downcast_mut::<T>(),
2020-07-22 13:05:24 +08:00
_ => None,
};
}
2020-08-14 13:43:26 +08:00
if TypeId::of::<T>() == TypeId::of::<ImmutableString>() {
2021-06-13 17:41:34 +08:00
return match self.0 {
2022-02-08 09:25:53 +08:00
Union::Str(ref mut v, ..) => v.as_any_mut().downcast_mut::<T>(),
2020-07-22 13:05:24 +08:00
_ => None,
};
}
2020-08-14 13:43:26 +08:00
if TypeId::of::<T>() == TypeId::of::<char>() {
2021-06-13 17:41:34 +08:00
return match self.0 {
2022-02-08 09:25:53 +08:00
Union::Char(ref mut v, ..) => v.as_any_mut().downcast_mut::<T>(),
2020-07-22 13:05:24 +08:00
_ => None,
};
}
#[cfg(not(feature = "no_index"))]
2021-12-06 20:52:47 +08:00
if TypeId::of::<T>() == TypeId::of::<crate::Array>() {
2021-06-13 17:41:34 +08:00
return match self.0 {
2022-02-08 09:25:53 +08:00
Union::Array(ref mut v, ..) => v.as_mut().as_any_mut().downcast_mut::<T>(),
2020-07-22 13:05:24 +08:00
_ => None,
};
}
2021-11-23 14:58:54 +08:00
#[cfg(not(feature = "no_index"))]
2021-12-06 20:52:47 +08:00
if TypeId::of::<T>() == TypeId::of::<crate::Blob>() {
2021-11-23 14:58:54 +08:00
return match self.0 {
2022-02-08 09:25:53 +08:00
Union::Blob(ref mut v, ..) => v.as_mut().as_any_mut().downcast_mut::<T>(),
2021-11-23 14:58:54 +08:00
_ => None,
};
}
2020-07-22 13:05:24 +08:00
#[cfg(not(feature = "no_object"))]
2021-12-06 20:52:47 +08:00
if TypeId::of::<T>() == TypeId::of::<crate::Map>() {
2021-06-13 17:41:34 +08:00
return match self.0 {
2022-02-08 09:25:53 +08:00
Union::Map(ref mut v, ..) => v.as_mut().as_any_mut().downcast_mut::<T>(),
2020-07-22 13:05:24 +08:00
_ => None,
};
}
2020-08-14 13:43:26 +08:00
if TypeId::of::<T>() == TypeId::of::<FnPtr>() {
2021-06-13 17:41:34 +08:00
return match self.0 {
2022-02-08 09:25:53 +08:00
Union::FnPtr(ref mut v, ..) => v.as_mut().as_any_mut().downcast_mut::<T>(),
2020-07-22 13:05:24 +08:00
_ => None,
};
}
2020-09-27 22:15:35 +08:00
#[cfg(not(feature = "no_std"))]
if TypeId::of::<T>() == TypeId::of::<Instant>() {
2021-06-13 17:41:34 +08:00
return match self.0 {
2022-02-08 09:25:53 +08:00
Union::TimeStamp(ref mut v, ..) => v.as_mut().as_any_mut().downcast_mut::<T>(),
2020-09-27 22:15:35 +08:00
_ => None,
};
}
2020-08-14 13:43:26 +08:00
if TypeId::of::<T>() == TypeId::of::<()>() {
2021-06-13 17:41:34 +08:00
return match self.0 {
2022-02-08 09:25:53 +08:00
Union::Unit(ref mut v, ..) => v.as_any_mut().downcast_mut::<T>(),
2020-07-22 13:05:24 +08:00
_ => None,
};
}
2020-08-14 13:43:26 +08:00
if TypeId::of::<T>() == TypeId::of::<Dynamic>() {
2022-01-03 23:11:06 +08:00
return self.as_any_mut().downcast_mut::<T>();
2020-04-13 23:31:05 +08:00
}
2021-06-13 17:41:34 +08:00
match self.0 {
2022-02-08 09:25:53 +08:00
Union::Variant(ref mut v, ..) => (***v).as_any_mut().downcast_mut::<T>(),
2020-08-03 12:10:20 +08:00
#[cfg(not(feature = "no_closure"))]
2022-02-08 09:02:15 +08:00
Union::Shared(..) => None,
2020-07-22 13:05:24 +08:00
_ => None,
2020-04-12 23:00:06 +08:00
}
}
2021-11-23 12:45:59 +08:00
/// Cast the [`Dynamic`] as a unit `()`.
2021-03-05 13:34:58 +08:00
/// Returns the name of the actual type if the cast fails.
#[inline]
2021-03-05 13:34:58 +08:00
pub fn as_unit(&self) -> Result<(), &'static str> {
match self.0 {
2022-02-08 09:25:53 +08:00
Union::Unit(v, ..) => Ok(v),
2021-03-05 13:34:58 +08:00
#[cfg(not(feature = "no_closure"))]
2022-02-08 09:02:15 +08:00
Union::Shared(..) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()),
2021-03-05 13:34:58 +08:00
_ => Err(self.type_name()),
}
}
2021-11-23 12:45:59 +08:00
/// Cast the [`Dynamic`] as the system integer type [`INT`].
2020-04-12 23:00:06 +08:00
/// Returns the name of the actual type if the cast fails.
#[inline]
pub fn as_int(&self) -> Result<INT, &'static str> {
2020-04-12 23:00:06 +08:00
match self.0 {
2022-02-08 09:25:53 +08:00
Union::Int(n, ..) => Ok(n),
2020-08-03 12:10:20 +08:00
#[cfg(not(feature = "no_closure"))]
2022-02-08 09:02:15 +08:00
Union::Shared(..) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()),
2020-04-12 23:00:06 +08:00
_ => Err(self.type_name()),
}
}
2021-12-06 20:52:47 +08:00
/// Cast the [`Dynamic`] as the system floating-point type [`FLOAT`][crate::FLOAT].
2020-05-22 21:49:53 +08:00
/// Returns the name of the actual type if the cast fails.
2021-02-13 20:57:56 +08:00
///
/// Not available under `no_float`.
2020-05-22 21:49:53 +08:00
#[cfg(not(feature = "no_float"))]
#[inline]
2021-12-06 20:52:47 +08:00
pub fn as_float(&self) -> Result<crate::FLOAT, &'static str> {
2020-05-22 21:49:53 +08:00
match self.0 {
2022-02-08 09:25:53 +08:00
Union::Float(n, ..) => Ok(*n),
2020-08-03 12:10:20 +08:00
#[cfg(not(feature = "no_closure"))]
2022-02-08 09:02:15 +08:00
Union::Shared(..) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()),
2020-05-22 21:49:53 +08:00
_ => Err(self.type_name()),
}
}
2021-12-06 20:52:47 +08:00
/// _(decimal)_ Cast the [`Dynamic`] as a [`Decimal`][rust_decimal::Decimal].
2021-02-13 20:57:56 +08:00
/// Returns the name of the actual type if the cast fails.
///
2021-02-21 14:26:31 +08:00
/// Exported under the `decimal` feature only.
2021-02-13 20:57:56 +08:00
#[cfg(feature = "decimal")]
#[inline]
2021-12-06 20:52:47 +08:00
pub fn as_decimal(&self) -> Result<rust_decimal::Decimal, &'static str> {
2021-05-25 10:54:48 +08:00
match self.0 {
2022-02-08 09:25:53 +08:00
Union::Decimal(ref n, ..) => Ok(**n),
2021-02-13 20:57:56 +08:00
#[cfg(not(feature = "no_closure"))]
2022-02-08 09:02:15 +08:00
Union::Shared(..) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()),
2021-02-13 20:57:56 +08:00
_ => Err(self.type_name()),
}
}
2021-11-23 12:45:59 +08:00
/// Cast the [`Dynamic`] as a [`bool`].
2020-04-12 23:00:06 +08:00
/// Returns the name of the actual type if the cast fails.
#[inline]
pub fn as_bool(&self) -> Result<bool, &'static str> {
2020-04-12 23:00:06 +08:00
match self.0 {
2022-02-08 09:25:53 +08:00
Union::Bool(b, ..) => Ok(b),
2020-08-03 12:10:20 +08:00
#[cfg(not(feature = "no_closure"))]
2022-02-08 09:02:15 +08:00
Union::Shared(..) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()),
2020-04-12 23:00:06 +08:00
_ => Err(self.type_name()),
}
}
2021-11-23 12:45:59 +08:00
/// Cast the [`Dynamic`] as a [`char`].
2020-04-12 23:00:06 +08:00
/// Returns the name of the actual type if the cast fails.
#[inline]
pub fn as_char(&self) -> Result<char, &'static str> {
2020-04-12 23:00:06 +08:00
match self.0 {
2022-02-08 09:25:53 +08:00
Union::Char(n, ..) => Ok(n),
2020-08-03 12:10:20 +08:00
#[cfg(not(feature = "no_closure"))]
2022-02-08 09:02:15 +08:00
Union::Shared(..) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()),
2020-04-12 23:00:06 +08:00
_ => Err(self.type_name()),
}
}
2021-11-23 12:45:59 +08:00
/// Cast the [`Dynamic`] as a string slice.
2020-04-12 23:00:06 +08:00
/// Returns the name of the actual type if the cast fails.
///
2021-03-05 23:00:27 +08:00
/// # Panics
///
/// Panics if the value is shared.
#[inline]
pub(crate) fn as_str_ref(&self) -> Result<&str, &'static str> {
2021-05-25 10:54:48 +08:00
match self.0 {
2022-02-08 09:25:53 +08:00
Union::Str(ref s, ..) => Ok(s),
2021-03-05 23:00:27 +08:00
#[cfg(not(feature = "no_closure"))]
2022-02-08 09:02:15 +08:00
Union::Shared(..) => panic!("as_str_ref() cannot be called on shared values"),
2020-04-12 23:00:06 +08:00
_ => Err(self.type_name()),
}
}
2021-11-23 12:45:59 +08:00
/// Convert the [`Dynamic`] into a [`String`].
/// If there are other references to the same string, a cloned copy is returned.
2020-04-12 23:00:06 +08:00
/// Returns the name of the actual type if the cast fails.
#[inline]
pub fn into_string(self) -> Result<String, &'static str> {
self.into_immutable_string()
.map(ImmutableString::into_owned)
}
2021-11-23 12:45:59 +08:00
/// Convert the [`Dynamic`] into an [`ImmutableString`].
/// Returns the name of the actual type if the cast fails.
#[inline]
pub fn into_immutable_string(self) -> Result<ImmutableString, &'static str> {
2020-04-12 23:00:06 +08:00
match self.0 {
2022-02-08 09:25:53 +08:00
Union::Str(s, ..) => Ok(s),
2020-08-03 12:10:20 +08:00
#[cfg(not(feature = "no_closure"))]
2022-02-08 09:25:53 +08:00
Union::Shared(cell, ..) => {
#[cfg(not(feature = "sync"))]
2021-03-05 14:18:36 +08:00
let value = cell.borrow();
#[cfg(feature = "sync")]
2021-03-05 14:18:36 +08:00
let value = cell.read().unwrap();
2021-06-13 17:41:34 +08:00
match value.0 {
2022-02-08 09:25:53 +08:00
Union::Str(ref s, ..) => Ok(s.clone()),
2021-03-05 14:18:36 +08:00
_ => Err((*value).type_name()),
}
}
2020-06-25 18:07:57 +08:00
_ => Err(self.type_name()),
}
}
2021-12-06 20:52:47 +08:00
/// Convert the [`Dynamic`] into an [`Array`][crate::Array].
2021-11-23 12:45:59 +08:00
/// Returns the name of the actual type if the cast fails.
2021-12-18 12:28:56 +08:00
#[cfg(not(feature = "no_index"))]
2021-11-23 12:45:59 +08:00
#[inline(always)]
2021-12-06 20:52:47 +08:00
pub fn into_array(self) -> Result<crate::Array, &'static str> {
2021-11-23 12:45:59 +08:00
match self.0 {
2022-02-08 09:25:53 +08:00
Union::Array(a, ..) => Ok(*a),
2021-11-23 12:45:59 +08:00
#[cfg(not(feature = "no_closure"))]
2022-02-08 09:25:53 +08:00
Union::Shared(cell, ..) => {
2021-11-23 12:45:59 +08:00
#[cfg(not(feature = "sync"))]
let value = cell.borrow();
#[cfg(feature = "sync")]
let value = cell.read().unwrap();
match value.0 {
2022-02-08 09:25:53 +08:00
Union::Array(ref a, ..) => Ok(a.as_ref().clone()),
2021-11-23 12:45:59 +08:00
_ => Err((*value).type_name()),
}
}
_ => Err(self.type_name()),
}
}
/// Convert the [`Dynamic`] into a [`Vec`].
/// Returns the name of the actual type if any cast fails.
2021-12-18 18:44:08 +08:00
#[cfg(not(feature = "no_index"))]
2021-11-23 12:45:59 +08:00
#[inline(always)]
pub fn into_typed_array<T: Variant + Clone>(self) -> Result<Vec<T>, &'static str> {
match self.0 {
2022-02-08 09:25:53 +08:00
Union::Array(a, ..) => a
2021-11-23 12:45:59 +08:00
.into_iter()
.map(|v| {
#[cfg(not(feature = "no_closure"))]
let typ = if v.is_shared() {
// Avoid panics/deadlocks with shared values
"<shared>"
} else {
v.type_name()
};
#[cfg(feature = "no_closure")]
let typ = v.type_name();
v.try_cast::<T>().ok_or_else(|| typ)
})
.collect(),
2022-02-08 09:02:15 +08:00
Union::Blob(..) if TypeId::of::<T>() == TypeId::of::<u8>() => Ok(self.cast::<Vec<T>>()),
2021-11-23 12:45:59 +08:00
#[cfg(not(feature = "no_closure"))]
2022-02-08 09:25:53 +08:00
Union::Shared(cell, ..) => {
2021-11-23 12:45:59 +08:00
#[cfg(not(feature = "sync"))]
let value = cell.borrow();
#[cfg(feature = "sync")]
let value = cell.read().unwrap();
match value.0 {
2022-02-08 09:25:53 +08:00
Union::Array(ref a, ..) => {
2021-11-23 12:45:59 +08:00
a.iter()
.map(|v| {
#[cfg(not(feature = "no_closure"))]
let typ = if v.is_shared() {
// Avoid panics/deadlocks with shared values
"<shared>"
} else {
v.type_name()
};
#[cfg(feature = "no_closure")]
let typ = v.type_name();
v.read_lock::<T>().ok_or_else(|| typ).map(|v| v.clone())
})
.collect()
}
2022-02-08 09:02:15 +08:00
Union::Blob(..) if TypeId::of::<T>() == TypeId::of::<u8>() => {
2021-12-18 18:44:08 +08:00
Ok((*value).clone().cast::<Vec<T>>())
}
2021-11-23 12:45:59 +08:00
_ => Err((*value).type_name()),
}
}
_ => Err(self.type_name()),
}
2021-11-23 14:58:54 +08:00
}
2021-12-18 12:28:56 +08:00
/// Convert the [`Dynamic`] into a [`Blob`][crate::Blob].
2021-11-23 14:58:54 +08:00
/// Returns the name of the actual type if the cast fails.
2021-12-18 12:28:56 +08:00
#[cfg(not(feature = "no_index"))]
2021-11-23 14:58:54 +08:00
#[inline(always)]
2021-12-06 20:52:47 +08:00
pub fn into_blob(self) -> Result<crate::Blob, &'static str> {
2021-11-23 14:58:54 +08:00
match self.0 {
2022-02-08 09:25:53 +08:00
Union::Blob(a, ..) => Ok(*a),
2021-11-23 14:58:54 +08:00
#[cfg(not(feature = "no_closure"))]
2022-02-08 09:25:53 +08:00
Union::Shared(cell, ..) => {
2021-11-23 14:58:54 +08:00
#[cfg(not(feature = "sync"))]
let value = cell.borrow();
#[cfg(feature = "sync")]
let value = cell.read().unwrap();
match value.0 {
2022-02-08 09:25:53 +08:00
Union::Blob(ref a, ..) => Ok(a.as_ref().clone()),
2021-11-23 14:58:54 +08:00
_ => Err((*value).type_name()),
}
}
_ => Err(self.type_name()),
}
2021-11-23 12:45:59 +08:00
}
}
2021-12-18 12:28:56 +08:00
impl From<()> for Dynamic {
#[inline(always)]
2021-12-18 12:28:56 +08:00
fn from(value: ()) -> Self {
Self(Union::Unit(value, DEFAULT_TAG_VALUE, ReadWrite))
}
}
impl From<bool> for Dynamic {
#[inline(always)]
fn from(value: bool) -> Self {
Self(Union::Bool(value, DEFAULT_TAG_VALUE, ReadWrite))
}
}
impl From<INT> for Dynamic {
#[inline(always)]
fn from(value: INT) -> Self {
Self(Union::Int(value, DEFAULT_TAG_VALUE, ReadWrite))
}
}
#[cfg(not(feature = "no_float"))]
impl From<crate::FLOAT> for Dynamic {
#[inline(always)]
fn from(value: crate::FLOAT) -> Self {
Self(Union::Float(value.into(), DEFAULT_TAG_VALUE, ReadWrite))
}
}
#[cfg(not(feature = "no_float"))]
impl From<crate::ast::FloatWrapper<crate::FLOAT>> for Dynamic {
#[inline(always)]
fn from(value: crate::ast::FloatWrapper<crate::FLOAT>) -> Self {
Self(Union::Float(value, DEFAULT_TAG_VALUE, ReadWrite))
}
}
#[cfg(feature = "decimal")]
impl From<rust_decimal::Decimal> for Dynamic {
#[inline(always)]
fn from(value: rust_decimal::Decimal) -> Self {
Self(Union::Decimal(value.into(), DEFAULT_TAG_VALUE, ReadWrite))
}
}
impl From<char> for Dynamic {
#[inline(always)]
fn from(value: char) -> Self {
Self(Union::Char(value, DEFAULT_TAG_VALUE, ReadWrite))
}
}
impl<S: Into<ImmutableString>> From<S> for Dynamic {
#[inline(always)]
fn from(value: S) -> Self {
Self(Union::Str(value.into(), DEFAULT_TAG_VALUE, ReadWrite))
}
}
impl From<&ImmutableString> for Dynamic {
#[inline(always)]
fn from(value: &ImmutableString) -> Self {
value.clone().into()
}
}
impl FromStr for Dynamic {
type Err = ();
fn from_str(value: &str) -> Result<Self, Self::Err> {
Ok(Self(Union::Str(value.into(), DEFAULT_TAG_VALUE, ReadWrite)))
}
}
#[cfg(not(feature = "no_index"))]
impl<T: Variant + Clone> From<Vec<T>> for Dynamic {
#[inline]
fn from(value: Vec<T>) -> Self {
Self(Union::Array(
Box::new(value.into_iter().map(Dynamic::from).collect()),
DEFAULT_TAG_VALUE,
ReadWrite,
))
}
}
#[cfg(not(feature = "no_index"))]
impl<T: Variant + Clone> From<&[T]> for Dynamic {
#[inline]
fn from(value: &[T]) -> Self {
Self(Union::Array(
Box::new(value.iter().cloned().map(Dynamic::from).collect()),
DEFAULT_TAG_VALUE,
ReadWrite,
))
}
}
#[cfg(not(feature = "no_index"))]
impl<T: Variant + Clone> std::iter::FromIterator<T> for Dynamic {
#[inline]
fn from_iter<X: IntoIterator<Item = T>>(iter: X) -> Self {
Self(Union::Array(
Box::new(iter.into_iter().map(Dynamic::from).collect()),
DEFAULT_TAG_VALUE,
ReadWrite,
))
}
}
#[cfg(not(feature = "no_object"))]
2021-03-23 12:13:53 +08:00
#[cfg(not(feature = "no_std"))]
2021-04-17 15:15:54 +08:00
impl<K: Into<crate::Identifier>, T: Variant + Clone> From<std::collections::HashMap<K, T>>
2020-11-16 16:28:04 +08:00
for Dynamic
{
#[inline]
2021-04-17 15:15:54 +08:00
fn from(value: std::collections::HashMap<K, T>) -> Self {
2020-12-08 22:47:38 +08:00
Self(Union::Map(
Box::new(
value
.into_iter()
.map(|(k, v)| (k.into(), Dynamic::from(v)))
.collect(),
),
2021-06-28 18:06:05 +08:00
DEFAULT_TAG_VALUE,
2021-05-29 18:33:29 +08:00
ReadWrite,
2020-12-08 22:47:38 +08:00
))
}
}
2021-03-23 12:13:53 +08:00
#[cfg(not(feature = "no_object"))]
#[cfg(not(feature = "no_std"))]
impl<K: Into<crate::Identifier>> From<std::collections::HashSet<K>> for Dynamic {
#[inline]
fn from(value: std::collections::HashSet<K>) -> Self {
Self(Union::Map(
Box::new(
value
.into_iter()
.map(|k| (k.into(), Dynamic::UNIT))
.collect(),
),
DEFAULT_TAG_VALUE,
ReadWrite,
))
}
}
#[cfg(not(feature = "no_object"))]
2021-04-17 15:15:54 +08:00
impl<K: Into<crate::Identifier>, T: Variant + Clone> From<std::collections::BTreeMap<K, T>>
for Dynamic
2021-03-23 12:13:53 +08:00
{
#[inline]
2021-04-17 15:15:54 +08:00
fn from(value: std::collections::BTreeMap<K, T>) -> Self {
2021-03-23 12:13:53 +08:00
Self(Union::Map(
Box::new(
value
.into_iter()
.map(|(k, v)| (k.into(), Dynamic::from(v)))
.collect(),
),
2021-06-28 18:06:05 +08:00
DEFAULT_TAG_VALUE,
2021-05-29 18:33:29 +08:00
ReadWrite,
2021-03-23 12:13:53 +08:00
))
}
}
#[cfg(not(feature = "no_object"))]
impl<K: Into<crate::Identifier>> From<std::collections::BTreeSet<K>> for Dynamic {
#[inline]
fn from(value: std::collections::BTreeSet<K>) -> Self {
Self(Union::Map(
Box::new(
value
.into_iter()
.map(|k| (k.into(), Dynamic::UNIT))
.collect(),
),
DEFAULT_TAG_VALUE,
ReadWrite,
))
}
}
2020-06-25 18:07:57 +08:00
impl From<FnPtr> for Dynamic {
2020-08-08 11:46:30 +08:00
#[inline(always)]
2020-06-25 18:07:57 +08:00
fn from(value: FnPtr) -> Self {
2021-06-29 18:25:20 +08:00
Self(Union::FnPtr(value.into(), DEFAULT_TAG_VALUE, ReadWrite))
2020-07-22 23:12:09 +08:00
}
}
2020-09-27 18:47:20 +08:00
#[cfg(not(feature = "no_std"))]
2020-09-26 19:41:04 +08:00
impl From<Instant> for Dynamic {
#[inline(always)]
fn from(value: Instant) -> Self {
2021-06-29 18:25:20 +08:00
Self(Union::TimeStamp(value.into(), DEFAULT_TAG_VALUE, ReadWrite))
2020-09-26 19:41:04 +08:00
}
}
2021-05-11 21:38:07 +08:00
#[cfg(not(feature = "no_closure"))]
impl From<crate::Shared<crate::Locked<Dynamic>>> for Dynamic {
#[inline(always)]
fn from(value: crate::Shared<crate::Locked<Self>>) -> Self {
2021-07-24 14:11:16 +08:00
Self(Union::Shared(value, DEFAULT_TAG_VALUE, ReadWrite))
2021-05-11 21:38:07 +08:00
}
}
2021-12-15 12:06:17 +08:00
impl From<ExclusiveRange> for Dynamic {
#[inline(always)]
fn from(value: ExclusiveRange) -> Self {
Dynamic::from(value)
}
}
impl From<InclusiveRange> for Dynamic {
#[inline(always)]
fn from(value: InclusiveRange) -> Self {
Dynamic::from(value)
}
}