spo_rhai/types/
dynamic.rs

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