rhai/src/any.rs

644 lines
22 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.
#[cfg(not(feature = "no_module"))]
use crate::module::Module;
2020-04-12 17:00:06 +02:00
use crate::parser::INT;
#[cfg(not(feature = "no_float"))]
use crate::parser::FLOAT;
#[cfg(not(feature = "no_index"))]
use crate::engine::Array;
#[cfg(not(feature = "no_object"))]
use crate::engine::Map;
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,
collections::HashMap,
fmt, mem, ptr,
string::String,
2020-04-24 06:39:24 +02:00
vec::Vec,
2020-03-10 03:07:44 +01:00
};
2017-12-20 12:16:14 +01:00
#[cfg(not(feature = "no_std"))]
use crate::stdlib::time::Instant;
2020-04-12 17:00:06 +02:00
/// A 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 {
/// 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-03-18 03:36:50 +01:00
/// This trait may only be implemented by `rhai`.
2017-12-20 12:16:14 +01:00
#[doc(hidden)]
fn _closed(&self) -> _Private;
}
2020-04-12 17:00:06 +02:00
#[cfg(not(feature = "sync"))]
impl<T: Any + Clone> Variant for T {
fn as_any(&self) -> &dyn Any {
self as &dyn Any
}
fn as_mut_any(&mut self) -> &mut dyn Any {
self as &mut dyn Any
}
fn as_box_any(self: Box<Self>) -> Box<dyn Any> {
self as Box<dyn Any>
}
fn type_name(&self) -> &'static str {
type_name::<T>()
}
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())
}
fn _closed(&self) -> _Private {
_Private
}
}
2020-04-12 17:00:06 +02:00
/// A 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 {
/// 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.
fn as_box_any(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;
/// This trait may only be implemented by `rhai`.
#[doc(hidden)]
fn _closed(&self) -> _Private;
}
2020-04-12 17:00:06 +02:00
#[cfg(feature = "sync")]
impl<T: Any + Clone + Send + Sync> Variant for T {
fn as_any(&self) -> &dyn Any {
self as &dyn Any
}
fn as_mut_any(&mut self) -> &mut dyn Any {
self as &mut dyn Any
2017-12-20 12:16:14 +01:00
}
fn as_box_any(self: Box<Self>) -> Box<dyn Any> {
self as Box<dyn Any>
}
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
fn _closed(&self) -> _Private {
_Private
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?
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
}
/// A dynamic type containing any value.
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),
Str(Box<String>),
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>),
#[cfg(not(feature = "no_module"))]
2020-05-05 04:39:12 +02:00
Module(Box<Module>),
Variant(Box<Box<dyn Variant>>),
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?
pub fn is_variant(&self) -> bool {
match self.0 {
Union::Variant(_) => true,
_ => false,
}
}
2020-04-12 17:00:06 +02:00
/// Is the value held by this `Dynamic` a particular type?
pub fn is<T: Variant + Clone>(&self) -> bool {
self.type_id() == TypeId::of::<T>()
}
/// Get the TypeId of the value held by this `Dynamic`.
pub fn type_id(&self) -> TypeId {
match &self.0 {
Union::Unit(_) => TypeId::of::<()>(),
Union::Bool(_) => TypeId::of::<bool>(),
Union::Str(_) => TypeId::of::<String>(),
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>(),
#[cfg(not(feature = "no_module"))]
2020-05-05 04:39:12 +02:00
Union::Module(_) => TypeId::of::<Module>(),
Union::Variant(value) => (***value).type_id(),
2020-04-12 17:00:06 +02:00
}
}
/// Get the name of the type of the value held by this `Dynamic`.
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",
#[cfg(not(feature = "no_module"))]
2020-05-05 04:39:12 +02:00
Union::Module(_) => "sub-scope",
2020-04-12 17:00:06 +02:00
#[cfg(not(feature = "no_std"))]
2020-04-12 17:00:06 +02:00
Union::Variant(value) if value.is::<Instant>() => "timestamp",
Union::Variant(value) => (***value).type_name(),
2017-12-20 12:16:14 +01:00
}
}
}
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, ""),
Union::Bool(value) => write!(f, "{}", value),
Union::Str(value) => write!(f, "{}", value),
Union::Char(value) => write!(f, "{}", value),
Union::Int(value) => write!(f, "{}", value),
#[cfg(not(feature = "no_float"))]
Union::Float(value) => write!(f, "{}", value),
#[cfg(not(feature = "no_index"))]
2020-04-12 17:00:06 +02:00
Union::Array(value) => write!(f, "{:?}", value),
#[cfg(not(feature = "no_object"))]
2020-04-26 12:04:07 +02:00
Union::Map(value) => write!(f, "#{:?}", value),
#[cfg(not(feature = "no_module"))]
2020-05-05 09:00:10 +02:00
Union::Module(value) => write!(f, "{:?}", value),
2020-05-05 14:54:56 +02:00
#[cfg(not(feature = "no_std"))]
Union::Variant(value) if value.is::<Instant>() => write!(f, "<timestamp>"),
2020-04-12 17:00:06 +02:00
Union::Variant(_) => write!(f, "?"),
}
}
}
impl fmt::Debug for Dynamic {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.0 {
Union::Unit(value) => write!(f, "{:?}", value),
Union::Bool(value) => write!(f, "{:?}", value),
Union::Str(value) => write!(f, "{:?}", value),
Union::Char(value) => write!(f, "{:?}", value),
Union::Int(value) => write!(f, "{:?}", value),
#[cfg(not(feature = "no_float"))]
Union::Float(value) => write!(f, "{:?}", value),
#[cfg(not(feature = "no_index"))]
2020-04-12 17:00:06 +02:00
Union::Array(value) => write!(f, "{:?}", value),
#[cfg(not(feature = "no_object"))]
2020-04-26 12:04:07 +02:00
Union::Map(value) => write!(f, "#{:?}", value),
#[cfg(not(feature = "no_module"))]
2020-05-05 09:00:10 +02:00
Union::Module(value) => write!(f, "{:?}", value),
2020-05-05 14:54:56 +02:00
#[cfg(not(feature = "no_std"))]
Union::Variant(value) if value.is::<Instant>() => write!(f, "<timestamp>"),
2020-04-13 04:27:08 +02:00
Union::Variant(_) => write!(f, "<dynamic>"),
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())),
#[cfg(not(feature = "no_module"))]
2020-05-05 04:39:12 +02:00
Union::Module(ref value) => Self(Union::Module(value.clone())),
2020-05-03 16:17:28 +02:00
Union::Variant(ref value) => (***value).clone_into_dynamic(),
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 {
fn default() -> Self {
Self(Union::Unit(()))
}
}
/// Cast a type into another type.
fn try_cast<A: Any, B: Any>(a: A) -> Option<B> {
if TypeId::of::<B>() == a.type_id() {
// SAFETY: Just checked we have the right type. We explicitly forget the
// value immediately after moving out, removing any chance of a destructor
// running or value otherwise being used again.
unsafe {
let ret: B = ptr::read(&a as *const _ as *const B);
mem::forget(a);
Some(ret)
}
} else {
None
}
}
2020-04-13 04:27:08 +02:00
/// Cast a Boxed type into another type.
fn cast_box<X: Variant, T: Variant>(item: Box<X>) -> Result<Box<T>, Box<X>> {
2020-04-13 04:27:08 +02:00
// Only allow casting to the exact same type
if TypeId::of::<X>() == TypeId::of::<T>() {
// SAFETY: just checked whether we are pointing to the correct type
unsafe {
let raw: *mut dyn Any = Box::into_raw(item as Box<dyn Any>);
Ok(Box::from_raw(raw as *mut T))
2020-04-13 04:27:08 +02:00
}
} else {
// Return the consumed item for chaining.
Err(item)
}
}
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");
///
/// let result = Dynamic::from("hello".to_string());
/// 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
/// ```
pub fn from<T: Variant + Clone>(value: T) -> Self {
2020-05-03 16:17:28 +02:00
let dyn_value = &value as &dyn Any;
2020-04-13 17:31:05 +02:00
if let Some(result) = dyn_value.downcast_ref::<()>().cloned().map(Union::Unit) {
return Self(result);
} else if let Some(result) = dyn_value.downcast_ref::<bool>().cloned().map(Union::Bool) {
return Self(result);
} else if let Some(result) = dyn_value.downcast_ref::<INT>().cloned().map(Union::Int) {
return Self(result);
} else if let Some(result) = dyn_value.downcast_ref::<char>().cloned().map(Union::Char) {
2020-04-12 17:00:06 +02:00
return Self(result);
}
2020-03-04 15:00:01 +01:00
2020-04-12 17:00:06 +02:00
#[cfg(not(feature = "no_float"))]
{
2020-04-13 17:31:05 +02:00
if let Some(result) = dyn_value.downcast_ref::<FLOAT>().cloned().map(Union::Float) {
2020-04-12 17:00:06 +02:00
return Self(result);
}
}
let mut var = Box::new(value);
var = match cast_box::<_, Dynamic>(var) {
Ok(d) => return *d,
Err(var) => var,
};
var = match cast_box::<_, String>(var) {
Ok(s) => return Self(Union::Str(s)),
Err(var) => var,
};
#[cfg(not(feature = "no_index"))]
{
var = match cast_box::<_, Array>(var) {
Ok(array) => return Self(Union::Array(array)),
Err(var) => var,
};
}
#[cfg(not(feature = "no_object"))]
{
var = match cast_box::<_, Map>(var) {
Ok(map) => return Self(Union::Map(map)),
Err(var) => var,
}
}
Self(Union::Variant(Box::new(var)))
2020-04-12 17:00:06 +02:00
}
2017-12-20 12:16:14 +01:00
2020-03-04 15:00:01 +01:00
/// Get a copy of the `Dynamic` value as a specific type.
2020-04-13 04:27:08 +02:00
/// Casting to a `Dynamic` just returns as is.
2020-03-04 15:00:01 +01:00
///
2020-04-12 17:00:06 +02:00
/// Returns an error with the name of the value's actual type when the cast fails.
///
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
/// ```
pub fn try_cast<T: Variant>(self) -> Option<T> {
2020-04-13 04:27:08 +02:00
if TypeId::of::<T>() == TypeId::of::<Dynamic>() {
return cast_box::<_, T>(Box::new(self)).ok().map(|v| *v);
2020-04-13 04:27:08 +02:00
}
2020-04-30 16:52:36 +02:00
match self.0 {
Union::Unit(value) => try_cast(value),
Union::Bool(value) => try_cast(value),
Union::Str(value) => cast_box::<_, T>(value).ok().map(|v| *v),
Union::Char(value) => try_cast(value),
Union::Int(value) => try_cast(value),
2020-04-12 17:00:06 +02:00
#[cfg(not(feature = "no_float"))]
Union::Float(value) => try_cast(value),
#[cfg(not(feature = "no_index"))]
Union::Array(value) => cast_box::<_, T>(value).ok().map(|v| *v),
#[cfg(not(feature = "no_object"))]
Union::Map(value) => cast_box::<_, T>(value).ok().map(|v| *v),
#[cfg(not(feature = "no_module"))]
Union::Module(value) => cast_box::<_, T>(value).ok().map(|v| *v),
Union::Variant(value) => (*value).as_box_any().downcast().map(|x| *x).ok(),
2017-12-20 12:16:14 +01:00
}
}
2020-03-04 15:00:01 +01:00
/// Get a copy of the `Dynamic` value as a specific type.
2020-04-13 17:31:05 +02:00
/// Casting to a `Dynamic` just returns as is.
///
/// # Panics
///
/// Panics if the cast fails (e.g. the type of the actual value is not the same as the specified type).
///
/// # 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-04-12 17:00:06 +02:00
pub fn cast<T: Variant + Clone>(self) -> T {
//self.try_cast::<T>().unwrap()
if TypeId::of::<T>() == TypeId::of::<Dynamic>() {
return *cast_box::<_, T>(Box::new(self)).unwrap();
}
match self.0 {
Union::Unit(value) => try_cast(value).unwrap(),
Union::Bool(value) => try_cast(value).unwrap(),
Union::Str(value) => *cast_box::<_, T>(value).unwrap(),
Union::Char(value) => try_cast(value).unwrap(),
Union::Int(value) => try_cast(value).unwrap(),
#[cfg(not(feature = "no_float"))]
Union::Float(value) => try_cast(value).unwrap(),
#[cfg(not(feature = "no_index"))]
Union::Array(value) => *cast_box::<_, T>(value).unwrap(),
#[cfg(not(feature = "no_object"))]
Union::Map(value) => *cast_box::<_, T>(value).unwrap(),
#[cfg(not(feature = "no_module"))]
Union::Module(value) => *cast_box::<_, T>(value).unwrap(),
Union::Variant(value) => (*value).as_box_any().downcast().map(|x| *x).unwrap(),
}
}
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.
2020-04-12 17:00:06 +02:00
/// Returns `None` if the cast fails.
pub fn downcast_ref<T: Variant + Clone>(&self) -> Option<&T> {
2020-04-13 17:31:05 +02:00
if TypeId::of::<T>() == TypeId::of::<Dynamic>() {
2020-05-03 16:17:28 +02:00
return (self as &dyn Any).downcast_ref::<T>();
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::Unit(value) => (value as &dyn Any).downcast_ref::<T>(),
Union::Bool(value) => (value as &dyn Any).downcast_ref::<T>(),
Union::Str(value) => (value.as_ref() as &dyn Any).downcast_ref::<T>(),
Union::Char(value) => (value as &dyn Any).downcast_ref::<T>(),
Union::Int(value) => (value as &dyn Any).downcast_ref::<T>(),
2020-04-12 17:00:06 +02:00
#[cfg(not(feature = "no_float"))]
2020-05-03 16:17:28 +02:00
Union::Float(value) => (value as &dyn Any).downcast_ref::<T>(),
#[cfg(not(feature = "no_index"))]
2020-05-03 16:17:28 +02:00
Union::Array(value) => (value.as_ref() as &dyn Any).downcast_ref::<T>(),
#[cfg(not(feature = "no_object"))]
2020-05-03 16:17:28 +02:00
Union::Map(value) => (value.as_ref() as &dyn Any).downcast_ref::<T>(),
#[cfg(not(feature = "no_module"))]
2020-05-05 04:39:12 +02:00
Union::Module(value) => (value.as_ref() as &dyn Any).downcast_ref::<T>(),
2020-05-03 16:17:28 +02:00
Union::Variant(value) => value.as_ref().as_ref().as_any().downcast_ref::<T>(),
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-04-12 17:00:06 +02:00
/// Returns `None` if the cast fails.
pub fn downcast_mut<T: Variant + Clone>(&mut self) -> Option<&mut T> {
2020-04-13 17:31:05 +02:00
if TypeId::of::<T>() == TypeId::of::<Dynamic>() {
2020-05-03 16:17:28 +02:00
return (self as &mut dyn Any).downcast_mut::<T>();
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::Unit(value) => (value as &mut dyn Any).downcast_mut::<T>(),
Union::Bool(value) => (value as &mut dyn Any).downcast_mut::<T>(),
Union::Str(value) => (value.as_mut() as &mut dyn Any).downcast_mut::<T>(),
Union::Char(value) => (value as &mut dyn Any).downcast_mut::<T>(),
Union::Int(value) => (value as &mut dyn Any).downcast_mut::<T>(),
2020-04-12 17:00:06 +02:00
#[cfg(not(feature = "no_float"))]
2020-05-03 16:17:28 +02:00
Union::Float(value) => (value as &mut dyn Any).downcast_mut::<T>(),
#[cfg(not(feature = "no_index"))]
2020-05-03 16:17:28 +02:00
Union::Array(value) => (value.as_mut() as &mut dyn Any).downcast_mut::<T>(),
#[cfg(not(feature = "no_object"))]
2020-05-03 16:17:28 +02:00
Union::Map(value) => (value.as_mut() as &mut dyn Any).downcast_mut::<T>(),
#[cfg(not(feature = "no_module"))]
2020-05-05 04:39:12 +02:00
Union::Module(value) => (value.as_mut() as &mut dyn Any).downcast_mut::<T>(),
2020-05-03 16:17:28 +02:00
Union::Variant(value) => value.as_mut().as_mut_any().downcast_mut::<T>(),
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.
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),
_ => Err(self.type_name()),
}
}
/// Cast the `Dynamic` as a `bool` and return it.
/// Returns the name of the actual type if the cast fails.
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),
_ => Err(self.type_name()),
}
}
/// Cast the `Dynamic` as a `char` and return it.
/// Returns the name of the actual type if the cast fails.
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),
_ => 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.
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),
_ => Err(self.type_name()),
}
}
/// Convert the `Dynamic` into `String` and return it.
/// Returns the name of the actual type if the cast fails.
pub fn take_string(self) -> Result<String, &'static str> {
2020-04-12 17:00:06 +02:00
match self.0 {
Union::Str(s) => Ok(*s),
2020-04-12 17:00:06 +02:00
_ => Err(self.type_name()),
}
}
}
2020-04-12 17:00:06 +02:00
impl From<()> for Dynamic {
fn from(value: ()) -> Self {
Self(Union::Unit(value))
2020-04-12 17:00:06 +02:00
}
}
impl From<bool> for Dynamic {
fn from(value: bool) -> Self {
2020-04-12 17:00:06 +02:00
Self(Union::Bool(value))
}
}
impl From<INT> for Dynamic {
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 {
fn from(value: FLOAT) -> Self {
2020-04-12 17:00:06 +02:00
Self(Union::Float(value))
}
}
impl From<char> for Dynamic {
fn from(value: char) -> Self {
2020-04-12 17:00:06 +02:00
Self(Union::Char(value))
}
}
impl From<String> for Dynamic {
fn from(value: String) -> Self {
Self(Union::Str(Box::new(value)))
2020-03-04 15:00:01 +01:00
}
2017-12-20 12:16:14 +01:00
}
#[cfg(not(feature = "no_index"))]
impl<T: Variant + Clone> From<Vec<T>> for Dynamic {
fn from(value: Vec<T>) -> Self {
Self(Union::Array(Box::new(
value.into_iter().map(Dynamic::from).collect(),
)))
}
}
#[cfg(not(feature = "no_object"))]
impl<T: Variant + Clone> From<HashMap<String, T>> for Dynamic {
fn from(value: HashMap<String, T>) -> Self {
Self(Union::Map(Box::new(
value
.into_iter()
.map(|(k, v)| (k, Dynamic::from(v)))
.collect(),
)))
}
}
2017-12-20 12:16:14 +01:00
2020-03-04 15:00:01 +01:00
/// Private type which ensures that `rhai::Any` and `rhai::AnyExt` can only
2017-12-20 12:16:14 +01:00
/// be implemented by this crate.
#[doc(hidden)]
pub struct _Private;