rhai/types/
dynamic.rs

1//! Helper module which defines the [`Dynamic`] data type.
2
3use crate::{ExclusiveRange, FnPtr, ImmutableString, InclusiveRange, INT};
4#[cfg(feature = "no_std")]
5use std::prelude::v1::*;
6use std::{
7    any::{type_name, Any, TypeId},
8    fmt,
9    hash::{Hash, Hasher},
10    mem,
11    ops::{Deref, DerefMut},
12    str::FromStr,
13};
14
15pub use super::Variant;
16
17#[cfg(not(feature = "no_time"))]
18#[cfg(any(not(target_family = "wasm"), not(target_os = "unknown")))]
19pub use std::time::Instant;
20
21#[cfg(not(feature = "no_time"))]
22#[cfg(all(target_family = "wasm", target_os = "unknown"))]
23pub use instant::Instant;
24
25#[cfg(not(feature = "no_index"))]
26use crate::{Array, Blob};
27
28#[cfg(not(feature = "no_object"))]
29use crate::Map;
30
31/// _(internals)_ Modes of access.
32/// Exported under the `internals` feature only.
33#[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)]
34#[non_exhaustive]
35pub enum AccessMode {
36    /// Mutable.
37    ReadWrite,
38    /// Immutable.
39    ReadOnly,
40}
41
42/// Arbitrary data attached to a [`Dynamic`] value.
43#[cfg(target_pointer_width = "64")]
44pub type Tag = i32;
45
46/// Arbitrary data attached to a [`Dynamic`] value.
47#[cfg(target_pointer_width = "32")]
48pub type Tag = i16;
49
50/// Default tag value for [`Dynamic`].
51const DEFAULT_TAG_VALUE: Tag = 0;
52
53/// Dynamic type containing any value.
54#[must_use]
55pub struct Dynamic(pub(crate) Union);
56
57/// Internal [`Dynamic`] representation.
58///
59/// Most variants are boxed to reduce the size.
60#[must_use]
61pub enum Union {
62    /// The Unit value - ().
63    Unit((), Tag, AccessMode),
64    /// A boolean value.
65    Bool(bool, Tag, AccessMode),
66    /// An [`ImmutableString`] value.
67    Str(ImmutableString, Tag, AccessMode),
68    /// A character value.
69    Char(char, Tag, AccessMode),
70    /// An integer value.
71    Int(INT, Tag, AccessMode),
72    /// A floating-point value.
73    #[cfg(not(feature = "no_float"))]
74    Float(super::FloatWrapper<crate::FLOAT>, Tag, AccessMode),
75    /// _(decimal)_ A fixed-precision decimal value.
76    /// Exported under the `decimal` feature only.
77    #[cfg(feature = "decimal")]
78    Decimal(Box<rust_decimal::Decimal>, Tag, AccessMode),
79    /// An array value.
80    #[cfg(not(feature = "no_index"))]
81    Array(Box<Array>, Tag, AccessMode),
82    /// An blob (byte array).
83    #[cfg(not(feature = "no_index"))]
84    Blob(Box<Blob>, Tag, AccessMode),
85    /// An object map value.
86    #[cfg(not(feature = "no_object"))]
87    Map(Box<Map>, Tag, AccessMode),
88    /// A function pointer.
89    FnPtr(Box<FnPtr>, Tag, AccessMode),
90    /// A timestamp value.
91    #[cfg(not(feature = "no_time"))]
92    TimeStamp(Box<Instant>, Tag, AccessMode),
93
94    /// Any type as a trait object.
95    ///
96    /// An extra level of redirection is used in order to avoid bloating the size of [`Dynamic`]
97    /// because `Box<dyn Variant>` is a fat pointer.
98    Variant(Box<Box<dyn Variant>>, Tag, AccessMode),
99
100    /// A _shared_ value of any type.
101    #[cfg(not(feature = "no_closure"))]
102    Shared(crate::Shared<crate::Locked<Dynamic>>, Tag, AccessMode),
103}
104
105/// _(internals)_ Lock guard for reading a [`Dynamic`].
106/// Exported under the `internals` feature only.
107///
108/// This type provides transparent interoperability between normal [`Dynamic`] and shared
109/// [`Dynamic`] values.
110#[derive(Debug)]
111#[must_use]
112pub struct DynamicReadLock<'d, T: Clone>(DynamicReadLockInner<'d, T>);
113
114/// Different types of read guards for [`DynamicReadLock`].
115#[derive(Debug)]
116#[must_use]
117enum DynamicReadLockInner<'d, T: Clone> {
118    /// A simple reference to a non-shared value.
119    Reference(&'d T),
120
121    /// A read guard to a _shared_ value.
122    #[cfg(not(feature = "no_closure"))]
123    Guard(crate::func::native::LockGuard<'d, Dynamic>),
124}
125
126impl<'d, T: Any + Clone> Deref for DynamicReadLock<'d, T> {
127    type Target = T;
128
129    #[inline]
130    fn deref(&self) -> &Self::Target {
131        match self.0 {
132            DynamicReadLockInner::Reference(reference) => reference,
133            #[cfg(not(feature = "no_closure"))]
134            DynamicReadLockInner::Guard(ref guard) => guard.downcast_ref().unwrap(),
135        }
136    }
137}
138
139/// _(internals)_ Lock guard for writing a [`Dynamic`].
140/// Exported under the `internals` feature only.
141///
142/// This type provides transparent interoperability between normal [`Dynamic`] and shared
143/// [`Dynamic`] values.
144#[derive(Debug)]
145#[must_use]
146pub struct DynamicWriteLock<'d, T: Clone>(DynamicWriteLockInner<'d, T>);
147
148/// Different types of write guards for [`DynamicReadLock`].
149#[derive(Debug)]
150#[must_use]
151enum DynamicWriteLockInner<'d, T: Clone> {
152    /// A simple mutable reference to a non-shared value.
153    Reference(&'d mut T),
154
155    /// A write guard to a _shared_ value.
156    #[cfg(not(feature = "no_closure"))]
157    Guard(crate::func::native::LockGuardMut<'d, Dynamic>),
158}
159
160impl<'d, T: Any + Clone> Deref for DynamicWriteLock<'d, T> {
161    type Target = T;
162
163    #[inline]
164    fn deref(&self) -> &Self::Target {
165        match self.0 {
166            DynamicWriteLockInner::Reference(ref reference) => reference,
167            #[cfg(not(feature = "no_closure"))]
168            DynamicWriteLockInner::Guard(ref guard) => guard.downcast_ref().unwrap(),
169        }
170    }
171}
172
173impl<'d, T: Any + Clone> DerefMut for DynamicWriteLock<'d, T> {
174    #[inline]
175    fn deref_mut(&mut self) -> &mut Self::Target {
176        match self.0 {
177            DynamicWriteLockInner::Reference(ref mut reference) => reference,
178            #[cfg(not(feature = "no_closure"))]
179            DynamicWriteLockInner::Guard(ref mut guard) => guard.downcast_mut().unwrap(),
180        }
181    }
182}
183
184impl Dynamic {
185    /// Get the arbitrary data attached to this [`Dynamic`].
186    #[must_use]
187    pub const fn tag(&self) -> Tag {
188        match self.0 {
189            Union::Unit((), tag, _)
190            | Union::Bool(_, tag, _)
191            | Union::Str(_, tag, _)
192            | Union::Char(_, tag, _)
193            | Union::Int(_, tag, _)
194            | Union::FnPtr(_, tag, _)
195            | Union::Variant(_, tag, _) => tag,
196
197            #[cfg(not(feature = "no_float"))]
198            Union::Float(_, tag, _) => tag,
199            #[cfg(feature = "decimal")]
200            Union::Decimal(_, tag, _) => tag,
201            #[cfg(not(feature = "no_index"))]
202            Union::Array(_, tag, _) | Union::Blob(_, tag, _) => tag,
203            #[cfg(not(feature = "no_object"))]
204            Union::Map(_, tag, _) => tag,
205            #[cfg(not(feature = "no_time"))]
206            Union::TimeStamp(_, tag, _) => tag,
207            #[cfg(not(feature = "no_closure"))]
208            Union::Shared(_, tag, _) => tag,
209        }
210    }
211    /// Attach arbitrary data to this [`Dynamic`].
212    pub fn set_tag(&mut self, value: Tag) -> &mut Self {
213        match self.0 {
214            Union::Unit((), ref mut tag, _)
215            | Union::Bool(_, ref mut tag, _)
216            | Union::Str(_, ref mut tag, _)
217            | Union::Char(_, ref mut tag, _)
218            | Union::Int(_, ref mut tag, _)
219            | Union::FnPtr(_, ref mut tag, _)
220            | Union::Variant(_, ref mut tag, _) => *tag = value,
221
222            #[cfg(not(feature = "no_float"))]
223            Union::Float(_, ref mut tag, _) => *tag = value,
224            #[cfg(feature = "decimal")]
225            Union::Decimal(_, ref mut tag, _) => *tag = value,
226            #[cfg(not(feature = "no_index"))]
227            Union::Array(_, ref mut tag, _) | Union::Blob(_, ref mut tag, _) => *tag = value,
228            #[cfg(not(feature = "no_object"))]
229            Union::Map(_, ref mut tag, _) => *tag = value,
230            #[cfg(not(feature = "no_time"))]
231            Union::TimeStamp(_, ref mut tag, _) => *tag = value,
232            #[cfg(not(feature = "no_closure"))]
233            Union::Shared(_, ref mut tag, _) => *tag = value,
234        }
235        self
236    }
237    /// Does this [`Dynamic`] hold a variant data type instead of one of the supported system
238    /// primitive types?
239    #[inline(always)]
240    #[must_use]
241    pub const fn is_variant(&self) -> bool {
242        matches!(self.0, Union::Variant(..))
243    }
244    /// Is the value held by this [`Dynamic`] shared?
245    ///
246    /// Not available under `no_closure`.
247    #[cfg(not(feature = "no_closure"))]
248    #[inline(always)]
249    #[must_use]
250    pub const fn is_shared(&self) -> bool {
251        matches!(self.0, Union::Shared(..))
252    }
253    /// Is the value held by this [`Dynamic`] a particular type?
254    ///
255    /// # Panics or Deadlocks When Value is Shared
256    ///
257    /// Under the `sync` feature, this call may deadlock, or [panic](https://doc.rust-lang.org/std/sync/struct.RwLock.html#panics-1).
258    /// Otherwise, this call panics if the data is currently borrowed for write.
259    #[inline]
260    #[must_use]
261    pub fn is<T: Any + Clone>(&self) -> bool {
262        #[cfg(not(feature = "no_closure"))]
263        if self.is_shared() {
264            return TypeId::of::<T>() == self.type_id();
265        }
266
267        if TypeId::of::<T>() == TypeId::of::<()>() {
268            return matches!(self.0, Union::Unit(..));
269        }
270        if TypeId::of::<T>() == TypeId::of::<bool>() {
271            return matches!(self.0, Union::Bool(..));
272        }
273        if TypeId::of::<T>() == TypeId::of::<char>() {
274            return matches!(self.0, Union::Char(..));
275        }
276        if TypeId::of::<T>() == TypeId::of::<INT>() {
277            return matches!(self.0, Union::Int(..));
278        }
279        #[cfg(not(feature = "no_float"))]
280        if TypeId::of::<T>() == TypeId::of::<crate::FLOAT>() {
281            return matches!(self.0, Union::Float(..));
282        }
283        if TypeId::of::<T>() == TypeId::of::<ImmutableString>()
284            || TypeId::of::<T>() == TypeId::of::<String>()
285        {
286            return matches!(self.0, Union::Str(..));
287        }
288        #[cfg(not(feature = "no_index"))]
289        if TypeId::of::<T>() == TypeId::of::<Array>() {
290            return matches!(self.0, Union::Array(..));
291        }
292        #[cfg(not(feature = "no_index"))]
293        if TypeId::of::<T>() == TypeId::of::<Blob>() {
294            return matches!(self.0, Union::Blob(..));
295        }
296        #[cfg(not(feature = "no_object"))]
297        if TypeId::of::<T>() == TypeId::of::<Map>() {
298            return matches!(self.0, Union::Map(..));
299        }
300        #[cfg(feature = "decimal")]
301        if TypeId::of::<T>() == TypeId::of::<rust_decimal::Decimal>() {
302            return matches!(self.0, Union::Decimal(..));
303        }
304        if TypeId::of::<T>() == TypeId::of::<FnPtr>() {
305            return matches!(self.0, Union::FnPtr(..));
306        }
307        #[cfg(not(feature = "no_time"))]
308        if TypeId::of::<T>() == TypeId::of::<crate::Instant>() {
309            return matches!(self.0, Union::TimeStamp(..));
310        }
311
312        TypeId::of::<T>() == self.type_id()
313    }
314    /// Get the [`TypeId`] of the value held by this [`Dynamic`].
315    ///
316    /// # Panics or Deadlocks When Value is Shared
317    ///
318    /// Under the `sync` feature, this call may deadlock, or [panic](https://doc.rust-lang.org/std/sync/struct.RwLock.html#panics-1).
319    /// Otherwise, this call panics if the data is currently borrowed for write.
320    #[must_use]
321    pub fn type_id(&self) -> TypeId {
322        match self.0 {
323            Union::Unit(..) => TypeId::of::<()>(),
324            Union::Bool(..) => TypeId::of::<bool>(),
325            Union::Str(..) => TypeId::of::<ImmutableString>(),
326            Union::Char(..) => TypeId::of::<char>(),
327            Union::Int(..) => TypeId::of::<INT>(),
328            #[cfg(not(feature = "no_float"))]
329            Union::Float(..) => TypeId::of::<crate::FLOAT>(),
330            #[cfg(feature = "decimal")]
331            Union::Decimal(..) => TypeId::of::<rust_decimal::Decimal>(),
332            #[cfg(not(feature = "no_index"))]
333            Union::Array(..) => TypeId::of::<Array>(),
334            #[cfg(not(feature = "no_index"))]
335            Union::Blob(..) => TypeId::of::<Blob>(),
336            #[cfg(not(feature = "no_object"))]
337            Union::Map(..) => TypeId::of::<Map>(),
338            Union::FnPtr(..) => TypeId::of::<FnPtr>(),
339            #[cfg(not(feature = "no_time"))]
340            Union::TimeStamp(..) => TypeId::of::<Instant>(),
341
342            Union::Variant(ref v, ..) => (***v).type_id(),
343
344            #[cfg(not(feature = "no_closure"))]
345            Union::Shared(ref cell, ..) => (*crate::func::locked_read(cell).unwrap()).type_id(),
346        }
347    }
348    /// Get the name of the type of the value held by this [`Dynamic`].
349    ///
350    /// # Panics or Deadlocks When Value is Shared
351    ///
352    /// Under the `sync` feature, this call may deadlock, or [panic](https://doc.rust-lang.org/std/sync/struct.RwLock.html#panics-1).
353    /// Otherwise, this call panics if the data is currently borrowed for write.
354    #[must_use]
355    pub fn type_name(&self) -> &'static str {
356        match self.0 {
357            Union::Unit(..) => "()",
358            Union::Bool(..) => "bool",
359            Union::Str(..) => "string",
360            Union::Char(..) => "char",
361            Union::Int(..) => type_name::<INT>(),
362            #[cfg(not(feature = "no_float"))]
363            Union::Float(..) => type_name::<crate::FLOAT>(),
364            #[cfg(feature = "decimal")]
365            Union::Decimal(..) => "decimal",
366            #[cfg(not(feature = "no_index"))]
367            Union::Array(..) => "array",
368            #[cfg(not(feature = "no_index"))]
369            Union::Blob(..) => "blob",
370            #[cfg(not(feature = "no_object"))]
371            Union::Map(..) => "map",
372            Union::FnPtr(..) => "Fn",
373            #[cfg(not(feature = "no_time"))]
374            Union::TimeStamp(..) => "timestamp",
375
376            Union::Variant(ref v, ..) => (***v).type_name(),
377
378            #[cfg(not(feature = "no_closure"))]
379            Union::Shared(ref cell, ..) => (*crate::func::locked_read(cell).unwrap()).type_name(),
380        }
381    }
382}
383
384impl Hash for Dynamic {
385    /// Hash the [`Dynamic`] value.
386    ///
387    /// # Panics
388    ///
389    /// Panics if the [`Dynamic`] value contains an unrecognized trait object.
390    fn hash<H: Hasher>(&self, state: &mut H) {
391        mem::discriminant(&self.0).hash(state);
392
393        match self.0 {
394            Union::Unit(..) => (),
395            Union::Bool(ref b, ..) => b.hash(state),
396            Union::Str(ref s, ..) => s.hash(state),
397            Union::Char(ref c, ..) => c.hash(state),
398            Union::Int(ref i, ..) => i.hash(state),
399            #[cfg(not(feature = "no_float"))]
400            Union::Float(ref f, ..) => f.hash(state),
401            #[cfg(feature = "decimal")]
402            Union::Decimal(ref d, ..) => d.hash(state),
403            #[cfg(not(feature = "no_index"))]
404            Union::Array(ref a, ..) => a.hash(state),
405            #[cfg(not(feature = "no_index"))]
406            Union::Blob(ref a, ..) => a.hash(state),
407            #[cfg(not(feature = "no_object"))]
408            Union::Map(ref m, ..) => m.hash(state),
409            #[cfg(not(feature = "no_function"))]
410            Union::FnPtr(ref f, ..) if f.env.is_some() => {
411                unimplemented!("FnPtr with embedded environment cannot be hashed")
412            }
413            Union::FnPtr(ref f, ..) => {
414                f.fn_name().hash(state);
415                f.curry().hash(state);
416            }
417
418            #[cfg(not(feature = "no_closure"))]
419            Union::Shared(ref cell, ..) => (*crate::func::locked_read(cell).unwrap()).hash(state),
420
421            Union::Variant(ref v, ..) => {
422                let _value_any = (***v).as_any();
423
424                #[cfg(not(feature = "only_i32"))]
425                #[cfg(not(feature = "only_i64"))]
426                if let Some(value) = _value_any.downcast_ref::<u8>() {
427                    return value.hash(state);
428                } else if let Some(value) = _value_any.downcast_ref::<u16>() {
429                    return value.hash(state);
430                } else if let Some(value) = _value_any.downcast_ref::<u32>() {
431                    return value.hash(state);
432                } else if let Some(value) = _value_any.downcast_ref::<u64>() {
433                    return value.hash(state);
434                } else if let Some(value) = _value_any.downcast_ref::<i8>() {
435                    return value.hash(state);
436                } else if let Some(value) = _value_any.downcast_ref::<i16>() {
437                    return value.hash(state);
438                } else if let Some(value) = _value_any.downcast_ref::<i32>() {
439                    return value.hash(state);
440                } else if let Some(value) = _value_any.downcast_ref::<i64>() {
441                    return value.hash(state);
442                }
443
444                #[cfg(not(feature = "no_float"))]
445                #[cfg(not(feature = "f32_float"))]
446                if let Some(value) = _value_any.downcast_ref::<f32>() {
447                    return value.to_ne_bytes().hash(state);
448                }
449                #[cfg(not(feature = "no_float"))]
450                #[cfg(feature = "f32_float")]
451                if let Some(value) = _value_any.downcast_ref::<f64>() {
452                    return value.to_ne_bytes().hash(state);
453                }
454
455                #[cfg(not(feature = "only_i32"))]
456                #[cfg(not(feature = "only_i64"))]
457                #[cfg(not(target_family = "wasm"))]
458                if let Some(value) = _value_any.downcast_ref::<u128>() {
459                    return value.hash(state);
460                } else if let Some(value) = _value_any.downcast_ref::<i128>() {
461                    return value.hash(state);
462                }
463
464                if let Some(range) = _value_any.downcast_ref::<ExclusiveRange>() {
465                    return range.hash(state);
466                } else if let Some(range) = _value_any.downcast_ref::<InclusiveRange>() {
467                    return range.hash(state);
468                }
469
470                unimplemented!("Custom type {} cannot be hashed", self.type_name())
471            }
472
473            #[cfg(not(feature = "no_time"))]
474            Union::TimeStamp(..) => unimplemented!("Timestamp cannot be hashed"),
475        }
476    }
477}
478
479impl fmt::Display for Dynamic {
480    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
481        match self.0 {
482            Union::Unit(..) => Ok(()),
483            Union::Bool(ref v, ..) => fmt::Display::fmt(v, f),
484            Union::Str(ref v, ..) => fmt::Display::fmt(v, f),
485            Union::Char(ref v, ..) => fmt::Display::fmt(v, f),
486            Union::Int(ref v, ..) => fmt::Display::fmt(v, f),
487            #[cfg(not(feature = "no_float"))]
488            Union::Float(ref v, ..) => fmt::Display::fmt(v, f),
489            #[cfg(feature = "decimal")]
490            Union::Decimal(ref v, ..) => fmt::Display::fmt(v, f),
491            #[cfg(not(feature = "no_index"))]
492            Union::Array(..) => fmt::Debug::fmt(self, f),
493            #[cfg(not(feature = "no_index"))]
494            Union::Blob(..) => fmt::Debug::fmt(self, f),
495            #[cfg(not(feature = "no_object"))]
496            Union::Map(..) => fmt::Debug::fmt(self, f),
497            Union::FnPtr(ref v, ..) => fmt::Display::fmt(v, f),
498            #[cfg(not(feature = "no_time"))]
499            Union::TimeStamp(..) => f.write_str("<timestamp>"),
500
501            Union::Variant(ref v, ..) => {
502                let _value_any = (***v).as_any();
503                let _type_id = _value_any.type_id();
504
505                #[cfg(not(feature = "only_i32"))]
506                #[cfg(not(feature = "only_i64"))]
507                if let Some(value) = _value_any.downcast_ref::<u8>() {
508                    return fmt::Display::fmt(value, f);
509                } else if let Some(value) = _value_any.downcast_ref::<u16>() {
510                    return fmt::Display::fmt(value, f);
511                } else if let Some(value) = _value_any.downcast_ref::<u32>() {
512                    return fmt::Display::fmt(value, f);
513                } else if let Some(value) = _value_any.downcast_ref::<u64>() {
514                    return fmt::Display::fmt(value, f);
515                } else if let Some(value) = _value_any.downcast_ref::<i8>() {
516                    return fmt::Display::fmt(value, f);
517                } else if let Some(value) = _value_any.downcast_ref::<i16>() {
518                    return fmt::Display::fmt(value, f);
519                } else if let Some(value) = _value_any.downcast_ref::<i32>() {
520                    return fmt::Display::fmt(value, f);
521                } else if let Some(value) = _value_any.downcast_ref::<i64>() {
522                    return fmt::Display::fmt(value, f);
523                }
524
525                #[cfg(not(feature = "no_float"))]
526                #[cfg(not(feature = "f32_float"))]
527                if let Some(value) = _value_any.downcast_ref::<f32>() {
528                    return fmt::Display::fmt(value, f);
529                }
530                #[cfg(not(feature = "no_float"))]
531                #[cfg(feature = "f32_float")]
532                if let Some(value) = _value_any.downcast_ref::<f64>() {
533                    return fmt::Display::fmt(value, f);
534                }
535
536                #[cfg(not(feature = "only_i32"))]
537                #[cfg(not(feature = "only_i64"))]
538                #[cfg(not(target_family = "wasm"))]
539                if let Some(value) = _value_any.downcast_ref::<u128>() {
540                    return fmt::Display::fmt(value, f);
541                } else if let Some(value) = _value_any.downcast_ref::<i128>() {
542                    return fmt::Display::fmt(value, f);
543                }
544
545                if let Some(range) = _value_any.downcast_ref::<ExclusiveRange>() {
546                    return if range.end == INT::MAX {
547                        write!(f, "{}..", range.start)
548                    } else {
549                        write!(f, "{}..{}", range.start, range.end)
550                    };
551                } else if let Some(range) = _value_any.downcast_ref::<InclusiveRange>() {
552                    return if *range.end() == INT::MAX {
553                        write!(f, "{}..=", range.start())
554                    } else {
555                        write!(f, "{}..={}", range.start(), range.end())
556                    };
557                }
558
559                f.write_str((***v).type_name())
560            }
561
562            #[cfg(not(feature = "no_closure"))]
563            Union::Shared(ref cell, ..) if cfg!(feature = "unchecked") => {
564                match crate::func::locked_read(cell) {
565                    Some(v) => write!(f, "{} (shared)", *v),
566                    _ => f.write_str("<shared>"),
567                }
568            }
569            #[cfg(not(feature = "no_closure"))]
570            Union::Shared(..) => {
571                #[cfg(feature = "no_std")]
572                use hashbrown::HashSet;
573                #[cfg(not(feature = "no_std"))]
574                use std::collections::HashSet;
575
576                // Avoid infinite recursion for shared values in a reference loop.
577                fn display_fmt_print(
578                    f: &mut fmt::Formatter<'_>,
579                    value: &Dynamic,
580                    dict: &mut HashSet<*const Dynamic>,
581                ) -> fmt::Result {
582                    match value.0 {
583                        #[cfg(not(feature = "no_closure"))]
584                        Union::Shared(ref cell, ..) => match crate::func::locked_read(cell) {
585                            Some(v) => {
586                                if dict.insert(value) {
587                                    display_fmt_print(f, &v, dict)?;
588                                    f.write_str(" (shared)")
589                                } else {
590                                    f.write_str("<shared>")
591                                }
592                            }
593                            _ => f.write_str("<shared>"),
594                        },
595                        #[cfg(not(feature = "no_index"))]
596                        Union::Array(ref arr, ..) => {
597                            dict.insert(value);
598
599                            f.write_str("[")?;
600                            for (i, v) in arr.iter().enumerate() {
601                                if i > 0 {
602                                    f.write_str(", ")?;
603                                }
604                                display_fmt_print(f, v, dict)?;
605                            }
606                            f.write_str("]")
607                        }
608                        #[cfg(not(feature = "no_object"))]
609                        Union::Map(ref map, ..) => {
610                            dict.insert(value);
611
612                            f.write_str("#{")?;
613                            for (i, (k, v)) in map.iter().enumerate() {
614                                if i > 0 {
615                                    f.write_str(", ")?;
616                                }
617                                fmt::Display::fmt(k, f)?;
618                                f.write_str(": ")?;
619                                display_fmt_print(f, v, dict)?;
620                            }
621                            f.write_str("}")
622                        }
623                        _ => fmt::Display::fmt(value, f),
624                    }
625                }
626
627                display_fmt_print(f, self, &mut <_>::default())
628            }
629        }
630    }
631}
632
633impl fmt::Debug for Dynamic {
634    #[cold]
635    #[inline(never)]
636    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
637        match self.0 {
638            Union::Unit(ref v, ..) => fmt::Debug::fmt(v, f),
639            Union::Bool(ref v, ..) => fmt::Debug::fmt(v, f),
640            Union::Str(ref v, ..) => fmt::Debug::fmt(v, f),
641            Union::Char(ref v, ..) => fmt::Debug::fmt(v, f),
642            Union::Int(ref v, ..) => fmt::Debug::fmt(v, f),
643            #[cfg(not(feature = "no_float"))]
644            Union::Float(ref v, ..) => fmt::Debug::fmt(v, f),
645            #[cfg(feature = "decimal")]
646            Union::Decimal(ref v, ..) => fmt::Debug::fmt(v, f),
647            #[cfg(not(feature = "no_index"))]
648            Union::Array(ref v, ..) => fmt::Debug::fmt(v, f),
649            #[cfg(not(feature = "no_index"))]
650            Union::Blob(ref v, ..) => {
651                f.write_str("[")?;
652                v.iter().enumerate().try_for_each(|(i, v)| {
653                    if i > 0 && i % 8 == 0 {
654                        f.write_str(" ")?;
655                    }
656                    write!(f, "{v:02x}")
657                })?;
658                f.write_str("]")
659            }
660            #[cfg(not(feature = "no_object"))]
661            Union::Map(ref v, ..) => {
662                f.write_str("#")?;
663                fmt::Debug::fmt(v, f)
664            }
665            Union::FnPtr(ref v, ..) => fmt::Debug::fmt(v, f),
666            #[cfg(not(feature = "no_time"))]
667            Union::TimeStamp(..) => write!(f, "<timestamp>"),
668
669            Union::Variant(ref v, ..) => {
670                let _value_any = (***v).as_any();
671                let _type_id = _value_any.type_id();
672
673                #[cfg(not(feature = "only_i32"))]
674                #[cfg(not(feature = "only_i64"))]
675                if let Some(value) = _value_any.downcast_ref::<u8>() {
676                    return fmt::Debug::fmt(value, f);
677                } else if let Some(value) = _value_any.downcast_ref::<u16>() {
678                    return fmt::Debug::fmt(value, f);
679                } else if let Some(value) = _value_any.downcast_ref::<u32>() {
680                    return fmt::Debug::fmt(value, f);
681                } else if let Some(value) = _value_any.downcast_ref::<u64>() {
682                    return fmt::Debug::fmt(value, f);
683                } else if let Some(value) = _value_any.downcast_ref::<i8>() {
684                    return fmt::Debug::fmt(value, f);
685                } else if let Some(value) = _value_any.downcast_ref::<i16>() {
686                    return fmt::Debug::fmt(value, f);
687                } else if let Some(value) = _value_any.downcast_ref::<i32>() {
688                    return fmt::Debug::fmt(value, f);
689                } else if let Some(value) = _value_any.downcast_ref::<i64>() {
690                    return fmt::Debug::fmt(value, f);
691                }
692
693                #[cfg(not(feature = "no_float"))]
694                #[cfg(not(feature = "f32_float"))]
695                if let Some(value) = _value_any.downcast_ref::<f32>() {
696                    return fmt::Debug::fmt(value, f);
697                }
698                #[cfg(not(feature = "no_float"))]
699                #[cfg(feature = "f32_float")]
700                if let Some(value) = _value_any.downcast_ref::<f64>() {
701                    return fmt::Debug::fmt(value, f);
702                }
703
704                #[cfg(not(feature = "only_i32"))]
705                #[cfg(not(feature = "only_i64"))]
706                #[cfg(not(target_family = "wasm"))]
707                if let Some(value) = _value_any.downcast_ref::<u128>() {
708                    return fmt::Debug::fmt(value, f);
709                } else if let Some(value) = _value_any.downcast_ref::<i128>() {
710                    return fmt::Debug::fmt(value, f);
711                }
712
713                if let Some(range) = _value_any.downcast_ref::<ExclusiveRange>() {
714                    return if range.end == INT::MAX {
715                        write!(f, "{}..", range.start)
716                    } else {
717                        write!(f, "{}..{}", range.start, range.end)
718                    };
719                } else if let Some(range) = _value_any.downcast_ref::<InclusiveRange>() {
720                    return if *range.end() == INT::MAX {
721                        write!(f, "{}..=", range.start())
722                    } else {
723                        write!(f, "{}..={}", range.start(), range.end())
724                    };
725                }
726
727                f.write_str((***v).type_name())
728            }
729
730            #[cfg(not(feature = "no_closure"))]
731            Union::Shared(ref cell, ..) if cfg!(feature = "unchecked") => {
732                match crate::func::locked_read(cell) {
733                    Some(v) => write!(f, "{:?} (shared)", *v),
734                    _ => f.write_str("<shared>"),
735                }
736            }
737            #[cfg(not(feature = "no_closure"))]
738            Union::Shared(..) => {
739                #[cfg(feature = "no_std")]
740                use hashbrown::HashSet;
741                #[cfg(not(feature = "no_std"))]
742                use std::collections::HashSet;
743
744                // Avoid infinite recursion for shared values in a reference loop.
745                fn checked_debug_fmt(
746                    f: &mut fmt::Formatter<'_>,
747                    value: &Dynamic,
748                    dict: &mut HashSet<*const Dynamic>,
749                ) -> fmt::Result {
750                    match value.0 {
751                        Union::Shared(ref cell, ..) => match crate::func::locked_read(cell) {
752                            Some(v) => {
753                                if dict.insert(value) {
754                                    checked_debug_fmt(f, &v, dict)?;
755                                    f.write_str(" (shared)")
756                                } else {
757                                    f.write_str("<shared>")
758                                }
759                            }
760                            _ => f.write_str("<shared>"),
761                        },
762                        #[cfg(not(feature = "no_index"))]
763                        Union::Array(ref arr, ..) => {
764                            dict.insert(value);
765
766                            f.write_str("[")?;
767                            for (i, v) in arr.iter().enumerate() {
768                                if i > 0 {
769                                    f.write_str(", ")?;
770                                }
771                                checked_debug_fmt(f, v, dict)?;
772                            }
773                            f.write_str("]")
774                        }
775                        #[cfg(not(feature = "no_object"))]
776                        Union::Map(ref map, ..) => {
777                            dict.insert(value);
778
779                            f.write_str("#{")?;
780                            for (i, (k, v)) in map.iter().enumerate() {
781                                if i > 0 {
782                                    f.write_str(", ")?;
783                                }
784                                fmt::Debug::fmt(k, f)?;
785                                f.write_str(": ")?;
786                                checked_debug_fmt(f, v, dict)?;
787                            }
788                            f.write_str("}")
789                        }
790                        Union::FnPtr(ref fnptr, ..) => {
791                            dict.insert(value);
792
793                            fmt::Display::fmt(&fnptr.typ, f)?;
794                            f.write_str("(")?;
795                            fmt::Debug::fmt(fnptr.fn_name(), f)?;
796                            for curry in &fnptr.curry {
797                                f.write_str(", ")?;
798                                checked_debug_fmt(f, curry, dict)?;
799                            }
800                            f.write_str(")")
801                        }
802                        _ => fmt::Debug::fmt(value, f),
803                    }
804                }
805
806                checked_debug_fmt(f, self, &mut <_>::default())
807            }
808        }
809    }
810}
811
812#[allow(clippy::enum_glob_use)]
813use AccessMode::*;
814
815impl Clone for Dynamic {
816    /// Clone the [`Dynamic`] value.
817    ///
818    /// # WARNING
819    ///
820    /// The cloned copy is marked read-write even if the original is read-only.
821    fn clone(&self) -> Self {
822        match self.0 {
823            Union::Unit(v, tag, ..) => Self(Union::Unit(v, tag, ReadWrite)),
824            Union::Bool(v, tag, ..) => Self(Union::Bool(v, tag, ReadWrite)),
825            Union::Str(ref v, tag, ..) => Self(Union::Str(v.clone(), tag, ReadWrite)),
826            Union::Char(v, tag, ..) => Self(Union::Char(v, tag, ReadWrite)),
827            Union::Int(v, tag, ..) => Self(Union::Int(v, tag, ReadWrite)),
828            #[cfg(not(feature = "no_float"))]
829            Union::Float(v, tag, ..) => Self(Union::Float(v, tag, ReadWrite)),
830            #[cfg(feature = "decimal")]
831            Union::Decimal(ref v, tag, ..) => Self(Union::Decimal(v.clone(), tag, ReadWrite)),
832            #[cfg(not(feature = "no_index"))]
833            Union::Array(ref v, tag, ..) => Self(Union::Array(v.clone(), tag, ReadWrite)),
834            #[cfg(not(feature = "no_index"))]
835            Union::Blob(ref v, tag, ..) => Self(Union::Blob(v.clone(), tag, ReadWrite)),
836            #[cfg(not(feature = "no_object"))]
837            Union::Map(ref v, tag, ..) => Self(Union::Map(v.clone(), tag, ReadWrite)),
838            Union::FnPtr(ref v, tag, ..) => Self(Union::FnPtr(v.clone(), tag, ReadWrite)),
839            #[cfg(not(feature = "no_time"))]
840            Union::TimeStamp(ref v, tag, ..) => Self(Union::TimeStamp(v.clone(), tag, ReadWrite)),
841
842            Union::Variant(ref v, tag, ..) => Self(Union::Variant(
843                v.as_ref().as_ref().clone_object().into(),
844                tag,
845                ReadWrite,
846            )),
847
848            #[cfg(not(feature = "no_closure"))]
849            Union::Shared(ref cell, tag, ..) => Self(Union::Shared(cell.clone(), tag, ReadWrite)),
850        }
851    }
852}
853
854impl Default for Dynamic {
855    #[inline(always)]
856    fn default() -> Self {
857        Self::UNIT
858    }
859}
860
861#[cfg(not(feature = "no_float"))]
862#[cfg(feature = "f32_float")]
863use std::f32::consts as FloatConstants;
864#[cfg(not(feature = "no_float"))]
865#[cfg(not(feature = "f32_float"))]
866use std::f64::consts as FloatConstants;
867
868impl Dynamic {
869    /// A [`Dynamic`] containing a `()`.
870    pub const UNIT: Self = Self(Union::Unit((), DEFAULT_TAG_VALUE, ReadWrite));
871    /// A [`Dynamic`] containing a `true`.
872    pub const TRUE: Self = Self::from_bool(true);
873    /// A [`Dynamic`] containing a [`false`].
874    pub const FALSE: Self = Self::from_bool(false);
875    /// A [`Dynamic`] containing the integer zero.
876    pub const ZERO: Self = Self::from_int(0);
877    /// A [`Dynamic`] containing the integer 1.
878    pub const ONE: Self = Self::from_int(1);
879    /// A [`Dynamic`] containing the integer 2.
880    pub const TWO: Self = Self::from_int(2);
881    /// A [`Dynamic`] containing the integer 3.
882    pub const THREE: Self = Self::from_int(3);
883    /// A [`Dynamic`] containing the integer 10.
884    pub const TEN: Self = Self::from_int(10);
885    /// A [`Dynamic`] containing the integer 100.
886    pub const HUNDRED: Self = Self::from_int(100);
887    /// A [`Dynamic`] containing the integer 1,000.
888    pub const THOUSAND: Self = Self::from_int(1000);
889    /// A [`Dynamic`] containing the integer 1,000,000.
890    pub const MILLION: Self = Self::from_int(1_000_000);
891    /// A [`Dynamic`] containing the integer -1.
892    pub const NEGATIVE_ONE: Self = Self::from_int(-1);
893    /// A [`Dynamic`] containing the integer -2.
894    pub const NEGATIVE_TWO: Self = Self::from_int(-2);
895    /// A [`Dynamic`] containing `0.0`.
896    ///
897    /// Not available under `no_float`.
898    #[cfg(not(feature = "no_float"))]
899    pub const FLOAT_ZERO: Self = Self::from_float(0.0);
900    /// A [`Dynamic`] containing `1.0`.
901    ///
902    /// Not available under `no_float`.
903    #[cfg(not(feature = "no_float"))]
904    pub const FLOAT_ONE: Self = Self::from_float(1.0);
905    /// A [`Dynamic`] containing `2.0`.
906    ///
907    /// Not available under `no_float`.
908    #[cfg(not(feature = "no_float"))]
909    pub const FLOAT_TWO: Self = Self::from_float(2.0);
910    /// A [`Dynamic`] containing `10.0`.
911    ///
912    /// Not available under `no_float`.
913    #[cfg(not(feature = "no_float"))]
914    pub const FLOAT_TEN: Self = Self::from_float(10.0);
915    /// A [`Dynamic`] containing `100.0`.
916    ///
917    /// Not available under `no_float`.
918    #[cfg(not(feature = "no_float"))]
919    pub const FLOAT_HUNDRED: Self = Self::from_float(100.0);
920    /// A [`Dynamic`] containing `1000.0`.
921    ///
922    /// Not available under `no_float`.
923    #[cfg(not(feature = "no_float"))]
924    pub const FLOAT_THOUSAND: Self = Self::from_float(1000.0);
925    /// A [`Dynamic`] containing `1000000.0`.
926    ///
927    /// Not available under `no_float`.
928    #[cfg(not(feature = "no_float"))]
929    pub const FLOAT_MILLION: Self = Self::from_float(1_000_000.0);
930    /// A [`Dynamic`] containing `-1.0`.
931    ///
932    /// Not available under `no_float`.
933    #[cfg(not(feature = "no_float"))]
934    pub const FLOAT_NEGATIVE_ONE: Self = Self::from_float(-1.0);
935    /// A [`Dynamic`] containing `-2.0`.
936    ///
937    /// Not available under `no_float`.
938    #[cfg(not(feature = "no_float"))]
939    pub const FLOAT_NEGATIVE_TWO: Self = Self::from_float(-2.0);
940    /// A [`Dynamic`] containing `0.5`.
941    ///
942    /// Not available under `no_float`.
943    #[cfg(not(feature = "no_float"))]
944    pub const FLOAT_HALF: Self = Self::from_float(0.5);
945    /// A [`Dynamic`] containing `0.25`.
946    ///
947    /// Not available under `no_float`.
948    #[cfg(not(feature = "no_float"))]
949    pub const FLOAT_QUARTER: Self = Self::from_float(0.25);
950    /// A [`Dynamic`] containing `0.2`.
951    ///
952    /// Not available under `no_float`.
953    #[cfg(not(feature = "no_float"))]
954    pub const FLOAT_FIFTH: Self = Self::from_float(0.2);
955    /// A [`Dynamic`] containing `0.1`.
956    ///
957    /// Not available under `no_float`.
958    #[cfg(not(feature = "no_float"))]
959    pub const FLOAT_TENTH: Self = Self::from_float(0.1);
960    /// A [`Dynamic`] containing `0.01`.
961    ///
962    /// Not available under `no_float`.
963    #[cfg(not(feature = "no_float"))]
964    pub const FLOAT_HUNDREDTH: Self = Self::from_float(0.01);
965    /// A [`Dynamic`] containing `0.001`.
966    ///
967    /// Not available under `no_float`.
968    #[cfg(not(feature = "no_float"))]
969    pub const FLOAT_THOUSANDTH: Self = Self::from_float(0.001);
970    /// A [`Dynamic`] containing `0.000001`.
971    ///
972    /// Not available under `no_float`.
973    #[cfg(not(feature = "no_float"))]
974    pub const FLOAT_MILLIONTH: Self = Self::from_float(0.000_001);
975    /// A [`Dynamic`] containing π.
976    ///
977    /// Not available under `no_float`.
978    #[cfg(not(feature = "no_float"))]
979    pub const FLOAT_PI: Self = Self::from_float(FloatConstants::PI);
980    /// A [`Dynamic`] containing π/2.
981    ///
982    /// Not available under `no_float`.
983    #[cfg(not(feature = "no_float"))]
984    pub const FLOAT_HALF_PI: Self = Self::from_float(FloatConstants::FRAC_PI_2);
985    /// A [`Dynamic`] containing π/4.
986    ///
987    /// Not available under `no_float`.
988    #[cfg(not(feature = "no_float"))]
989    pub const FLOAT_QUARTER_PI: Self = Self::from_float(FloatConstants::FRAC_PI_4);
990    /// A [`Dynamic`] containing 2Ï€.
991    ///
992    /// Not available under `no_float`.
993    #[cfg(not(feature = "no_float"))]
994    pub const FLOAT_TWO_PI: Self = Self::from_float(FloatConstants::TAU);
995    /// A [`Dynamic`] containing 1/Ï€.
996    ///
997    /// Not available under `no_float`.
998    #[cfg(not(feature = "no_float"))]
999    pub const FLOAT_INVERSE_PI: Self = Self::from_float(FloatConstants::FRAC_1_PI);
1000    /// A [`Dynamic`] containing _e_.
1001    ///
1002    /// Not available under `no_float`.
1003    #[cfg(not(feature = "no_float"))]
1004    pub const FLOAT_E: Self = Self::from_float(FloatConstants::E);
1005    /// A [`Dynamic`] containing `log` _e_.
1006    ///
1007    /// Not available under `no_float`.
1008    #[cfg(not(feature = "no_float"))]
1009    pub const FLOAT_LOG_E: Self = Self::from_float(FloatConstants::LOG10_E);
1010    /// A [`Dynamic`] containing `ln 10`.
1011    ///
1012    /// Not available under `no_float`.
1013    #[cfg(not(feature = "no_float"))]
1014    pub const FLOAT_LN_10: Self = Self::from_float(FloatConstants::LN_10);
1015
1016    /// Create a new [`Dynamic`] from a [`bool`].
1017    #[inline(always)]
1018    pub const fn from_bool(value: bool) -> Self {
1019        Self(Union::Bool(value, DEFAULT_TAG_VALUE, ReadWrite))
1020    }
1021    /// Create a new [`Dynamic`] from an [`INT`].
1022    #[inline(always)]
1023    pub const fn from_int(value: INT) -> Self {
1024        Self(Union::Int(value, DEFAULT_TAG_VALUE, ReadWrite))
1025    }
1026    /// Create a new [`Dynamic`] from a [`char`].
1027    #[inline(always)]
1028    pub const fn from_char(value: char) -> Self {
1029        Self(Union::Char(value, DEFAULT_TAG_VALUE, ReadWrite))
1030    }
1031    /// Create a new [`Dynamic`] from a [`FLOAT`][crate::FLOAT].
1032    ///
1033    /// Not available under `no_float`.
1034    #[cfg(not(feature = "no_float"))]
1035    #[inline(always)]
1036    pub const fn from_float(value: crate::FLOAT) -> Self {
1037        Self(Union::Float(
1038            super::FloatWrapper::new(value),
1039            DEFAULT_TAG_VALUE,
1040            ReadWrite,
1041        ))
1042    }
1043    /// Create a new [`Dynamic`] from a [`Decimal`](https://docs.rs/rust_decimal).
1044    ///
1045    /// Exported under the `decimal` feature only.
1046    #[cfg(feature = "decimal")]
1047    #[inline(always)]
1048    pub fn from_decimal(value: rust_decimal::Decimal) -> Self {
1049        Self(Union::Decimal(value.into(), DEFAULT_TAG_VALUE, ReadWrite))
1050    }
1051    /// Create a [`Dynamic`] from an [`Array`].
1052    #[cfg(not(feature = "no_index"))]
1053    #[inline(always)]
1054    pub fn from_array(array: Array) -> Self {
1055        Self(Union::Array(array.into(), DEFAULT_TAG_VALUE, ReadWrite))
1056    }
1057    /// Create a [`Dynamic`] from a [`Blob`].
1058    #[cfg(not(feature = "no_index"))]
1059    #[inline(always)]
1060    pub fn from_blob(blob: Blob) -> Self {
1061        Self(Union::Blob(blob.into(), DEFAULT_TAG_VALUE, ReadWrite))
1062    }
1063    /// Create a [`Dynamic`] from a [`Map`].
1064    #[cfg(not(feature = "no_object"))]
1065    #[inline(always)]
1066    pub fn from_map(map: Map) -> Self {
1067        Self(Union::Map(map.into(), DEFAULT_TAG_VALUE, ReadWrite))
1068    }
1069    /// Create a new [`Dynamic`] from an [`Instant`].
1070    ///
1071    /// Not available under `no-std` or `no_time`.
1072    #[cfg(not(feature = "no_time"))]
1073    #[inline(always)]
1074    pub fn from_timestamp(value: Instant) -> Self {
1075        Self(Union::TimeStamp(value.into(), DEFAULT_TAG_VALUE, ReadWrite))
1076    }
1077
1078    /// Get the [`AccessMode`] for this [`Dynamic`].
1079    #[must_use]
1080    pub(crate) const fn access_mode(&self) -> AccessMode {
1081        match self.0 {
1082            Union::Unit(.., access)
1083            | Union::Bool(.., access)
1084            | Union::Str(.., access)
1085            | Union::Char(.., access)
1086            | Union::Int(.., access)
1087            | Union::FnPtr(.., access)
1088            | Union::Variant(.., access) => access,
1089
1090            #[cfg(not(feature = "no_float"))]
1091            Union::Float(.., access) => access,
1092            #[cfg(feature = "decimal")]
1093            Union::Decimal(.., access) => access,
1094            #[cfg(not(feature = "no_index"))]
1095            Union::Array(.., access) | Union::Blob(.., access) => access,
1096            #[cfg(not(feature = "no_object"))]
1097            Union::Map(.., access) => access,
1098            #[cfg(not(feature = "no_time"))]
1099            Union::TimeStamp(.., access) => access,
1100            #[cfg(not(feature = "no_closure"))]
1101            Union::Shared(.., access) => access,
1102        }
1103    }
1104    /// Set the [`AccessMode`] for this [`Dynamic`].
1105    pub(crate) fn set_access_mode(&mut self, typ: AccessMode) -> &mut Self {
1106        match self.0 {
1107            Union::Unit(.., ref mut access)
1108            | Union::Bool(.., ref mut access)
1109            | Union::Str(.., ref mut access)
1110            | Union::Char(.., ref mut access)
1111            | Union::Int(.., ref mut access)
1112            | Union::FnPtr(.., ref mut access)
1113            | Union::Variant(.., ref mut access) => *access = typ,
1114
1115            #[cfg(not(feature = "no_float"))]
1116            Union::Float(.., ref mut access) => *access = typ,
1117            #[cfg(feature = "decimal")]
1118            Union::Decimal(.., ref mut access) => *access = typ,
1119            #[cfg(not(feature = "no_index"))]
1120            Union::Array(ref mut a, _, ref mut access) => {
1121                *access = typ;
1122                for v in a.as_mut() {
1123                    v.set_access_mode(typ);
1124                }
1125            }
1126            #[cfg(not(feature = "no_index"))]
1127            Union::Blob(.., ref mut access) => *access = typ,
1128            #[cfg(not(feature = "no_object"))]
1129            Union::Map(ref mut m, _, ref mut access) => {
1130                *access = typ;
1131                for v in m.values_mut() {
1132                    v.set_access_mode(typ);
1133                }
1134            }
1135            #[cfg(not(feature = "no_time"))]
1136            Union::TimeStamp(.., ref mut access) => *access = typ,
1137            #[cfg(not(feature = "no_closure"))]
1138            Union::Shared(.., ref mut access) => *access = typ,
1139        }
1140        self
1141    }
1142    /// Make this [`Dynamic`] read-only (i.e. a constant).
1143    #[inline(always)]
1144    pub fn into_read_only(self) -> Self {
1145        let mut value = self;
1146        value.set_access_mode(AccessMode::ReadOnly);
1147        value
1148    }
1149    /// Is this [`Dynamic`] read-only?
1150    ///
1151    /// Constant [`Dynamic`] values are read-only.
1152    ///
1153    /// # Usage
1154    ///
1155    /// If a [`&mut Dynamic`][Dynamic] to such a constant is passed to a Rust function, the function
1156    /// can use this information to return the error
1157    /// [`ErrorAssignmentToConstant`][crate::EvalAltResult::ErrorAssignmentToConstant] if its value
1158    /// will be modified.
1159    ///
1160    /// This safe-guards constant values from being modified within Rust functions.
1161    ///
1162    /// # Shared Value
1163    ///
1164    /// If a [`Dynamic`] holds a _shared_ value, then it is read-only only if the shared value
1165    /// itself is read-only.
1166    ///
1167    /// Under the `sync` feature, a _shared_ value may deadlock.
1168    /// Otherwise, the data may currently be borrowed for write (so its access mode cannot be determined).
1169    ///
1170    /// Under these circumstances, `false` is returned.
1171    ///
1172    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
1173    #[must_use]
1174    pub fn is_read_only(&self) -> bool {
1175        #[cfg(not(feature = "no_closure"))]
1176        if let Union::Shared(ref cell, ..) = self.0 {
1177            return match crate::func::locked_read(cell).map_or(ReadWrite, |v| v.access_mode()) {
1178                ReadWrite => false,
1179                ReadOnly => true,
1180            };
1181        }
1182
1183        match self.access_mode() {
1184            ReadWrite => false,
1185            ReadOnly => true,
1186        }
1187    }
1188    /// Can this [`Dynamic`] be hashed?
1189    ///
1190    /// # Shared Value
1191    ///
1192    /// If a [`Dynamic`] holds a _shared_ value, then it is hashable only if the shared value
1193    /// itself is hashable.
1194    ///
1195    /// Under the `sync` feature, a _shared_ value may deadlock.
1196    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
1197    ///
1198    /// Under these circumstances, `false` is returned.
1199    ///
1200    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
1201    #[must_use]
1202    pub(crate) fn is_hashable(&self) -> bool {
1203        match self.0 {
1204            Union::Unit(..)
1205            | Union::Bool(..)
1206            | Union::Str(..)
1207            | Union::Char(..)
1208            | Union::Int(..) => true,
1209
1210            #[cfg(not(feature = "no_float"))]
1211            Union::Float(..) => true,
1212            #[cfg(feature = "decimal")]
1213            Union::Decimal(..) => true,
1214            #[cfg(not(feature = "no_index"))]
1215            Union::Array(ref a, ..) => a.iter().all(Self::is_hashable),
1216            #[cfg(not(feature = "no_index"))]
1217            Union::Blob(..) => true,
1218            #[cfg(not(feature = "no_object"))]
1219            Union::Map(ref m, ..) => m.values().all(Self::is_hashable),
1220            #[cfg(not(feature = "no_function"))]
1221            Union::FnPtr(ref f, ..) if f.env.is_some() => false,
1222            Union::FnPtr(ref f, ..) => f.curry().iter().all(Self::is_hashable),
1223            #[cfg(not(feature = "no_time"))]
1224            Union::TimeStamp(..) => false,
1225
1226            Union::Variant(ref v, ..) => {
1227                let _value_any = (***v).as_any();
1228                let _type_id = _value_any.type_id();
1229
1230                #[cfg(not(feature = "only_i32"))]
1231                #[cfg(not(feature = "only_i64"))]
1232                if _type_id == TypeId::of::<u8>()
1233                    || _type_id == TypeId::of::<u16>()
1234                    || _type_id == TypeId::of::<u32>()
1235                    || _type_id == TypeId::of::<u64>()
1236                    || _type_id == TypeId::of::<i8>()
1237                    || _type_id == TypeId::of::<i16>()
1238                    || _type_id == TypeId::of::<i32>()
1239                    || _type_id == TypeId::of::<i64>()
1240                {
1241                    return true;
1242                }
1243
1244                #[cfg(not(feature = "no_float"))]
1245                #[cfg(not(feature = "f32_float"))]
1246                if _type_id == TypeId::of::<f32>() {
1247                    return true;
1248                }
1249                #[cfg(not(feature = "no_float"))]
1250                #[cfg(feature = "f32_float")]
1251                if _type_id == TypeId::of::<f64>() {
1252                    return true;
1253                }
1254
1255                #[cfg(not(feature = "only_i32"))]
1256                #[cfg(not(feature = "only_i64"))]
1257                #[cfg(not(target_family = "wasm"))]
1258                if _type_id == TypeId::of::<u128>() || _type_id == TypeId::of::<i128>() {
1259                    return true;
1260                }
1261
1262                if _type_id == TypeId::of::<ExclusiveRange>()
1263                    || _type_id == TypeId::of::<InclusiveRange>()
1264                {
1265                    return true;
1266                }
1267
1268                false
1269            }
1270
1271            #[cfg(not(feature = "no_closure"))]
1272            Union::Shared(ref cell, ..) if cfg!(feature = "unchecked") => {
1273                crate::func::locked_read(cell).map_or(false, |v| v.is_hashable())
1274            }
1275            #[cfg(not(feature = "no_closure"))]
1276            Union::Shared(..) => {
1277                #[cfg(feature = "no_std")]
1278                use hashbrown::HashSet;
1279                #[cfg(not(feature = "no_std"))]
1280                use std::collections::HashSet;
1281
1282                // Avoid infinite recursion for shared values in a reference loop.
1283                fn checked_is_hashable(
1284                    value: &Dynamic,
1285                    dict: &mut HashSet<*const Dynamic>,
1286                ) -> bool {
1287                    match value.0 {
1288                        Union::Shared(ref cell, ..) => crate::func::locked_read(cell)
1289                            .map_or(false, |v| {
1290                                dict.insert(value) && checked_is_hashable(&v, dict)
1291                            }),
1292                        #[cfg(not(feature = "no_index"))]
1293                        Union::Array(ref a, ..) => a.iter().all(|v| checked_is_hashable(v, dict)),
1294                        #[cfg(not(feature = "no_object"))]
1295                        Union::Map(ref m, ..) => m.values().all(|v| checked_is_hashable(v, dict)),
1296                        Union::FnPtr(ref f, ..) => {
1297                            f.env.is_none()
1298                                && f.curry().iter().all(|v| checked_is_hashable(v, dict))
1299                        }
1300                        _ => value.is_hashable(),
1301                    }
1302                }
1303
1304                checked_is_hashable(self, &mut <_>::default())
1305            }
1306        }
1307    }
1308    /// Create a [`Dynamic`] from any type.  A [`Dynamic`] value is simply returned as is.
1309    ///
1310    /// # Arrays
1311    ///
1312    /// Beware that you need to pass in an [`Array`] type for it to be recognized as
1313    /// an [`Array`]. A [`Vec<T>`][Vec] does not get automatically converted to an
1314    /// [`Array`], but will be a custom type instead (stored as a trait object).
1315    ///
1316    /// Use `array.into()` or `array.into_iter()` to convert a [`Vec<T>`][Vec] into a [`Dynamic`] as
1317    /// an [`Array`] value.  See the examples for details.
1318    ///
1319    /// # Hash Maps
1320    ///
1321    /// Similarly, passing in a [`HashMap<String, T>`][std::collections::HashMap] or
1322    /// [`BTreeMap<String, T>`][std::collections::BTreeMap] will not get a [`Map`] but a
1323    /// custom type.
1324    ///
1325    /// Again, use `map.into()` to get a [`Dynamic`] with a [`Map`] value.
1326    /// See the examples for details.
1327    ///
1328    /// # Examples
1329    ///
1330    /// ```
1331    /// use rhai::Dynamic;
1332    ///
1333    /// let result = Dynamic::from(42_i64);
1334    /// assert_eq!(result.type_name(), "i64");
1335    /// assert_eq!(result.to_string(), "42");
1336    ///
1337    /// let result = Dynamic::from("hello");
1338    /// assert_eq!(result.type_name(), "string");
1339    /// assert_eq!(result.to_string(), "hello");
1340    ///
1341    /// let new_result = Dynamic::from(result);
1342    /// assert_eq!(new_result.type_name(), "string");
1343    /// assert_eq!(new_result.to_string(), "hello");
1344    ///
1345    /// # #[cfg(not(feature = "no_index"))]
1346    /// # {
1347    /// // Arrays - this is a custom object!
1348    /// let result = Dynamic::from(vec![1_i64, 2, 3]);
1349    /// assert_eq!(result.type_name(), "alloc::vec::Vec<i64>");
1350    ///
1351    /// // Use '.into()' to convert a Vec<T> into an Array
1352    /// let result: Dynamic = vec![1_i64, 2, 3].into();
1353    /// assert_eq!(result.type_name(), "array");
1354    /// # }
1355    ///
1356    /// # #[cfg(not(feature = "no_object"))]
1357    /// # {
1358    /// # use std::collections::HashMap;
1359    /// // Hash map
1360    /// let mut map = HashMap::new();
1361    /// map.insert("a".to_string(), 1_i64);
1362    ///
1363    /// // This is a custom object!
1364    /// let result = Dynamic::from(map.clone());
1365    /// assert_eq!(result.type_name(), "std::collections::hash::map::HashMap<alloc::string::String, i64>");
1366    ///
1367    /// // Use '.into()' to convert a HashMap<String, T> into an object map
1368    /// let result: Dynamic = map.into();
1369    /// assert_eq!(result.type_name(), "map");
1370    /// # }
1371    /// ```
1372    #[inline]
1373    pub fn from<T: Variant + Clone>(value: T) -> Self {
1374        // Coded this way in order to maximally leverage potentials for dead-code removal.
1375
1376        reify! { value => |v: Self| return v }
1377        reify! { value => |v: INT| return v.into() }
1378
1379        #[cfg(not(feature = "no_float"))]
1380        reify! { value => |v: crate::FLOAT| return v.into() }
1381
1382        #[cfg(feature = "decimal")]
1383        reify! { value => |v: rust_decimal::Decimal| return v.into() }
1384
1385        reify! { value => |v: bool| return v.into() }
1386        reify! { value => |v: char| return v.into() }
1387        reify! { value => |v: ImmutableString| return v.into() }
1388        reify! { value => |v: String| return v.into() }
1389        reify! { value => |v: &str| return v.into() }
1390        reify! { value => |v: ()| return v.into() }
1391
1392        #[cfg(not(feature = "no_index"))]
1393        reify! { value => |v: Array| return v.into() }
1394        #[cfg(not(feature = "no_index"))]
1395        // don't use blob.into() because it'll be converted into an Array
1396        reify! { value => |v: Blob| return Self::from_blob(v) }
1397        #[cfg(not(feature = "no_object"))]
1398        reify! { value => |v: Map| return v.into() }
1399        reify! { value => |v: FnPtr| return v.into() }
1400
1401        #[cfg(not(feature = "no_time"))]
1402        reify! { value => |v: Instant| return v.into() }
1403        #[cfg(not(feature = "no_closure"))]
1404        reify! { value => |v: crate::Shared<crate::Locked<Self>>| return v.into() }
1405
1406        Self(Union::Variant(
1407            Box::new(Box::new(value)),
1408            DEFAULT_TAG_VALUE,
1409            ReadWrite,
1410        ))
1411    }
1412    /// Turn the [`Dynamic`] value into a shared [`Dynamic`] value backed by an
1413    /// [`Rc<RefCell<Dynamic>>`][std::rc::Rc] or [`Arc<RwLock<Dynamic>>`][std::sync::Arc]
1414    /// depending on the `sync` feature.
1415    ///
1416    /// Not available under `no_closure`.
1417    ///
1418    /// Shared [`Dynamic`] values are relatively cheap to clone as they simply increment the
1419    /// reference counts.
1420    ///
1421    /// Shared [`Dynamic`] values can be converted seamlessly to and from ordinary [`Dynamic`]
1422    /// values.
1423    ///
1424    /// If the [`Dynamic`] value is already shared, this method returns itself.
1425    #[cfg(not(feature = "no_closure"))]
1426    #[inline]
1427    pub fn into_shared(self) -> Self {
1428        let _access = self.access_mode();
1429
1430        match self.0 {
1431            Union::Shared(..) => self,
1432            _ => Self(Union::Shared(
1433                crate::Locked::new(self).into(),
1434                DEFAULT_TAG_VALUE,
1435                _access,
1436            )),
1437        }
1438    }
1439    /// Return this [`Dynamic`], replacing it with [`Dynamic::UNIT`].
1440    #[inline(always)]
1441    pub fn take(&mut self) -> Self {
1442        mem::take(self)
1443    }
1444    /// Convert the [`Dynamic`] value into specific type.
1445    ///
1446    /// Casting to a [`Dynamic`] simply returns itself.
1447    ///
1448    /// # Errors
1449    ///
1450    /// Returns [`None`] if types mismatch.
1451    ///
1452    /// # Shared Value
1453    ///
1454    /// If the [`Dynamic`] is a _shared_ value, it returns the shared value if there are no
1455    /// outstanding references, or a cloned copy otherwise.
1456    ///
1457    /// Under the `sync` feature, a _shared_ value may deadlock.
1458    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
1459    ///
1460    /// Under these circumstances, the cast also fails.
1461    ///
1462    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
1463    ///
1464    /// # Example
1465    ///
1466    /// ```
1467    /// use rhai::Dynamic;
1468    ///
1469    /// let x = Dynamic::from(42_u32);
1470    ///
1471    /// assert_eq!(x.try_cast::<u32>().expect("x should be u32"), 42);
1472    /// ```
1473    #[inline(always)]
1474    #[must_use]
1475    #[allow(unused_mut)]
1476    pub fn try_cast<T: Any>(mut self) -> Option<T> {
1477        self.try_cast_result().ok()
1478    }
1479    /// Convert the [`Dynamic`] value into specific type.
1480    ///
1481    /// Casting to a [`Dynamic`] simply returns itself.
1482    ///
1483    /// # Errors
1484    ///
1485    /// Returns itself as an error if types mismatch.
1486    ///
1487    /// # Shared Value
1488    ///
1489    /// If the [`Dynamic`] is a _shared_ value, it returns the shared value if there are no
1490    /// outstanding references, or a cloned copy otherwise.
1491    ///
1492    /// Under the `sync` feature, a _shared_ value may deadlock.
1493    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
1494    ///
1495    /// Under these circumstances, the cast also fails.
1496    ///
1497    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
1498    #[allow(unused_mut)]
1499    pub fn try_cast_result<T: Any>(mut self) -> Result<T, Self> {
1500        // Coded this way in order to maximally leverage potentials for dead-code removal.
1501
1502        #[cfg(not(feature = "no_closure"))]
1503        {
1504            self = self.flatten();
1505        }
1506
1507        if TypeId::of::<T>() == TypeId::of::<Self>() {
1508            return Ok(reify! { self => !!! T });
1509        }
1510        if TypeId::of::<T>() == TypeId::of::<()>() {
1511            return match self.0 {
1512                Union::Unit(..) => Ok(reify! { () => !!! T }),
1513                _ => Err(self),
1514            };
1515        }
1516        if TypeId::of::<T>() == TypeId::of::<INT>() {
1517            return match self.0 {
1518                Union::Int(n, ..) => Ok(reify! { n => !!! T }),
1519                _ => Err(self),
1520            };
1521        }
1522        #[cfg(not(feature = "no_float"))]
1523        if TypeId::of::<T>() == TypeId::of::<crate::FLOAT>() {
1524            return match self.0 {
1525                Union::Float(v, ..) => Ok(reify! { *v => !!! T }),
1526                _ => Err(self),
1527            };
1528        }
1529        #[cfg(feature = "decimal")]
1530        if TypeId::of::<T>() == TypeId::of::<rust_decimal::Decimal>() {
1531            return match self.0 {
1532                Union::Decimal(v, ..) => Ok(reify! { *v => !!! T }),
1533                _ => Err(self),
1534            };
1535        }
1536        if TypeId::of::<T>() == TypeId::of::<bool>() {
1537            return match self.0 {
1538                Union::Bool(b, ..) => Ok(reify! { b => !!! T }),
1539                _ => Err(self),
1540            };
1541        }
1542        if TypeId::of::<T>() == TypeId::of::<ImmutableString>() {
1543            return match self.0 {
1544                Union::Str(s, ..) => Ok(reify! { s => !!! T }),
1545                _ => Err(self),
1546            };
1547        }
1548        if TypeId::of::<T>() == TypeId::of::<String>() {
1549            return match self.0 {
1550                Union::Str(s, ..) => Ok(reify! { s.to_string() => !!! T }),
1551                _ => Err(self),
1552            };
1553        }
1554        if TypeId::of::<T>() == TypeId::of::<char>() {
1555            return match self.0 {
1556                Union::Char(c, ..) => Ok(reify! { c => !!! T }),
1557                _ => Err(self),
1558            };
1559        }
1560        #[cfg(not(feature = "no_index"))]
1561        if TypeId::of::<T>() == TypeId::of::<Array>() {
1562            return match self.0 {
1563                Union::Array(a, ..) => Ok(reify! { *a => !!! T }),
1564                _ => Err(self),
1565            };
1566        }
1567        #[cfg(not(feature = "no_index"))]
1568        if TypeId::of::<T>() == TypeId::of::<Blob>() {
1569            return match self.0 {
1570                Union::Blob(b, ..) => Ok(reify! { *b => !!! T }),
1571                _ => Err(self),
1572            };
1573        }
1574        #[cfg(not(feature = "no_object"))]
1575        if TypeId::of::<T>() == TypeId::of::<Map>() {
1576            return match self.0 {
1577                Union::Map(m, ..) => Ok(reify! { *m => !!! T }),
1578                _ => Err(self),
1579            };
1580        }
1581        if TypeId::of::<T>() == TypeId::of::<FnPtr>() {
1582            return match self.0 {
1583                Union::FnPtr(f, ..) => Ok(reify! { *f => !!! T }),
1584                _ => Err(self),
1585            };
1586        }
1587        #[cfg(not(feature = "no_time"))]
1588        if TypeId::of::<T>() == TypeId::of::<Instant>() {
1589            return match self.0 {
1590                Union::TimeStamp(t, ..) => Ok(reify! { *t => !!! T }),
1591                _ => Err(self),
1592            };
1593        }
1594
1595        match self.0 {
1596            Union::Variant(v, ..) if TypeId::of::<T>() == (**v).type_id() => {
1597                Ok((*v).as_boxed_any().downcast().map(|x| *x).unwrap())
1598            }
1599            _ => Err(self),
1600        }
1601    }
1602    /// Convert the [`Dynamic`] value into a specific type.
1603    ///
1604    /// Casting to a [`Dynamic`] just returns as is.
1605    ///
1606    /// # Panics
1607    ///
1608    /// Panics if the cast fails (e.g. the type of the actual value is not the same as the specified type).
1609    ///
1610    /// # Shared Value
1611    ///
1612    /// If the [`Dynamic`] is a _shared_ value, it returns the shared value if there are no
1613    /// outstanding references, or a cloned copy otherwise.
1614    ///
1615    /// Under the `sync` feature, a _shared_ value may deadlock.
1616    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
1617    ///
1618    /// Under these circumstances, the _shared_ value is simply cloned, which means that the returned
1619    /// value is also shared.
1620    ///
1621    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
1622    ///
1623    /// # Example
1624    ///
1625    /// ```
1626    /// use rhai::Dynamic;
1627    ///
1628    /// let x = Dynamic::from(42_u32);
1629    ///
1630    /// assert_eq!(x.cast::<u32>(), 42);
1631    /// ```
1632    #[inline]
1633    #[must_use]
1634    pub fn cast<T: Any + Clone>(self) -> T {
1635        // Bail out early if the return type needs no cast
1636        if TypeId::of::<T>() == TypeId::of::<Self>() {
1637            return reify! { self => !!! T };
1638        }
1639
1640        #[cfg(not(feature = "no_closure"))]
1641        let self_type_name = if self.is_shared() {
1642            // Avoid panics/deadlocks with shared values
1643            "<shared>"
1644        } else {
1645            self.type_name()
1646        };
1647        #[cfg(feature = "no_closure")]
1648        let self_type_name = self.type_name();
1649
1650        self.try_cast::<T>()
1651            .unwrap_or_else(|| panic!("cannot cast {} to {}", self_type_name, type_name::<T>()))
1652    }
1653    /// Clone the [`Dynamic`] value and convert it into a specific type.
1654    ///
1655    /// Casting to a [`Dynamic`] just returns as is.
1656    ///
1657    /// # Panics
1658    ///
1659    /// Panics if the cast fails (e.g. the type of the actual value is not the
1660    /// same as the specified type).
1661    ///
1662    /// # Shared Value
1663    ///
1664    /// If the [`Dynamic`] is a _shared_ value, a cloned copy of the shared value is returned.
1665    ///
1666    /// Under the `sync` feature, a _shared_ value may deadlock.
1667    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
1668    ///
1669    /// Under these circumstances, the _shared_ value is simply cloned.
1670    ///
1671    /// This normally shouldn't occur since most operations in Rhai are single-threaded.
1672    ///
1673    /// # Example
1674    ///
1675    /// ```
1676    /// use rhai::Dynamic;
1677    ///
1678    /// let x = Dynamic::from(42_u32);
1679    /// let y = &x;
1680    ///
1681    /// assert_eq!(y.clone_cast::<u32>(), 42);
1682    /// ```
1683    #[inline(always)]
1684    #[must_use]
1685    pub fn clone_cast<T: Any + Clone>(&self) -> T {
1686        self.flatten_clone().cast::<T>()
1687    }
1688    /// Flatten the [`Dynamic`] and clone it.
1689    ///
1690    /// If the [`Dynamic`] is not a _shared_ value, a cloned copy is returned.
1691    ///
1692    /// If the [`Dynamic`] is a _shared_ value, a cloned copy of the shared value is returned.
1693    ///
1694    /// # Shared Value
1695    ///
1696    /// Under the `sync` feature, a _shared_ value may deadlock.
1697    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
1698    ///
1699    /// Under these circumstances, the _shared_ value is simply cloned.
1700    ///
1701    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
1702    #[inline]
1703    pub fn flatten_clone(&self) -> Self {
1704        match self.0 {
1705            #[cfg(not(feature = "no_closure"))]
1706            Union::Shared(ref cell, ..) => {
1707                crate::func::locked_read(cell).map_or_else(|| self.clone(), |v| v.flatten_clone())
1708            }
1709            _ => self.clone(),
1710        }
1711    }
1712    /// Flatten the [`Dynamic`].
1713    ///
1714    /// If the [`Dynamic`] is not a _shared_ value, it simply returns itself.
1715    ///
1716    /// If the [`Dynamic`] is a _shared_ value, it returns the shared value if there are no
1717    /// outstanding references, or a cloned copy otherwise.
1718    ///
1719    /// # Shared Value
1720    ///
1721    /// Under the `sync` feature, a _shared_ value may deadlock.
1722    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
1723    ///
1724    /// Under these circumstances, the _shared_ value is simply cloned, meaning that the result
1725    /// value will also be _shared_.
1726    ///
1727    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
1728    #[inline]
1729    pub fn flatten(self) -> Self {
1730        match self.0 {
1731            #[cfg(not(feature = "no_closure"))]
1732            Union::Shared(cell, tag, access) => match crate::func::native::shared_try_take(cell) {
1733                // If there are no outstanding references, consume the shared value and return it
1734                #[cfg(not(feature = "sync"))]
1735                Ok(value) => value.into_inner().flatten(),
1736                #[cfg(feature = "sync")]
1737                #[cfg(not(feature = "no_std"))]
1738                Ok(value) => value.into_inner().unwrap().flatten(),
1739                #[cfg(feature = "sync")]
1740                #[cfg(feature = "no_std")]
1741                Ok(value) => value.into_inner().flatten(),
1742                // If there are outstanding references, return a cloned copy
1743                Err(cell) => {
1744                    if let Some(guard) = crate::func::locked_read(&cell) {
1745                        return guard.flatten_clone();
1746                    }
1747                    Self(Union::Shared(cell, tag, access))
1748                }
1749            },
1750            _ => self,
1751        }
1752    }
1753    /// Is the [`Dynamic`] a _shared_ value that is locked?
1754    ///
1755    /// Not available under `no_closure`.
1756    ///
1757    /// ## Note
1758    ///
1759    /// Under the `sync` feature, shared values use [`RwLock`][std::sync::RwLock] and they are never locked.
1760    /// Access just waits until the [`RwLock`][std::sync::RwLock] is released.
1761    /// So this method always returns [`false`] under [`Sync`].
1762    #[cfg(not(feature = "no_closure"))]
1763    #[inline]
1764    #[must_use]
1765    pub fn is_locked(&self) -> bool {
1766        #[cfg(not(feature = "no_closure"))]
1767        if let Union::Shared(ref _cell, ..) = self.0 {
1768            #[cfg(not(feature = "sync"))]
1769            return _cell.try_borrow().is_err();
1770            #[cfg(feature = "sync")]
1771            return false;
1772        }
1773
1774        false
1775    }
1776    /// Get a reference of a specific type to the [`Dynamic`].
1777    ///
1778    /// Casting to [`Dynamic`] just returns a reference to it.
1779    ///
1780    /// Returns [`None`] if the cast fails.
1781    ///
1782    /// # Shared Value
1783    ///
1784    /// Under the `sync` feature, a _shared_ value may deadlock.
1785    /// Otherwise, this call also fails if the data is currently borrowed for write.
1786    ///
1787    /// Under these circumstances, [`None`] is also returned.
1788    ///
1789    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
1790    #[inline]
1791    pub fn read_lock<T: Any + Clone>(&self) -> Option<DynamicReadLock<T>> {
1792        match self.0 {
1793            #[cfg(not(feature = "no_closure"))]
1794            Union::Shared(ref cell, ..) => {
1795                return match crate::func::locked_read(cell) {
1796                    Some(guard)
1797                        if TypeId::of::<Self>() == TypeId::of::<T>()
1798                            || (*guard).type_id() == TypeId::of::<T>() =>
1799                    {
1800                        Some(DynamicReadLock(DynamicReadLockInner::Guard(guard)))
1801                    }
1802                    _ => None,
1803                };
1804            }
1805            _ => (),
1806        }
1807
1808        self.downcast_ref()
1809            .map(DynamicReadLockInner::Reference)
1810            .map(DynamicReadLock)
1811    }
1812    /// Get a mutable reference of a specific type to the [`Dynamic`].
1813    ///
1814    /// Casting to [`Dynamic`] just returns a mutable reference to it.
1815    ///
1816    /// Returns [`None`] if the cast fails.
1817    ///
1818    /// # Shared Value
1819    ///
1820    /// Under the `sync` feature, a _shared_ value may deadlock.
1821    /// Otherwise, this call also fails if the data is currently borrowed for write.
1822    ///
1823    /// Under these circumstances, [`None`] is also returned.
1824    ///
1825    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
1826    #[inline]
1827    pub fn write_lock<T: Any + Clone>(&mut self) -> Option<DynamicWriteLock<T>> {
1828        match self.0 {
1829            #[cfg(not(feature = "no_closure"))]
1830            Union::Shared(ref cell, ..) => {
1831                return match crate::func::locked_write(cell) {
1832                    Some(guard)
1833                        if TypeId::of::<Self>() == TypeId::of::<T>()
1834                            || (*guard).type_id() == TypeId::of::<T>() =>
1835                    {
1836                        Some(DynamicWriteLock(DynamicWriteLockInner::Guard(guard)))
1837                    }
1838                    _ => None,
1839                };
1840            }
1841            _ => (),
1842        }
1843
1844        self.downcast_mut()
1845            .map(DynamicWriteLockInner::Reference)
1846            .map(DynamicWriteLock)
1847    }
1848    /// Get a reference of a specific type to the [`Dynamic`].
1849    ///
1850    /// Casting to [`Dynamic`] just returns a reference to it.
1851    ///
1852    /// Returns [`None`] if the cast fails.
1853    ///
1854    /// # Shared Value
1855    ///
1856    /// Returns [`None`] also if the value is _shared_.
1857    #[inline]
1858    #[must_use]
1859    pub(crate) fn downcast_ref<T: Any + Clone + ?Sized>(&self) -> Option<&T> {
1860        // Coded this way in order to maximally leverage potentials for dead-code removal.
1861
1862        if TypeId::of::<T>() == TypeId::of::<INT>() {
1863            return match self.0 {
1864                Union::Int(ref v, ..) => v.as_any().downcast_ref::<T>(),
1865                _ => None,
1866            };
1867        }
1868        #[cfg(not(feature = "no_float"))]
1869        if TypeId::of::<T>() == TypeId::of::<crate::FLOAT>() {
1870            return match self.0 {
1871                Union::Float(ref v, ..) => v.as_ref().as_any().downcast_ref::<T>(),
1872                _ => None,
1873            };
1874        }
1875        #[cfg(feature = "decimal")]
1876        if TypeId::of::<T>() == TypeId::of::<rust_decimal::Decimal>() {
1877            return match self.0 {
1878                Union::Decimal(ref v, ..) => v.as_ref().as_any().downcast_ref::<T>(),
1879                _ => None,
1880            };
1881        }
1882        if TypeId::of::<T>() == TypeId::of::<bool>() {
1883            return match self.0 {
1884                Union::Bool(ref v, ..) => v.as_any().downcast_ref::<T>(),
1885                _ => None,
1886            };
1887        }
1888        if TypeId::of::<T>() == TypeId::of::<ImmutableString>() {
1889            return match self.0 {
1890                Union::Str(ref v, ..) => v.as_any().downcast_ref::<T>(),
1891                _ => None,
1892            };
1893        }
1894        if TypeId::of::<T>() == TypeId::of::<char>() {
1895            return match self.0 {
1896                Union::Char(ref v, ..) => v.as_any().downcast_ref::<T>(),
1897                _ => None,
1898            };
1899        }
1900        #[cfg(not(feature = "no_index"))]
1901        if TypeId::of::<T>() == TypeId::of::<Array>() {
1902            return match self.0 {
1903                Union::Array(ref v, ..) => v.as_ref().as_any().downcast_ref::<T>(),
1904                _ => None,
1905            };
1906        }
1907        #[cfg(not(feature = "no_index"))]
1908        if TypeId::of::<T>() == TypeId::of::<Blob>() {
1909            return match self.0 {
1910                Union::Blob(ref v, ..) => v.as_ref().as_any().downcast_ref::<T>(),
1911                _ => None,
1912            };
1913        }
1914        #[cfg(not(feature = "no_object"))]
1915        if TypeId::of::<T>() == TypeId::of::<Map>() {
1916            return match self.0 {
1917                Union::Map(ref v, ..) => v.as_ref().as_any().downcast_ref::<T>(),
1918                _ => None,
1919            };
1920        }
1921        if TypeId::of::<T>() == TypeId::of::<FnPtr>() {
1922            return match self.0 {
1923                Union::FnPtr(ref v, ..) => v.as_ref().as_any().downcast_ref::<T>(),
1924                _ => None,
1925            };
1926        }
1927        #[cfg(not(feature = "no_time"))]
1928        if TypeId::of::<T>() == TypeId::of::<Instant>() {
1929            return match self.0 {
1930                Union::TimeStamp(ref v, ..) => v.as_ref().as_any().downcast_ref::<T>(),
1931                _ => None,
1932            };
1933        }
1934        if TypeId::of::<T>() == TypeId::of::<()>() {
1935            return match self.0 {
1936                Union::Unit(ref v, ..) => v.as_any().downcast_ref::<T>(),
1937                _ => None,
1938            };
1939        }
1940        if TypeId::of::<T>() == TypeId::of::<Self>() {
1941            return self.as_any().downcast_ref::<T>();
1942        }
1943
1944        match self.0 {
1945            Union::Variant(ref v, ..) => (***v).as_any().downcast_ref::<T>(),
1946            #[cfg(not(feature = "no_closure"))]
1947            Union::Shared(..) => None,
1948            _ => None,
1949        }
1950    }
1951    /// Get a mutable reference of a specific type to the [`Dynamic`].
1952    ///
1953    /// Casting to [`Dynamic`] just returns a mutable reference to it.
1954    ///
1955    /// Returns [`None`] if the cast fails.
1956    ///
1957    /// # Shared Value
1958    ///
1959    /// Returns [`None`] also if the value is _shared_.
1960    #[inline]
1961    #[must_use]
1962    pub(crate) fn downcast_mut<T: Any + Clone + ?Sized>(&mut self) -> Option<&mut T> {
1963        // Coded this way in order to maximally leverage potentials for dead-code removal.
1964
1965        if TypeId::of::<T>() == TypeId::of::<INT>() {
1966            return match self.0 {
1967                Union::Int(ref mut v, ..) => v.as_any_mut().downcast_mut::<T>(),
1968                _ => None,
1969            };
1970        }
1971        #[cfg(not(feature = "no_float"))]
1972        if TypeId::of::<T>() == TypeId::of::<crate::FLOAT>() {
1973            return match self.0 {
1974                Union::Float(ref mut v, ..) => v.as_mut().as_any_mut().downcast_mut::<T>(),
1975                _ => None,
1976            };
1977        }
1978        #[cfg(feature = "decimal")]
1979        if TypeId::of::<T>() == TypeId::of::<rust_decimal::Decimal>() {
1980            return match self.0 {
1981                Union::Decimal(ref mut v, ..) => v.as_mut().as_any_mut().downcast_mut::<T>(),
1982                _ => None,
1983            };
1984        }
1985        if TypeId::of::<T>() == TypeId::of::<bool>() {
1986            return match self.0 {
1987                Union::Bool(ref mut v, ..) => v.as_any_mut().downcast_mut::<T>(),
1988                _ => None,
1989            };
1990        }
1991        if TypeId::of::<T>() == TypeId::of::<ImmutableString>() {
1992            return match self.0 {
1993                Union::Str(ref mut v, ..) => v.as_any_mut().downcast_mut::<T>(),
1994                _ => None,
1995            };
1996        }
1997        if TypeId::of::<T>() == TypeId::of::<char>() {
1998            return match self.0 {
1999                Union::Char(ref mut v, ..) => v.as_any_mut().downcast_mut::<T>(),
2000                _ => None,
2001            };
2002        }
2003        #[cfg(not(feature = "no_index"))]
2004        if TypeId::of::<T>() == TypeId::of::<Array>() {
2005            return match self.0 {
2006                Union::Array(ref mut v, ..) => v.as_mut().as_any_mut().downcast_mut::<T>(),
2007                _ => None,
2008            };
2009        }
2010        #[cfg(not(feature = "no_index"))]
2011        if TypeId::of::<T>() == TypeId::of::<Blob>() {
2012            return match self.0 {
2013                Union::Blob(ref mut v, ..) => v.as_mut().as_any_mut().downcast_mut::<T>(),
2014                _ => None,
2015            };
2016        }
2017        #[cfg(not(feature = "no_object"))]
2018        if TypeId::of::<T>() == TypeId::of::<Map>() {
2019            return match self.0 {
2020                Union::Map(ref mut v, ..) => v.as_mut().as_any_mut().downcast_mut::<T>(),
2021                _ => None,
2022            };
2023        }
2024        if TypeId::of::<T>() == TypeId::of::<FnPtr>() {
2025            return match self.0 {
2026                Union::FnPtr(ref mut v, ..) => v.as_mut().as_any_mut().downcast_mut::<T>(),
2027                _ => None,
2028            };
2029        }
2030        #[cfg(not(feature = "no_time"))]
2031        if TypeId::of::<T>() == TypeId::of::<Instant>() {
2032            return match self.0 {
2033                Union::TimeStamp(ref mut v, ..) => v.as_mut().as_any_mut().downcast_mut::<T>(),
2034                _ => None,
2035            };
2036        }
2037        if TypeId::of::<T>() == TypeId::of::<()>() {
2038            return match self.0 {
2039                Union::Unit(ref mut v, ..) => v.as_any_mut().downcast_mut::<T>(),
2040                _ => None,
2041            };
2042        }
2043        if TypeId::of::<T>() == TypeId::of::<Self>() {
2044            return self.as_any_mut().downcast_mut::<T>();
2045        }
2046
2047        match self.0 {
2048            Union::Variant(ref mut v, ..) => (***v).as_any_mut().downcast_mut::<T>(),
2049            #[cfg(not(feature = "no_closure"))]
2050            Union::Shared(..) => None,
2051            _ => None,
2052        }
2053    }
2054
2055    /// Return `true` if the [`Dynamic`] holds a `()`.
2056    ///
2057    /// # Shared Value
2058    ///
2059    /// Under the `sync` feature, a _shared_ value may deadlock.
2060    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2061    ///
2062    /// Under these circumstances, `false` is returned.
2063    ///
2064    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2065    #[inline]
2066    #[must_use]
2067    pub fn is_unit(&self) -> bool {
2068        match self.0 {
2069            Union::Unit(..) => true,
2070            #[cfg(not(feature = "no_closure"))]
2071            Union::Shared(ref cell, ..) => {
2072                crate::func::locked_read(cell).map_or(false, |v| matches!(v.0, Union::Unit(..)))
2073            }
2074            _ => false,
2075        }
2076    }
2077    /// Return `true` if the [`Dynamic`] holds the system integer type [`INT`].
2078    ///
2079    /// # Shared Value
2080    ///
2081    /// Under the `sync` feature, a _shared_ value may deadlock.
2082    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2083    ///
2084    /// Under these circumstances, `false` is returned.
2085    ///
2086    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2087    #[inline]
2088    #[must_use]
2089    pub fn is_int(&self) -> bool {
2090        match self.0 {
2091            Union::Int(..) => true,
2092            #[cfg(not(feature = "no_closure"))]
2093            Union::Shared(ref cell, ..) => {
2094                crate::func::locked_read(cell).map_or(false, |v| matches!(v.0, Union::Int(..)))
2095            }
2096            _ => false,
2097        }
2098    }
2099    /// Return `true` if the [`Dynamic`] holds the system floating-point type [`FLOAT`][crate::FLOAT].
2100    ///
2101    /// Not available under `no_float`.
2102    ///
2103    /// # Shared Value
2104    ///
2105    /// Under the `sync` feature, a _shared_ value may deadlock.
2106    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2107    ///
2108    /// Under these circumstances, `false` is returned.
2109    ///
2110    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2111    #[cfg(not(feature = "no_float"))]
2112    #[inline]
2113    #[must_use]
2114    pub fn is_float(&self) -> bool {
2115        match self.0 {
2116            Union::Float(..) => true,
2117            #[cfg(not(feature = "no_closure"))]
2118            Union::Shared(ref cell, ..) => {
2119                crate::func::locked_read(cell).map_or(false, |v| matches!(v.0, Union::Float(..)))
2120            }
2121            _ => false,
2122        }
2123    }
2124    /// _(decimal)_ Return `true` if the [`Dynamic`] holds a [`Decimal`][rust_decimal::Decimal].
2125    /// Exported under the `decimal` feature only.
2126    ///
2127    /// # Shared Value
2128    ///
2129    /// Under the `sync` feature, a _shared_ value may deadlock.
2130    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2131    ///
2132    /// Under these circumstances, `false` is returned.
2133    ///
2134    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2135    #[cfg(feature = "decimal")]
2136    #[inline]
2137    #[must_use]
2138    pub fn is_decimal(&self) -> bool {
2139        match self.0 {
2140            Union::Decimal(..) => true,
2141            #[cfg(not(feature = "no_closure"))]
2142            Union::Shared(ref cell, ..) => {
2143                crate::func::locked_read(cell).map_or(false, |v| matches!(v.0, Union::Decimal(..)))
2144            }
2145            _ => false,
2146        }
2147    }
2148    /// Return `true` if the [`Dynamic`] holds a [`bool`].
2149    ///
2150    /// # Shared Value
2151    ///
2152    /// Under the `sync` feature, a _shared_ value may deadlock.
2153    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2154    ///
2155    /// Under these circumstances, `false` is returned.
2156    ///
2157    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2158    #[inline]
2159    #[must_use]
2160    pub fn is_bool(&self) -> bool {
2161        match self.0 {
2162            Union::Bool(..) => true,
2163            #[cfg(not(feature = "no_closure"))]
2164            Union::Shared(ref cell, ..) => {
2165                crate::func::locked_read(cell).map_or(false, |v| matches!(v.0, Union::Bool(..)))
2166            }
2167            _ => false,
2168        }
2169    }
2170    /// Return `true` if the [`Dynamic`] holds a [`char`].
2171    ///
2172    /// # Shared Value
2173    ///
2174    /// Under the `sync` feature, a _shared_ value may deadlock.
2175    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2176    ///
2177    /// Under these circumstances, `false` is returned.
2178    ///
2179    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2180    #[inline]
2181    #[must_use]
2182    pub fn is_char(&self) -> bool {
2183        match self.0 {
2184            Union::Char(..) => true,
2185            #[cfg(not(feature = "no_closure"))]
2186            Union::Shared(ref cell, ..) => {
2187                crate::func::locked_read(cell).map_or(false, |v| matches!(v.0, Union::Char(..)))
2188            }
2189            _ => false,
2190        }
2191    }
2192    /// Return `true` if the [`Dynamic`] holds an [`ImmutableString`].
2193    ///
2194    /// # Shared Value
2195    ///
2196    /// Under the `sync` feature, a _shared_ value may deadlock.
2197    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2198    ///
2199    /// Under these circumstances, `false` is returned.
2200    ///
2201    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2202    #[inline]
2203    #[must_use]
2204    pub fn is_string(&self) -> bool {
2205        match self.0 {
2206            Union::Str(..) => true,
2207            #[cfg(not(feature = "no_closure"))]
2208            Union::Shared(ref cell, ..) => {
2209                crate::func::locked_read(cell).map_or(false, |v| matches!(v.0, Union::Str(..)))
2210            }
2211            _ => false,
2212        }
2213    }
2214    /// Return `true` if the [`Dynamic`] holds an [`Array`].
2215    ///
2216    /// Not available under `no_index`.
2217    ///
2218    /// # Shared Value
2219    ///
2220    /// Under the `sync` feature, a _shared_ value may deadlock.
2221    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2222    ///
2223    /// Under these circumstances, `false` is returned.
2224    ///
2225    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2226    #[cfg(not(feature = "no_index"))]
2227    #[inline]
2228    #[must_use]
2229    pub fn is_array(&self) -> bool {
2230        match self.0 {
2231            Union::Array(..) => true,
2232            #[cfg(not(feature = "no_closure"))]
2233            Union::Shared(ref cell, ..) => {
2234                crate::func::locked_read(cell).map_or(false, |v| matches!(v.0, Union::Array(..)))
2235            }
2236            _ => false,
2237        }
2238    }
2239    /// Return `true` if the [`Dynamic`] holds a [`Blob`].
2240    ///
2241    /// Not available under `no_index`.
2242    ///
2243    /// # Shared Value
2244    ///
2245    /// Under the `sync` feature, a _shared_ value may deadlock.
2246    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2247    ///
2248    /// Under these circumstances, `false` is returned.
2249    ///
2250    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2251    #[cfg(not(feature = "no_index"))]
2252    #[inline]
2253    #[must_use]
2254    pub fn is_blob(&self) -> bool {
2255        match self.0 {
2256            Union::Blob(..) => true,
2257            #[cfg(not(feature = "no_closure"))]
2258            Union::Shared(ref cell, ..) => {
2259                crate::func::locked_read(cell).map_or(false, |v| matches!(v.0, Union::Blob(..)))
2260            }
2261            _ => false,
2262        }
2263    }
2264    /// Return `true` if the [`Dynamic`] holds a [`Map`].
2265    ///
2266    /// Not available under `no_object`.
2267    ///
2268    /// # Shared Value
2269    ///
2270    /// Under the `sync` feature, a _shared_ value may deadlock.
2271    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2272    ///
2273    /// Under these circumstances, `false` is returned.
2274    ///
2275    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2276    #[cfg(not(feature = "no_object"))]
2277    #[inline]
2278    #[must_use]
2279    pub fn is_map(&self) -> bool {
2280        match self.0 {
2281            Union::Map(..) => true,
2282            #[cfg(not(feature = "no_closure"))]
2283            Union::Shared(ref cell, ..) => {
2284                crate::func::locked_read(cell).map_or(false, |v| matches!(v.0, Union::Map(..)))
2285            }
2286            _ => false,
2287        }
2288    }
2289    /// Return `true` if the [`Dynamic`] holds a [`FnPtr`].
2290    ///
2291    /// # Shared Value
2292    ///
2293    /// Under the `sync` feature, a _shared_ value may deadlock.
2294    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2295    ///
2296    /// Under these circumstances, `false` is returned.
2297    ///
2298    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2299    #[inline]
2300    #[must_use]
2301    pub fn is_fnptr(&self) -> bool {
2302        match self.0 {
2303            Union::FnPtr(..) => true,
2304            #[cfg(not(feature = "no_closure"))]
2305            Union::Shared(ref cell, ..) => {
2306                crate::func::locked_read(cell).map_or(false, |v| matches!(v.0, Union::FnPtr(..)))
2307            }
2308            _ => false,
2309        }
2310    }
2311    /// Return `true` if the [`Dynamic`] holds a [timestamp][Instant].
2312    ///
2313    /// Not available under `no_time`.
2314    ///
2315    /// # Shared Value
2316    ///
2317    /// Under the `sync` feature, a _shared_ value may deadlock.
2318    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2319    ///
2320    /// Under these circumstances, `false` is returned.
2321    ///
2322    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2323    #[cfg(not(feature = "no_time"))]
2324    #[inline]
2325    #[must_use]
2326    pub fn is_timestamp(&self) -> bool {
2327        match self.0 {
2328            Union::TimeStamp(..) => true,
2329            #[cfg(not(feature = "no_closure"))]
2330            Union::Shared(ref cell, ..) => crate::func::locked_read(cell)
2331                .map_or(false, |v| matches!(v.0, Union::TimeStamp(..))),
2332            _ => false,
2333        }
2334    }
2335
2336    /// Cast the [`Dynamic`] as a unit `()`.
2337    ///
2338    /// # Errors
2339    ///
2340    /// Returns the name of the actual type as an error if the cast fails.
2341    ///
2342    /// # Shared Value
2343    ///
2344    /// Under the `sync` feature, a _shared_ value may deadlock.
2345    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2346    ///
2347    /// Under these circumstances, the cast also fails.
2348    ///
2349    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2350    #[inline]
2351    pub fn as_unit(&self) -> Result<(), &'static str> {
2352        match self.0 {
2353            Union::Unit(..) => Ok(()),
2354            #[cfg(not(feature = "no_closure"))]
2355            Union::Shared(ref cell, ..) => crate::func::locked_read(cell)
2356                .and_then(|guard| match guard.0 {
2357                    Union::Unit(..) => Some(()),
2358                    _ => None,
2359                })
2360                .ok_or_else(|| cell.type_name()),
2361            _ => Err(self.type_name()),
2362        }
2363    }
2364    /// Cast the [`Dynamic`] as the system integer type [`INT`].
2365    ///
2366    /// # Errors
2367    ///
2368    /// Returns the name of the actual type as an error if the cast fails.
2369    ///
2370    /// # Shared Value
2371    ///
2372    /// Under the `sync` feature, a _shared_ value may deadlock.
2373    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2374    ///
2375    /// Under these circumstances, the cast also fails.
2376    ///
2377    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2378    #[inline]
2379    pub fn as_int(&self) -> Result<INT, &'static str> {
2380        match self.0 {
2381            Union::Int(n, ..) => Ok(n),
2382            #[cfg(not(feature = "no_closure"))]
2383            Union::Shared(ref cell, ..) => crate::func::locked_read(cell)
2384                .and_then(|guard| match guard.0 {
2385                    Union::Int(n, ..) => Some(n),
2386                    _ => None,
2387                })
2388                .ok_or_else(|| cell.type_name()),
2389            _ => Err(self.type_name()),
2390        }
2391    }
2392    /// Cast the [`Dynamic`] as the system floating-point type [`FLOAT`][crate::FLOAT].
2393    ///
2394    /// Not available under `no_float`.
2395    ///
2396    /// # Errors
2397    ///
2398    /// Returns the name of the actual type as an error if the cast fails.
2399    ///
2400    /// # Shared Value
2401    ///
2402    /// Under the `sync` feature, a _shared_ value may deadlock.
2403    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2404    ///
2405    /// Under these circumstances, the cast also fails.
2406    ///
2407    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2408    #[cfg(not(feature = "no_float"))]
2409    #[inline]
2410    pub fn as_float(&self) -> Result<crate::FLOAT, &'static str> {
2411        match self.0 {
2412            Union::Float(n, ..) => Ok(*n),
2413            #[cfg(not(feature = "no_closure"))]
2414            Union::Shared(ref cell, ..) => crate::func::locked_read(cell)
2415                .and_then(|guard| match guard.0 {
2416                    Union::Float(n, ..) => Some(*n),
2417                    _ => None,
2418                })
2419                .ok_or_else(|| cell.type_name()),
2420            _ => Err(self.type_name()),
2421        }
2422    }
2423    /// _(decimal)_ Cast the [`Dynamic`] as a [`Decimal`][rust_decimal::Decimal].
2424    /// Exported under the `decimal` feature only.
2425    ///
2426    /// # Errors
2427    ///
2428    /// Returns the name of the actual type as an error if the cast fails.
2429    ///
2430    /// # Shared Value
2431    ///
2432    /// Under the `sync` feature, a _shared_ value may deadlock.
2433    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2434    ///
2435    /// Under these circumstances, the cast also fails.
2436    ///
2437    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2438    #[cfg(feature = "decimal")]
2439    #[inline]
2440    pub fn as_decimal(&self) -> Result<rust_decimal::Decimal, &'static str> {
2441        match self.0 {
2442            Union::Decimal(ref n, ..) => Ok(**n),
2443            #[cfg(not(feature = "no_closure"))]
2444            Union::Shared(ref cell, ..) => crate::func::locked_read(cell)
2445                .and_then(|guard| match guard.0 {
2446                    Union::Decimal(ref n, ..) => Some(**n),
2447                    _ => None,
2448                })
2449                .ok_or_else(|| cell.type_name()),
2450            _ => Err(self.type_name()),
2451        }
2452    }
2453    /// Cast the [`Dynamic`] as a [`bool`].
2454    ///
2455    /// # Errors
2456    ///
2457    /// Returns the name of the actual type as an error if the cast fails.
2458    ///
2459    /// # Shared Value
2460    ///
2461    /// Under the `sync` feature, a _shared_ value may deadlock.
2462    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2463    ///
2464    /// Under these circumstances, the cast also fails.
2465    ///
2466    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2467    #[inline]
2468    pub fn as_bool(&self) -> Result<bool, &'static str> {
2469        match self.0 {
2470            Union::Bool(b, ..) => Ok(b),
2471            #[cfg(not(feature = "no_closure"))]
2472            Union::Shared(ref cell, ..) => crate::func::locked_read(cell)
2473                .and_then(|guard| match guard.0 {
2474                    Union::Bool(b, ..) => Some(b),
2475                    _ => None,
2476                })
2477                .ok_or_else(|| cell.type_name()),
2478            _ => Err(self.type_name()),
2479        }
2480    }
2481    /// Cast the [`Dynamic`] as a [`char`].
2482    ///
2483    /// # Errors
2484    ///
2485    /// Returns the name of the actual type as an error if the cast fails.
2486    ///
2487    /// # Shared Value
2488    ///
2489    /// Under the `sync` feature, a _shared_ value may deadlock.
2490    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2491    ///
2492    /// Under these circumstances, the cast also fails.
2493    ///
2494    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2495    #[inline]
2496    pub fn as_char(&self) -> Result<char, &'static str> {
2497        match self.0 {
2498            Union::Char(c, ..) => Ok(c),
2499            #[cfg(not(feature = "no_closure"))]
2500            Union::Shared(ref cell, ..) => crate::func::locked_read(cell)
2501                .and_then(|guard| match guard.0 {
2502                    Union::Char(c, ..) => Some(c),
2503                    _ => None,
2504                })
2505                .ok_or_else(|| cell.type_name()),
2506            _ => Err(self.type_name()),
2507        }
2508    }
2509    /// Cast the [`Dynamic`] as an [`ImmutableString`].
2510    ///
2511    /// # Errors
2512    ///
2513    /// Returns the name of the actual type as an error if the cast fails.
2514    ///
2515    /// # Shared Value
2516    ///
2517    /// Under the `sync` feature, a _shared_ value may deadlock.
2518    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2519    ///
2520    /// Under these circumstances, the cast also fails.
2521    ///
2522    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2523    #[inline]
2524    pub fn as_immutable_string_ref(
2525        &self,
2526    ) -> Result<impl Deref<Target = ImmutableString> + '_, &'static str> {
2527        self.read_lock::<ImmutableString>()
2528            .ok_or_else(|| self.type_name())
2529    }
2530    /// Cast the [`Dynamic`] as a mutable reference to an [`ImmutableString`].
2531    ///
2532    /// # Errors
2533    ///
2534    /// Returns the name of the actual type as an error if the cast fails.
2535    ///
2536    /// # Shared Value
2537    ///
2538    /// Under the `sync` feature, a _shared_ value may deadlock.
2539    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2540    ///
2541    /// Under these circumstances, the cast also fails.
2542    ///
2543    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2544    #[inline]
2545    pub fn as_immutable_string_mut(
2546        &mut self,
2547    ) -> Result<impl DerefMut<Target = ImmutableString> + '_, &'static str> {
2548        let type_name = self.type_name();
2549        self.write_lock::<ImmutableString>().ok_or(type_name)
2550    }
2551    /// Cast the [`Dynamic`] as an [`Array`].
2552    ///
2553    /// Not available under `no_index`.
2554    ///
2555    /// # Errors
2556    ///
2557    /// Returns the name of the actual type as an error if the cast fails.
2558    ///
2559    /// # Shared Value
2560    ///
2561    /// Under the `sync` feature, a _shared_ value may deadlock.
2562    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2563    ///
2564    /// Under these circumstances, the cast also fails.
2565    ///
2566    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2567    #[cfg(not(feature = "no_index"))]
2568    #[inline(always)]
2569    pub fn as_array_ref(&self) -> Result<impl Deref<Target = Array> + '_, &'static str> {
2570        self.read_lock::<Array>().ok_or_else(|| self.type_name())
2571    }
2572    /// Cast the [`Dynamic`] as a mutable reference to an [`Array`].
2573    ///
2574    /// Not available under `no_index`.
2575    ///
2576    /// # Errors
2577    ///
2578    /// Returns the name of the actual type as an error if the cast fails.
2579    ///
2580    /// # Shared Value
2581    ///
2582    /// Under the `sync` feature, a _shared_ value may deadlock.
2583    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2584    ///
2585    /// Under these circumstances, the cast also fails.
2586    ///
2587    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2588    #[cfg(not(feature = "no_index"))]
2589    #[inline(always)]
2590    pub fn as_array_mut(&mut self) -> Result<impl DerefMut<Target = Array> + '_, &'static str> {
2591        let type_name = self.type_name();
2592        self.write_lock::<Array>().ok_or(type_name)
2593    }
2594    /// Cast the [`Dynamic`] as a [`Blob`].
2595    ///
2596    /// Not available under `no_index`.
2597    ///
2598    /// # Errors
2599    ///
2600    /// Returns the name of the actual type as an error if the cast fails.
2601    ///
2602    /// # Shared Value
2603    ///
2604    /// Under the `sync` feature, a _shared_ value may deadlock.
2605    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2606    ///
2607    /// Under these circumstances, the cast also fails.
2608    ///
2609    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2610    #[cfg(not(feature = "no_index"))]
2611    #[inline(always)]
2612    pub fn as_blob_ref(&self) -> Result<impl Deref<Target = Blob> + '_, &'static str> {
2613        self.read_lock::<Blob>().ok_or_else(|| self.type_name())
2614    }
2615    /// Cast the [`Dynamic`] as a mutable reference to a [`Blob`].
2616    ///
2617    /// Not available under `no_index`.
2618    ///
2619    /// # Errors
2620    ///
2621    /// Returns the name of the actual type as an error if the cast fails.
2622    ///
2623    /// # Shared Value
2624    ///
2625    /// Under the `sync` feature, a _shared_ value may deadlock.
2626    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2627    ///
2628    /// Under these circumstances, the cast also fails.
2629    ///
2630    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2631    #[cfg(not(feature = "no_index"))]
2632    #[inline(always)]
2633    pub fn as_blob_mut(&mut self) -> Result<impl DerefMut<Target = Blob> + '_, &'static str> {
2634        let type_name = self.type_name();
2635        self.write_lock::<Blob>().ok_or(type_name)
2636    }
2637    /// Cast the [`Dynamic`] as a [`Map`].
2638    ///
2639    /// Not available under `no_object`.
2640    ///
2641    /// # Errors
2642    ///
2643    /// Returns the name of the actual type as an error if the cast fails.
2644    ///
2645    /// # Shared Value
2646    ///
2647    /// Under the `sync` feature, a _shared_ value may deadlock.
2648    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2649    ///
2650    /// Under these circumstances, the cast also fails.
2651    ///
2652    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2653    #[cfg(not(feature = "no_object"))]
2654    #[inline(always)]
2655    pub fn as_map_ref(&self) -> Result<impl Deref<Target = Map> + '_, &'static str> {
2656        self.read_lock::<Map>().ok_or_else(|| self.type_name())
2657    }
2658    /// Cast the [`Dynamic`] as a mutable reference to a [`Map`].
2659    ///
2660    /// Not available under `no_object`.
2661    ///
2662    /// # Errors
2663    ///
2664    /// Returns the name of the actual type as an error if the cast fails.
2665    ///
2666    /// # Shared Value
2667    ///
2668    /// Under the `sync` feature, a _shared_ value may deadlock.
2669    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2670    ///
2671    /// Under these circumstances, the cast also fails.
2672    ///
2673    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2674    #[cfg(not(feature = "no_object"))]
2675    #[inline(always)]
2676    pub fn as_map_mut(&mut self) -> Result<impl DerefMut<Target = Map> + '_, &'static str> {
2677        let type_name = self.type_name();
2678        self.write_lock::<Map>().ok_or(type_name)
2679    }
2680    /// Convert the [`Dynamic`] into a [`String`].
2681    ///
2682    /// If there are other references to the same string, a cloned copy is returned.
2683    ///
2684    /// # Errors
2685    ///
2686    /// Returns the name of the actual type as an error if the cast fails.
2687    ///
2688    /// # Shared Value
2689    ///
2690    /// Under the `sync` feature, a _shared_ value may deadlock.
2691    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2692    ///
2693    /// Under these circumstances, the cast also fails.
2694    ///
2695    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2696    #[inline]
2697    pub fn into_string(self) -> Result<String, &'static str> {
2698        self.into_immutable_string()
2699            .map(ImmutableString::into_owned)
2700    }
2701    /// Convert the [`Dynamic`] into an [`ImmutableString`].
2702    ///
2703    /// # Errors
2704    ///
2705    /// Returns the name of the actual type as an error if the cast fails.
2706    ///
2707    /// # Shared Value
2708    ///
2709    /// Under the `sync` feature, a _shared_ value may deadlock.
2710    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2711    ///
2712    /// Under these circumstances, the cast also fails.
2713    ///
2714    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2715    #[inline]
2716    pub fn into_immutable_string(self) -> Result<ImmutableString, &'static str> {
2717        match self.0 {
2718            Union::Str(s, ..) => Ok(s),
2719            #[cfg(not(feature = "no_closure"))]
2720            Union::Shared(ref cell, ..) => crate::func::locked_read(cell)
2721                .and_then(|guard| match guard.0 {
2722                    Union::Str(ref s, ..) => Some(s.clone()),
2723                    _ => None,
2724                })
2725                .ok_or_else(|| cell.type_name()),
2726            _ => Err(self.type_name()),
2727        }
2728    }
2729    /// Convert the [`Dynamic`] into an [`Array`].
2730    ///
2731    /// Not available under `no_index`.
2732    ///
2733    /// # Errors
2734    ///
2735    /// Returns the name of the actual type as an error if the cast fails.
2736    ///
2737    /// # Shared Value
2738    ///
2739    /// Under the `sync` feature, a _shared_ value may deadlock.
2740    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2741    ///
2742    /// Under these circumstances, the cast also fails.
2743    ///
2744    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2745    #[cfg(not(feature = "no_index"))]
2746    #[inline(always)]
2747    pub fn into_array(self) -> Result<Array, &'static str> {
2748        match self.0 {
2749            Union::Array(a, ..) => Ok(*a),
2750            #[cfg(not(feature = "no_closure"))]
2751            Union::Shared(ref cell, ..) => crate::func::locked_read(cell)
2752                .and_then(|guard| match guard.0 {
2753                    Union::Array(ref a, ..) => Some(a.as_ref().clone()),
2754                    _ => None,
2755                })
2756                .ok_or_else(|| cell.type_name()),
2757            _ => Err(self.type_name()),
2758        }
2759    }
2760    /// Convert the [`Dynamic`] into a [`Vec`].
2761    ///
2762    /// Not available under `no_index`.
2763    ///
2764    /// # Errors
2765    ///
2766    /// Returns the name of the actual type as an error if the cast fails.
2767    ///
2768    /// # Shared Value
2769    ///
2770    /// Under the `sync` feature, a _shared_ value may deadlock.
2771    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2772    ///
2773    /// Under these circumstances, the cast also fails.
2774    ///
2775    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2776    #[cfg(not(feature = "no_index"))]
2777    #[inline(always)]
2778    pub fn into_typed_array<T: Variant + Clone>(self) -> Result<Vec<T>, &'static str> {
2779        match self.0 {
2780            Union::Array(a, ..) => a
2781                .into_iter()
2782                .map(|v| {
2783                    #[cfg(not(feature = "no_closure"))]
2784                    let typ = if v.is_shared() {
2785                        // Avoid panics/deadlocks with shared values
2786                        "<shared>"
2787                    } else {
2788                        v.type_name()
2789                    };
2790                    #[cfg(feature = "no_closure")]
2791                    let typ = v.type_name();
2792
2793                    v.try_cast::<T>().ok_or(typ)
2794                })
2795                .collect(),
2796            Union::Blob(b, ..) if TypeId::of::<T>() == TypeId::of::<u8>() => {
2797                Ok(reify! { *b => !!! Vec<T> })
2798            }
2799            #[cfg(not(feature = "no_closure"))]
2800            Union::Shared(ref cell, ..) => crate::func::locked_read(cell)
2801                .and_then(|guard| match guard.0 {
2802                    Union::Array(ref a, ..) => a
2803                        .iter()
2804                        .map(|v| v.read_lock::<T>().map(|v| v.clone()))
2805                        .collect(),
2806                    Union::Blob(ref b, ..) if TypeId::of::<T>() == TypeId::of::<u8>() => {
2807                        Some(reify! { b.clone() => !!! Vec<T> })
2808                    }
2809                    _ => None,
2810                })
2811                .ok_or_else(|| cell.type_name()),
2812            _ => Err(self.type_name()),
2813        }
2814    }
2815    /// Convert the [`Dynamic`] into a [`Blob`].
2816    ///
2817    /// Not available under `no_index`.
2818    ///
2819    /// # Errors
2820    ///
2821    /// Returns the name of the actual type as an error if the cast fails.
2822    ///
2823    /// # Shared Value
2824    ///
2825    /// Under the `sync` feature, a _shared_ value may deadlock.
2826    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2827    ///
2828    /// Under these circumstances, the cast also fails.
2829    ///
2830    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2831    #[cfg(not(feature = "no_index"))]
2832    #[inline(always)]
2833    pub fn into_blob(self) -> Result<Blob, &'static str> {
2834        match self.0 {
2835            Union::Blob(b, ..) => Ok(*b),
2836            #[cfg(not(feature = "no_closure"))]
2837            Union::Shared(ref cell, ..) => crate::func::locked_read(cell)
2838                .and_then(|guard| match guard.0 {
2839                    Union::Blob(ref b, ..) => Some(b.as_ref().clone()),
2840                    _ => None,
2841                })
2842                .ok_or_else(|| cell.type_name()),
2843            _ => Err(self.type_name()),
2844        }
2845    }
2846
2847    /// Recursively scan for [`Dynamic`] values within this [`Dynamic`] (e.g. items in an array or map),
2848    /// calling a filter function on each.
2849    ///
2850    /// # Shared Value
2851    ///
2852    /// Shared values are _NOT_ scanned.
2853    #[inline]
2854    #[allow(clippy::only_used_in_recursion)]
2855    pub fn deep_scan(&mut self, mut filter: impl FnMut(&mut Self)) {
2856        fn scan_inner(value: &mut Dynamic, filter: &mut (impl FnMut(&mut Dynamic) + ?Sized)) {
2857            filter(value);
2858
2859            match &mut value.0 {
2860                #[cfg(not(feature = "no_index"))]
2861                Union::Array(a, ..) => a.iter_mut().for_each(|v| scan_inner(v, filter)),
2862                #[cfg(not(feature = "no_object"))]
2863                Union::Map(m, ..) => m.values_mut().for_each(|v| scan_inner(v, filter)),
2864                Union::FnPtr(f, ..) => f.iter_curry_mut().for_each(|v| scan_inner(v, filter)),
2865                _ => (),
2866            }
2867        }
2868
2869        scan_inner(self, &mut filter);
2870    }
2871}
2872
2873impl From<()> for Dynamic {
2874    #[inline(always)]
2875    fn from(value: ()) -> Self {
2876        Self(Union::Unit(value, DEFAULT_TAG_VALUE, ReadWrite))
2877    }
2878}
2879impl From<bool> for Dynamic {
2880    #[inline(always)]
2881    fn from(value: bool) -> Self {
2882        Self(Union::Bool(value, DEFAULT_TAG_VALUE, ReadWrite))
2883    }
2884}
2885impl From<INT> for Dynamic {
2886    #[inline(always)]
2887    fn from(value: INT) -> Self {
2888        Self(Union::Int(value, DEFAULT_TAG_VALUE, ReadWrite))
2889    }
2890}
2891#[cfg(not(feature = "no_float"))]
2892impl From<crate::FLOAT> for Dynamic {
2893    #[inline(always)]
2894    fn from(value: crate::FLOAT) -> Self {
2895        Self(Union::Float(value.into(), DEFAULT_TAG_VALUE, ReadWrite))
2896    }
2897}
2898#[cfg(not(feature = "no_float"))]
2899impl From<super::FloatWrapper<crate::FLOAT>> for Dynamic {
2900    #[inline(always)]
2901    fn from(value: super::FloatWrapper<crate::FLOAT>) -> Self {
2902        Self(Union::Float(value, DEFAULT_TAG_VALUE, ReadWrite))
2903    }
2904}
2905#[cfg(feature = "decimal")]
2906impl From<rust_decimal::Decimal> for Dynamic {
2907    #[inline(always)]
2908    fn from(value: rust_decimal::Decimal) -> Self {
2909        Self(Union::Decimal(value.into(), DEFAULT_TAG_VALUE, ReadWrite))
2910    }
2911}
2912impl From<char> for Dynamic {
2913    #[inline(always)]
2914    fn from(value: char) -> Self {
2915        Self(Union::Char(value, DEFAULT_TAG_VALUE, ReadWrite))
2916    }
2917}
2918impl<S: Into<ImmutableString>> From<S> for Dynamic {
2919    #[inline(always)]
2920    fn from(value: S) -> Self {
2921        Self(Union::Str(value.into(), DEFAULT_TAG_VALUE, ReadWrite))
2922    }
2923}
2924impl FromStr for Dynamic {
2925    type Err = ();
2926
2927    fn from_str(value: &str) -> Result<Self, Self::Err> {
2928        Ok(Self(Union::Str(value.into(), DEFAULT_TAG_VALUE, ReadWrite)))
2929    }
2930}
2931#[cfg(not(feature = "no_index"))]
2932impl<T: Variant + Clone> From<Vec<T>> for Dynamic {
2933    #[inline]
2934    fn from(value: Vec<T>) -> Self {
2935        Self(Union::Array(
2936            Box::new(value.into_iter().map(Self::from).collect()),
2937            DEFAULT_TAG_VALUE,
2938            ReadWrite,
2939        ))
2940    }
2941}
2942#[cfg(not(feature = "no_index"))]
2943impl<T: Variant + Clone> From<&[T]> for Dynamic {
2944    #[inline]
2945    fn from(value: &[T]) -> Self {
2946        Self(Union::Array(
2947            Box::new(value.iter().cloned().map(Self::from).collect()),
2948            DEFAULT_TAG_VALUE,
2949            ReadWrite,
2950        ))
2951    }
2952}
2953#[cfg(not(feature = "no_index"))]
2954impl<T: Variant + Clone> std::iter::FromIterator<T> for Dynamic {
2955    #[inline]
2956    fn from_iter<X: IntoIterator<Item = T>>(iter: X) -> Self {
2957        Self(Union::Array(
2958            Box::new(iter.into_iter().map(Self::from).collect()),
2959            DEFAULT_TAG_VALUE,
2960            ReadWrite,
2961        ))
2962    }
2963}
2964#[cfg(not(feature = "no_object"))]
2965#[cfg(not(feature = "no_std"))]
2966impl<K: Into<crate::Identifier>, T: Variant + Clone> From<std::collections::HashMap<K, T>>
2967    for Dynamic
2968{
2969    #[inline]
2970    fn from(value: std::collections::HashMap<K, T>) -> Self {
2971        Self(Union::Map(
2972            Box::new(
2973                value
2974                    .into_iter()
2975                    .map(|(k, v)| (k.into(), Self::from(v)))
2976                    .collect(),
2977            ),
2978            DEFAULT_TAG_VALUE,
2979            ReadWrite,
2980        ))
2981    }
2982}
2983#[cfg(not(feature = "no_object"))]
2984#[cfg(not(feature = "no_std"))]
2985impl<K: Into<crate::Identifier>> From<std::collections::HashSet<K>> for Dynamic {
2986    #[inline]
2987    fn from(value: std::collections::HashSet<K>) -> Self {
2988        Self(Union::Map(
2989            Box::new(value.into_iter().map(|k| (k.into(), Self::UNIT)).collect()),
2990            DEFAULT_TAG_VALUE,
2991            ReadWrite,
2992        ))
2993    }
2994}
2995#[cfg(not(feature = "no_object"))]
2996impl<K: Into<crate::Identifier>, T: Variant + Clone> From<std::collections::BTreeMap<K, T>>
2997    for Dynamic
2998{
2999    #[inline]
3000    fn from(value: std::collections::BTreeMap<K, T>) -> Self {
3001        Self(Union::Map(
3002            Box::new(
3003                value
3004                    .into_iter()
3005                    .map(|(k, v)| (k.into(), Self::from(v)))
3006                    .collect(),
3007            ),
3008            DEFAULT_TAG_VALUE,
3009            ReadWrite,
3010        ))
3011    }
3012}
3013#[cfg(not(feature = "no_object"))]
3014impl<K: Into<crate::Identifier>> From<std::collections::BTreeSet<K>> for Dynamic {
3015    #[inline]
3016    fn from(value: std::collections::BTreeSet<K>) -> Self {
3017        Self(Union::Map(
3018            Box::new(value.into_iter().map(|k| (k.into(), Self::UNIT)).collect()),
3019            DEFAULT_TAG_VALUE,
3020            ReadWrite,
3021        ))
3022    }
3023}
3024impl From<FnPtr> for Dynamic {
3025    #[inline(always)]
3026    fn from(value: FnPtr) -> Self {
3027        Self(Union::FnPtr(value.into(), DEFAULT_TAG_VALUE, ReadWrite))
3028    }
3029}
3030#[cfg(not(feature = "no_time"))]
3031impl From<Instant> for Dynamic {
3032    #[inline(always)]
3033    fn from(value: Instant) -> Self {
3034        Self(Union::TimeStamp(value.into(), DEFAULT_TAG_VALUE, ReadWrite))
3035    }
3036}
3037#[cfg(not(feature = "no_closure"))]
3038impl From<crate::Shared<crate::Locked<Self>>> for Dynamic {
3039    #[inline(always)]
3040    fn from(value: crate::Shared<crate::Locked<Self>>) -> Self {
3041        Self(Union::Shared(value, DEFAULT_TAG_VALUE, ReadWrite))
3042    }
3043}
3044
3045impl From<ExclusiveRange> for Dynamic {
3046    #[inline(always)]
3047    fn from(value: ExclusiveRange) -> Self {
3048        Self::from(value)
3049    }
3050}
3051impl From<InclusiveRange> for Dynamic {
3052    #[inline(always)]
3053    fn from(value: InclusiveRange) -> Self {
3054        Self::from(value)
3055    }
3056}