Skip to main content

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 web_time::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<T: Any + Clone> Deref for DynamicReadLock<'_, 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<T: Any + Clone> Deref for DynamicWriteLock<'_, 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<T: Any + Clone> DerefMut for DynamicWriteLock<'_, 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>(&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>(&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    /// Note that there is no accompanying `as_fnptr()` method, use [`cast()`](Self::cast) to obtain the [`FnPtr`].
2292    ///
2293    /// # Shared Value
2294    ///
2295    /// Under the `sync` feature, a _shared_ value may deadlock.
2296    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2297    ///
2298    /// Under these circumstances, `false` is returned.
2299    ///
2300    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2301    #[inline]
2302    #[must_use]
2303    pub fn is_fnptr(&self) -> bool {
2304        match self.0 {
2305            Union::FnPtr(..) => true,
2306            #[cfg(not(feature = "no_closure"))]
2307            Union::Shared(ref cell, ..) => {
2308                crate::func::locked_read(cell).map_or(false, |v| matches!(v.0, Union::FnPtr(..)))
2309            }
2310            _ => false,
2311        }
2312    }
2313    /// Return `true` if the [`Dynamic`] holds a [timestamp][Instant].
2314    ///
2315    /// Not available under `no_time`.
2316    ///
2317    /// # Shared Value
2318    ///
2319    /// Under the `sync` feature, a _shared_ value may deadlock.
2320    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2321    ///
2322    /// Under these circumstances, `false` is returned.
2323    ///
2324    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2325    #[cfg(not(feature = "no_time"))]
2326    #[inline]
2327    #[must_use]
2328    pub fn is_timestamp(&self) -> bool {
2329        match self.0 {
2330            Union::TimeStamp(..) => true,
2331            #[cfg(not(feature = "no_closure"))]
2332            Union::Shared(ref cell, ..) => crate::func::locked_read(cell)
2333                .map_or(false, |v| matches!(v.0, Union::TimeStamp(..))),
2334            _ => false,
2335        }
2336    }
2337
2338    /// Cast the [`Dynamic`] as a unit `()`.
2339    ///
2340    /// # Errors
2341    ///
2342    /// Returns the name of the actual type as an error if the cast fails.
2343    ///
2344    /// # Shared Value
2345    ///
2346    /// Under the `sync` feature, a _shared_ value may deadlock.
2347    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2348    ///
2349    /// Under these circumstances, the cast also fails.
2350    ///
2351    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2352    #[inline]
2353    pub fn as_unit(&self) -> Result<(), &'static str> {
2354        match self.0 {
2355            Union::Unit(..) => Ok(()),
2356            #[cfg(not(feature = "no_closure"))]
2357            Union::Shared(ref cell, ..) => crate::func::locked_read(cell)
2358                .and_then(|guard| match guard.0 {
2359                    Union::Unit(..) => Some(()),
2360                    _ => None,
2361                })
2362                .ok_or_else(|| cell.type_name()),
2363            _ => Err(self.type_name()),
2364        }
2365    }
2366    /// Cast the [`Dynamic`] as the system integer type [`INT`].
2367    ///
2368    /// # Errors
2369    ///
2370    /// Returns the name of the actual type as an error if the cast fails.
2371    ///
2372    /// # Shared Value
2373    ///
2374    /// Under the `sync` feature, a _shared_ value may deadlock.
2375    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2376    ///
2377    /// Under these circumstances, the cast also fails.
2378    ///
2379    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2380    #[inline]
2381    pub fn as_int(&self) -> Result<INT, &'static str> {
2382        match self.0 {
2383            Union::Int(n, ..) => Ok(n),
2384            #[cfg(not(feature = "no_closure"))]
2385            Union::Shared(ref cell, ..) => crate::func::locked_read(cell)
2386                .and_then(|guard| match guard.0 {
2387                    Union::Int(n, ..) => Some(n),
2388                    _ => None,
2389                })
2390                .ok_or_else(|| cell.type_name()),
2391            _ => Err(self.type_name()),
2392        }
2393    }
2394    /// Cast the [`Dynamic`] as the system floating-point type [`FLOAT`][crate::FLOAT].
2395    ///
2396    /// Not available under `no_float`.
2397    ///
2398    /// # Errors
2399    ///
2400    /// Returns the name of the actual type as an error if the cast fails.
2401    ///
2402    /// # Shared Value
2403    ///
2404    /// Under the `sync` feature, a _shared_ value may deadlock.
2405    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2406    ///
2407    /// Under these circumstances, the cast also fails.
2408    ///
2409    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2410    #[cfg(not(feature = "no_float"))]
2411    #[inline]
2412    pub fn as_float(&self) -> Result<crate::FLOAT, &'static str> {
2413        match self.0 {
2414            Union::Float(n, ..) => Ok(*n),
2415            #[cfg(not(feature = "no_closure"))]
2416            Union::Shared(ref cell, ..) => crate::func::locked_read(cell)
2417                .and_then(|guard| match guard.0 {
2418                    Union::Float(n, ..) => Some(*n),
2419                    _ => None,
2420                })
2421                .ok_or_else(|| cell.type_name()),
2422            _ => Err(self.type_name()),
2423        }
2424    }
2425    /// _(decimal)_ Cast the [`Dynamic`] as a [`Decimal`][rust_decimal::Decimal].
2426    /// Exported under the `decimal` feature only.
2427    ///
2428    /// # Errors
2429    ///
2430    /// Returns the name of the actual type as an error if the cast fails.
2431    ///
2432    /// # Shared Value
2433    ///
2434    /// Under the `sync` feature, a _shared_ value may deadlock.
2435    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2436    ///
2437    /// Under these circumstances, the cast also fails.
2438    ///
2439    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2440    #[cfg(feature = "decimal")]
2441    #[inline]
2442    pub fn as_decimal(&self) -> Result<rust_decimal::Decimal, &'static str> {
2443        match self.0 {
2444            Union::Decimal(ref n, ..) => Ok(**n),
2445            #[cfg(not(feature = "no_closure"))]
2446            Union::Shared(ref cell, ..) => crate::func::locked_read(cell)
2447                .and_then(|guard| match guard.0 {
2448                    Union::Decimal(ref n, ..) => Some(**n),
2449                    _ => None,
2450                })
2451                .ok_or_else(|| cell.type_name()),
2452            _ => Err(self.type_name()),
2453        }
2454    }
2455    /// Cast the [`Dynamic`] as a [`bool`].
2456    ///
2457    /// # Errors
2458    ///
2459    /// Returns the name of the actual type as an error if the cast fails.
2460    ///
2461    /// # Shared Value
2462    ///
2463    /// Under the `sync` feature, a _shared_ value may deadlock.
2464    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2465    ///
2466    /// Under these circumstances, the cast also fails.
2467    ///
2468    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2469    #[inline]
2470    pub fn as_bool(&self) -> Result<bool, &'static str> {
2471        match self.0 {
2472            Union::Bool(b, ..) => Ok(b),
2473            #[cfg(not(feature = "no_closure"))]
2474            Union::Shared(ref cell, ..) => crate::func::locked_read(cell)
2475                .and_then(|guard| match guard.0 {
2476                    Union::Bool(b, ..) => Some(b),
2477                    _ => None,
2478                })
2479                .ok_or_else(|| cell.type_name()),
2480            _ => Err(self.type_name()),
2481        }
2482    }
2483    /// RUX DIVERGENCE: this value as an index, accepting a whole float.
2484    /// See crates/rux-rhai/DIVERGENCE.md.
2485    ///
2486    /// Every number a Rux document handles is an `f64`, because `signal()`
2487    /// coerces to one. So `rows[i]` where `i` came from a signal handed the
2488    /// engine a float where it wanted an integer and failed with "Data type
2489    /// incorrect: f64 (expecting i64)" — indexing by a computed number, which is
2490    /// most indexing anyone does.
2491    ///
2492    /// A **fractional** index is still an error rather than being truncated.
2493    /// JavaScript answers `undefined` for `arr[1.5]`, which is the one place its
2494    /// behaviour is not worth copying: silently reading a different element than
2495    /// the one asked for is the kind of failure this milestone exists to remove.
2496    #[inline]
2497    pub fn as_index(&self) -> Result<crate::INT, &'static str> {
2498        match self.as_int() {
2499            Ok(i) => Ok(i),
2500            Err(typ) => match self.as_float() {
2501                Ok(f) if f.fract() == 0.0 => Ok(f as crate::INT),
2502                // Deliberately reports the type rather than the value: a
2503                // fractional index is a mistake in the expression that produced
2504                // it, and the type is what the reader has to fix.
2505                _ => Err(typ),
2506            },
2507        }
2508    }
2509    /// RUX DIVERGENCE: is this value truthy, by JavaScript's rules?
2510    /// See crates/rux-rhai/DIVERGENCE.md.
2511    ///
2512    /// Falsy: `false`, zero of any numeric type, `NaN`, the empty string, and
2513    /// `()`. **Everything else is truthy**, including an empty array, an empty
2514    /// object map, the string `"0"` and the string `"false"`.
2515    ///
2516    /// This never fails, which is the point: upstream a condition must already
2517    /// be a `bool` and anything else is a type error. Rux's users arrive from
2518    /// JavaScript and write `if user { … }` and `r-if="items.length"`, and in
2519    /// binding position especially they are not thinking about a scripting
2520    /// language's type rules.
2521    ///
2522    /// JavaScript's rules are adopted whole rather than adjusted. An empty array
2523    /// being truthy is the part that reads worst in isolation, and it is kept
2524    /// anyway: a rule that is *almost* JavaScript is worse than either following
2525    /// it or departing from it visibly, because the exception is only ever
2526    /// discovered by being bitten by it.
2527    #[must_use]
2528    pub fn is_truthy(&self) -> bool {
2529        match self.0 {
2530            Union::Bool(b, ..) => b,
2531            Union::Unit(..) => false,
2532            Union::Str(ref s, ..) => !s.is_empty(),
2533            Union::Int(n, ..) => n != 0,
2534            #[cfg(not(feature = "no_float"))]
2535            Union::Float(n, ..) => *n != 0.0 && !n.is_nan(),
2536            #[cfg(feature = "decimal")]
2537            Union::Decimal(ref n, ..) => !n.is_zero(),
2538            #[cfg(not(feature = "no_closure"))]
2539            Union::Shared(ref cell, ..) => crate::func::locked_read(cell)
2540                .map_or(true, |guard| guard.is_truthy()),
2541            // Arrays, maps, chars, timestamps, function pointers and any
2542            // registered custom type. JavaScript treats every object as truthy
2543            // and a one-character string is not empty, so all of these are true.
2544            _ => true,
2545        }
2546    }
2547    /// Cast the [`Dynamic`] as a [`char`].
2548    ///
2549    /// # Errors
2550    ///
2551    /// Returns the name of the actual type as an error if the cast fails.
2552    ///
2553    /// # Shared Value
2554    ///
2555    /// Under the `sync` feature, a _shared_ value may deadlock.
2556    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2557    ///
2558    /// Under these circumstances, the cast also fails.
2559    ///
2560    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2561    #[inline]
2562    pub fn as_char(&self) -> Result<char, &'static str> {
2563        match self.0 {
2564            Union::Char(c, ..) => Ok(c),
2565            #[cfg(not(feature = "no_closure"))]
2566            Union::Shared(ref cell, ..) => crate::func::locked_read(cell)
2567                .and_then(|guard| match guard.0 {
2568                    Union::Char(c, ..) => Some(c),
2569                    _ => None,
2570                })
2571                .ok_or_else(|| cell.type_name()),
2572            _ => Err(self.type_name()),
2573        }
2574    }
2575    /// Cast the [`Dynamic`] as an [`ImmutableString`].
2576    ///
2577    /// # Errors
2578    ///
2579    /// Returns the name of the actual type as an error if the cast fails.
2580    ///
2581    /// # Shared Value
2582    ///
2583    /// Under the `sync` feature, a _shared_ value may deadlock.
2584    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2585    ///
2586    /// Under these circumstances, the cast also fails.
2587    ///
2588    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2589    #[inline]
2590    pub fn as_immutable_string_ref(
2591        &self,
2592    ) -> Result<impl Deref<Target = ImmutableString> + '_, &'static str> {
2593        self.read_lock::<ImmutableString>()
2594            .ok_or_else(|| self.type_name())
2595    }
2596    /// Cast the [`Dynamic`] as a mutable reference to an [`ImmutableString`].
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    #[inline]
2611    pub fn as_immutable_string_mut(
2612        &mut self,
2613    ) -> Result<impl DerefMut<Target = ImmutableString> + '_, &'static str> {
2614        let type_name = self.type_name();
2615        self.write_lock::<ImmutableString>().ok_or(type_name)
2616    }
2617    /// Cast the [`Dynamic`] as an [`Array`].
2618    ///
2619    /// Not available under `no_index`.
2620    ///
2621    /// # Errors
2622    ///
2623    /// Returns the name of the actual type as an error if the cast fails.
2624    ///
2625    /// # Shared Value
2626    ///
2627    /// Under the `sync` feature, a _shared_ value may deadlock.
2628    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2629    ///
2630    /// Under these circumstances, the cast also fails.
2631    ///
2632    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2633    #[cfg(not(feature = "no_index"))]
2634    #[inline(always)]
2635    pub fn as_array_ref(&self) -> Result<impl Deref<Target = Array> + '_, &'static str> {
2636        self.read_lock::<Array>().ok_or_else(|| self.type_name())
2637    }
2638    /// Cast the [`Dynamic`] as a mutable reference to an [`Array`].
2639    ///
2640    /// Not available under `no_index`.
2641    ///
2642    /// # Errors
2643    ///
2644    /// Returns the name of the actual type as an error if the cast fails.
2645    ///
2646    /// # Shared Value
2647    ///
2648    /// Under the `sync` feature, a _shared_ value may deadlock.
2649    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2650    ///
2651    /// Under these circumstances, the cast also fails.
2652    ///
2653    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2654    #[cfg(not(feature = "no_index"))]
2655    #[inline(always)]
2656    pub fn as_array_mut(&mut self) -> Result<impl DerefMut<Target = Array> + '_, &'static str> {
2657        let type_name = self.type_name();
2658        self.write_lock::<Array>().ok_or(type_name)
2659    }
2660    /// Cast the [`Dynamic`] as a [`Blob`].
2661    ///
2662    /// Not available under `no_index`.
2663    ///
2664    /// # Errors
2665    ///
2666    /// Returns the name of the actual type as an error if the cast fails.
2667    ///
2668    /// # Shared Value
2669    ///
2670    /// Under the `sync` feature, a _shared_ value may deadlock.
2671    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2672    ///
2673    /// Under these circumstances, the cast also fails.
2674    ///
2675    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2676    #[cfg(not(feature = "no_index"))]
2677    #[inline(always)]
2678    pub fn as_blob_ref(&self) -> Result<impl Deref<Target = Blob> + '_, &'static str> {
2679        self.read_lock::<Blob>().ok_or_else(|| self.type_name())
2680    }
2681    /// Cast the [`Dynamic`] as a mutable reference to a [`Blob`].
2682    ///
2683    /// Not available under `no_index`.
2684    ///
2685    /// # Errors
2686    ///
2687    /// Returns the name of the actual type as an error if the cast fails.
2688    ///
2689    /// # Shared Value
2690    ///
2691    /// Under the `sync` feature, a _shared_ value may deadlock.
2692    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2693    ///
2694    /// Under these circumstances, the cast also fails.
2695    ///
2696    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2697    #[cfg(not(feature = "no_index"))]
2698    #[inline(always)]
2699    pub fn as_blob_mut(&mut self) -> Result<impl DerefMut<Target = Blob> + '_, &'static str> {
2700        let type_name = self.type_name();
2701        self.write_lock::<Blob>().ok_or(type_name)
2702    }
2703    /// Cast the [`Dynamic`] as a [`Map`].
2704    ///
2705    /// Not available under `no_object`.
2706    ///
2707    /// # Errors
2708    ///
2709    /// Returns the name of the actual type as an error if the cast fails.
2710    ///
2711    /// # Shared Value
2712    ///
2713    /// Under the `sync` feature, a _shared_ value may deadlock.
2714    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2715    ///
2716    /// Under these circumstances, the cast also fails.
2717    ///
2718    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2719    #[cfg(not(feature = "no_object"))]
2720    #[inline(always)]
2721    pub fn as_map_ref(&self) -> Result<impl Deref<Target = Map> + '_, &'static str> {
2722        self.read_lock::<Map>().ok_or_else(|| self.type_name())
2723    }
2724    /// Cast the [`Dynamic`] as a mutable reference to a [`Map`].
2725    ///
2726    /// Not available under `no_object`.
2727    ///
2728    /// # Errors
2729    ///
2730    /// Returns the name of the actual type as an error if the cast fails.
2731    ///
2732    /// # Shared Value
2733    ///
2734    /// Under the `sync` feature, a _shared_ value may deadlock.
2735    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2736    ///
2737    /// Under these circumstances, the cast also fails.
2738    ///
2739    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2740    #[cfg(not(feature = "no_object"))]
2741    #[inline(always)]
2742    pub fn as_map_mut(&mut self) -> Result<impl DerefMut<Target = Map> + '_, &'static str> {
2743        let type_name = self.type_name();
2744        self.write_lock::<Map>().ok_or(type_name)
2745    }
2746    /// Convert the [`Dynamic`] into a [`String`].
2747    ///
2748    /// If there are other references to the same string, a cloned copy is returned.
2749    ///
2750    /// # Errors
2751    ///
2752    /// Returns the name of the actual type as an error if the cast fails.
2753    ///
2754    /// # Shared Value
2755    ///
2756    /// Under the `sync` feature, a _shared_ value may deadlock.
2757    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2758    ///
2759    /// Under these circumstances, the cast also fails.
2760    ///
2761    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2762    #[inline]
2763    pub fn into_string(self) -> Result<String, &'static str> {
2764        self.into_immutable_string()
2765            .map(ImmutableString::into_owned)
2766    }
2767    /// Convert the [`Dynamic`] into an [`ImmutableString`].
2768    ///
2769    /// # Errors
2770    ///
2771    /// Returns the name of the actual type as an error if the cast fails.
2772    ///
2773    /// # Shared Value
2774    ///
2775    /// Under the `sync` feature, a _shared_ value may deadlock.
2776    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2777    ///
2778    /// Under these circumstances, the cast also fails.
2779    ///
2780    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2781    #[inline]
2782    pub fn into_immutable_string(self) -> Result<ImmutableString, &'static str> {
2783        match self.0 {
2784            Union::Str(s, ..) => Ok(s),
2785            #[cfg(not(feature = "no_closure"))]
2786            Union::Shared(ref cell, ..) => crate::func::locked_read(cell)
2787                .and_then(|guard| match guard.0 {
2788                    Union::Str(ref s, ..) => Some(s.clone()),
2789                    _ => None,
2790                })
2791                .ok_or_else(|| cell.type_name()),
2792            _ => Err(self.type_name()),
2793        }
2794    }
2795    /// Convert the [`Dynamic`] into an [`Array`].
2796    ///
2797    /// Not available under `no_index`.
2798    ///
2799    /// # Errors
2800    ///
2801    /// Returns the name of the actual type as an error if the cast fails.
2802    ///
2803    /// # Shared Value
2804    ///
2805    /// Under the `sync` feature, a _shared_ value may deadlock.
2806    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2807    ///
2808    /// Under these circumstances, the cast also fails.
2809    ///
2810    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2811    #[cfg(not(feature = "no_index"))]
2812    #[inline(always)]
2813    pub fn into_array(self) -> Result<Array, &'static str> {
2814        match self.0 {
2815            Union::Array(a, ..) => Ok(*a),
2816            #[cfg(not(feature = "no_closure"))]
2817            Union::Shared(ref cell, ..) => crate::func::locked_read(cell)
2818                .and_then(|guard| match guard.0 {
2819                    Union::Array(ref a, ..) => Some(a.as_ref().clone()),
2820                    _ => None,
2821                })
2822                .ok_or_else(|| cell.type_name()),
2823            _ => Err(self.type_name()),
2824        }
2825    }
2826    /// Convert the [`Dynamic`] into a [`Vec`].
2827    ///
2828    /// Not available under `no_index`.
2829    ///
2830    /// # Errors
2831    ///
2832    /// Returns the name of the actual type as an error if the cast fails.
2833    ///
2834    /// # Shared Value
2835    ///
2836    /// Under the `sync` feature, a _shared_ value may deadlock.
2837    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2838    ///
2839    /// Under these circumstances, the cast also fails.
2840    ///
2841    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2842    #[cfg(not(feature = "no_index"))]
2843    #[inline(always)]
2844    pub fn into_typed_array<T: Variant + Clone>(self) -> Result<Vec<T>, &'static str> {
2845        match self.0 {
2846            Union::Array(a, ..) => a
2847                .into_iter()
2848                .map(|v| {
2849                    #[cfg(not(feature = "no_closure"))]
2850                    let typ = if v.is_shared() {
2851                        // Avoid panics/deadlocks with shared values
2852                        "<shared>"
2853                    } else {
2854                        v.type_name()
2855                    };
2856                    #[cfg(feature = "no_closure")]
2857                    let typ = v.type_name();
2858
2859                    v.try_cast::<T>().ok_or(typ)
2860                })
2861                .collect(),
2862            Union::Blob(b, ..) if TypeId::of::<T>() == TypeId::of::<u8>() => {
2863                Ok(reify! { *b => !!! Vec<T> })
2864            }
2865            #[cfg(not(feature = "no_closure"))]
2866            Union::Shared(ref cell, ..) => crate::func::locked_read(cell)
2867                .and_then(|guard| match guard.0 {
2868                    Union::Array(ref a, ..) => a
2869                        .iter()
2870                        .map(|v| v.read_lock::<T>().map(|v| v.clone()))
2871                        .collect(),
2872                    Union::Blob(ref b, ..) if TypeId::of::<T>() == TypeId::of::<u8>() => {
2873                        Some(reify! { b.clone() => !!! Vec<T> })
2874                    }
2875                    _ => None,
2876                })
2877                .ok_or_else(|| cell.type_name()),
2878            _ => Err(self.type_name()),
2879        }
2880    }
2881    /// Convert the [`Dynamic`] into a [`Blob`].
2882    ///
2883    /// Not available under `no_index`.
2884    ///
2885    /// # Errors
2886    ///
2887    /// Returns the name of the actual type as an error if the cast fails.
2888    ///
2889    /// # Shared Value
2890    ///
2891    /// Under the `sync` feature, a _shared_ value may deadlock.
2892    /// Otherwise, the data may currently be borrowed for write (so its type cannot be determined).
2893    ///
2894    /// Under these circumstances, the cast also fails.
2895    ///
2896    /// These normally shouldn't occur since most operations in Rhai are single-threaded.
2897    #[cfg(not(feature = "no_index"))]
2898    #[inline(always)]
2899    pub fn into_blob(self) -> Result<Blob, &'static str> {
2900        match self.0 {
2901            Union::Blob(b, ..) => Ok(*b),
2902            #[cfg(not(feature = "no_closure"))]
2903            Union::Shared(ref cell, ..) => crate::func::locked_read(cell)
2904                .and_then(|guard| match guard.0 {
2905                    Union::Blob(ref b, ..) => Some(b.as_ref().clone()),
2906                    _ => None,
2907                })
2908                .ok_or_else(|| cell.type_name()),
2909            _ => Err(self.type_name()),
2910        }
2911    }
2912
2913    /// Recursively scan for [`Dynamic`] values within this [`Dynamic`] (e.g. items in an array or map),
2914    /// calling a filter function on each.
2915    ///
2916    /// # Shared Value
2917    ///
2918    /// Shared values are _NOT_ scanned.
2919    #[inline]
2920    #[allow(clippy::only_used_in_recursion)]
2921    pub fn deep_scan(&mut self, mut filter: impl FnMut(&mut Self)) {
2922        fn scan_inner(value: &mut Dynamic, filter: &mut (impl FnMut(&mut Dynamic) + ?Sized)) {
2923            filter(value);
2924
2925            match &mut value.0 {
2926                #[cfg(not(feature = "no_index"))]
2927                Union::Array(a, ..) => a.iter_mut().for_each(|v| scan_inner(v, filter)),
2928                #[cfg(not(feature = "no_object"))]
2929                Union::Map(m, ..) => m.values_mut().for_each(|v| scan_inner(v, filter)),
2930                Union::FnPtr(f, ..) => f.iter_curry_mut().for_each(|v| scan_inner(v, filter)),
2931                _ => (),
2932            }
2933        }
2934
2935        scan_inner(self, &mut filter);
2936    }
2937}
2938
2939impl From<()> for Dynamic {
2940    #[inline(always)]
2941    fn from(value: ()) -> Self {
2942        Self(Union::Unit(value, DEFAULT_TAG_VALUE, ReadWrite))
2943    }
2944}
2945impl From<bool> for Dynamic {
2946    #[inline(always)]
2947    fn from(value: bool) -> Self {
2948        Self(Union::Bool(value, DEFAULT_TAG_VALUE, ReadWrite))
2949    }
2950}
2951impl From<INT> for Dynamic {
2952    #[inline(always)]
2953    fn from(value: INT) -> Self {
2954        Self(Union::Int(value, DEFAULT_TAG_VALUE, ReadWrite))
2955    }
2956}
2957#[cfg(not(feature = "no_float"))]
2958impl From<crate::FLOAT> for Dynamic {
2959    #[inline(always)]
2960    fn from(value: crate::FLOAT) -> Self {
2961        Self(Union::Float(value.into(), DEFAULT_TAG_VALUE, ReadWrite))
2962    }
2963}
2964#[cfg(not(feature = "no_float"))]
2965impl From<super::FloatWrapper<crate::FLOAT>> for Dynamic {
2966    #[inline(always)]
2967    fn from(value: super::FloatWrapper<crate::FLOAT>) -> Self {
2968        Self(Union::Float(value, DEFAULT_TAG_VALUE, ReadWrite))
2969    }
2970}
2971#[cfg(feature = "decimal")]
2972impl From<rust_decimal::Decimal> for Dynamic {
2973    #[inline(always)]
2974    fn from(value: rust_decimal::Decimal) -> Self {
2975        Self(Union::Decimal(value.into(), DEFAULT_TAG_VALUE, ReadWrite))
2976    }
2977}
2978impl From<char> for Dynamic {
2979    #[inline(always)]
2980    fn from(value: char) -> Self {
2981        Self(Union::Char(value, DEFAULT_TAG_VALUE, ReadWrite))
2982    }
2983}
2984impl<S: Into<ImmutableString>> From<S> for Dynamic {
2985    #[inline(always)]
2986    fn from(value: S) -> Self {
2987        Self(Union::Str(value.into(), DEFAULT_TAG_VALUE, ReadWrite))
2988    }
2989}
2990impl FromStr for Dynamic {
2991    type Err = ();
2992
2993    fn from_str(value: &str) -> Result<Self, Self::Err> {
2994        Ok(Self(Union::Str(value.into(), DEFAULT_TAG_VALUE, ReadWrite)))
2995    }
2996}
2997#[cfg(not(feature = "no_index"))]
2998impl<T: Variant + Clone> From<Vec<T>> for Dynamic {
2999    #[inline]
3000    fn from(value: Vec<T>) -> Self {
3001        Self(Union::Array(
3002            Box::new(value.into_iter().map(Self::from).collect()),
3003            DEFAULT_TAG_VALUE,
3004            ReadWrite,
3005        ))
3006    }
3007}
3008#[cfg(not(feature = "no_index"))]
3009impl<T: Variant + Clone> From<&[T]> for Dynamic {
3010    #[inline]
3011    fn from(value: &[T]) -> Self {
3012        Self(Union::Array(
3013            Box::new(value.iter().cloned().map(Self::from).collect()),
3014            DEFAULT_TAG_VALUE,
3015            ReadWrite,
3016        ))
3017    }
3018}
3019#[cfg(not(feature = "no_index"))]
3020impl<T: Variant + Clone> std::iter::FromIterator<T> for Dynamic {
3021    #[inline]
3022    fn from_iter<X: IntoIterator<Item = T>>(iter: X) -> Self {
3023        Self(Union::Array(
3024            Box::new(iter.into_iter().map(Self::from).collect()),
3025            DEFAULT_TAG_VALUE,
3026            ReadWrite,
3027        ))
3028    }
3029}
3030#[cfg(not(feature = "no_object"))]
3031#[cfg(not(feature = "no_std"))]
3032impl<K: Into<crate::Identifier>, T: Variant + Clone> From<std::collections::HashMap<K, T>>
3033    for Dynamic
3034{
3035    #[inline]
3036    fn from(value: std::collections::HashMap<K, T>) -> Self {
3037        Self(Union::Map(
3038            Box::new(
3039                value
3040                    .into_iter()
3041                    .map(|(k, v)| (k.into(), Self::from(v)))
3042                    .collect(),
3043            ),
3044            DEFAULT_TAG_VALUE,
3045            ReadWrite,
3046        ))
3047    }
3048}
3049#[cfg(not(feature = "no_object"))]
3050#[cfg(not(feature = "no_std"))]
3051impl<K: Into<crate::Identifier>> From<std::collections::HashSet<K>> for Dynamic {
3052    #[inline]
3053    fn from(value: std::collections::HashSet<K>) -> Self {
3054        Self(Union::Map(
3055            Box::new(value.into_iter().map(|k| (k.into(), Self::UNIT)).collect()),
3056            DEFAULT_TAG_VALUE,
3057            ReadWrite,
3058        ))
3059    }
3060}
3061#[cfg(not(feature = "no_object"))]
3062impl<K: Into<crate::Identifier>, T: Variant + Clone> From<std::collections::BTreeMap<K, T>>
3063    for Dynamic
3064{
3065    #[inline]
3066    fn from(value: std::collections::BTreeMap<K, T>) -> Self {
3067        Self(Union::Map(
3068            Box::new(
3069                value
3070                    .into_iter()
3071                    .map(|(k, v)| (k.into(), Self::from(v)))
3072                    .collect(),
3073            ),
3074            DEFAULT_TAG_VALUE,
3075            ReadWrite,
3076        ))
3077    }
3078}
3079#[cfg(not(feature = "no_object"))]
3080impl<K: Into<crate::Identifier>> From<std::collections::BTreeSet<K>> for Dynamic {
3081    #[inline]
3082    fn from(value: std::collections::BTreeSet<K>) -> Self {
3083        Self(Union::Map(
3084            Box::new(value.into_iter().map(|k| (k.into(), Self::UNIT)).collect()),
3085            DEFAULT_TAG_VALUE,
3086            ReadWrite,
3087        ))
3088    }
3089}
3090impl From<FnPtr> for Dynamic {
3091    #[inline(always)]
3092    fn from(value: FnPtr) -> Self {
3093        Self(Union::FnPtr(value.into(), DEFAULT_TAG_VALUE, ReadWrite))
3094    }
3095}
3096#[cfg(not(feature = "no_time"))]
3097impl From<Instant> for Dynamic {
3098    #[inline(always)]
3099    fn from(value: Instant) -> Self {
3100        Self(Union::TimeStamp(value.into(), DEFAULT_TAG_VALUE, ReadWrite))
3101    }
3102}
3103#[cfg(not(feature = "no_closure"))]
3104impl From<crate::Shared<crate::Locked<Self>>> for Dynamic {
3105    #[inline(always)]
3106    fn from(value: crate::Shared<crate::Locked<Self>>) -> Self {
3107        Self(Union::Shared(value, DEFAULT_TAG_VALUE, ReadWrite))
3108    }
3109}
3110
3111impl From<ExclusiveRange> for Dynamic {
3112    #[inline(always)]
3113    fn from(value: ExclusiveRange) -> Self {
3114        Self::from(value)
3115    }
3116}
3117impl From<InclusiveRange> for Dynamic {
3118    #[inline(always)]
3119    fn from(value: InclusiveRange) -> Self {
3120        Self::from(value)
3121    }
3122}