Skip to main content

typex/
collections.rs

1use crate::{
2  AccessKind, AnyRef, EnumAccess, EnumAccessMut, MapAccess, MapAccessMut, MapEntryVisitor, Meta,
3  MetaMut, Object, ObjectOps, ObjectRef, ObjectRefMut, OptionAccessMut, Reflect, ReflectMut,
4  SequenceAccess, SequenceAccessMut, TupleAccess, TupleAccessMut, TypedMapAccess,
5  TypedMapAccessMut, VariantFields, VariantFieldsMut, as_map_key, btree_map_get, btree_map_get_mut,
6};
7#[cfg(feature = "std")]
8use crate::{hash_map_get, hash_map_get_mut};
9use alloc::borrow::ToOwned;
10use alloc::boxed::Box;
11use alloc::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
12use alloc::rc::Rc;
13use alloc::string::String;
14use alloc::sync::Arc;
15use alloc::vec::Vec;
16use core::any::{Any, TypeId};
17#[cfg(feature = "std")]
18use core::hash::Hash;
19#[cfg(feature = "std")]
20use std::collections::HashMap;
21
22macro_rules! impl_meta {
23  ($($ty:ty),* $(,)?) => {
24    $(
25      impl Meta for $ty {
26        fn reflect(&self) -> Reflect<'_> {
27          Reflect::Scalar
28        }
29
30        fn eq_dyn(&self, other: &dyn Meta) -> bool {
31          other.as_any().downcast_ref::<$ty>().is_some_and(|other| self == other)
32        }
33
34        fn into_any(self: Box<Self>) -> Box<dyn Any> {
35          self
36        }
37
38        fn as_any(&self) -> &dyn Any {
39          self
40        }
41      }
42
43      impl MetaMut for $ty {
44        set_body!();
45
46        fn reflect_mut(&mut self) -> ReflectMut<'_> {
47          ReflectMut::Opaque
48        }
49
50        fn as_any_mut(&mut self) -> &mut dyn Any {
51          self
52        }
53      }
54    )*
55  };
56}
57
58impl_meta!(
59  bool,
60  char,
61  i8,
62  i16,
63  i32,
64  i64,
65  i128,
66  isize,
67  u8,
68  u16,
69  u32,
70  u64,
71  u128,
72  usize,
73  f32,
74  f64,
75  &'static str,
76  String,
77);
78
79// Downcasts `value` to `T` when possible, returning the original value otherwise.
80fn into_typed<T: 'static>(value: Object) -> Result<T, Object> {
81  if !value.is::<T>() {
82    return Err(value);
83  }
84
85  Ok(*value.into_inner().into_any().downcast::<T>().unwrap())
86}
87
88macro_rules! impl_meta_forward {
89  ($wrapper:ident) => {
90    impl<T> Meta for $wrapper<T>
91    where
92      T: Meta + 'static,
93    {
94      fn reflect(&self) -> Reflect<'_> {
95        (**self).reflect()
96      }
97
98      fn eq_dyn(&self, other: &dyn Meta) -> bool {
99        other
100          .as_any()
101          .downcast_ref::<Self>()
102          .is_some_and(|other| (**self).eq_dyn(&**other))
103      }
104
105      fn into_any(self: Box<Self>) -> Box<dyn Any> {
106        self
107      }
108
109      fn as_any(&self) -> &dyn Any {
110        self
111      }
112    }
113  };
114}
115
116macro_rules! impl_meta_mut_forward {
117  (wrapper = $wrapper:ident, mode = direct $(,)?) => {
118    impl<T> MetaMut for $wrapper<T>
119    where
120      T: MetaMut + 'static,
121    {
122      set_body!();
123
124      fn reflect_mut(&mut self) -> ReflectMut<'_> {
125        (**self).reflect_mut()
126      }
127
128      fn as_any_mut(&mut self) -> &mut dyn Any {
129        self
130      }
131    }
132  };
133  (wrapper = $wrapper:ident, mode = unique $(,)?) => {
134    impl<T> MetaMut for $wrapper<T>
135    where
136      T: MetaMut + 'static,
137    {
138      set_body!();
139
140      // A shared value exposes no mutable structure.
141      fn reflect_mut(&mut self) -> ReflectMut<'_> {
142        match $wrapper::get_mut(self) {
143          Some(inner) => inner.reflect_mut(),
144          None => ReflectMut::Opaque,
145        }
146      }
147
148      fn as_any_mut(&mut self) -> &mut dyn Any {
149        self
150      }
151    }
152  };
153}
154
155impl_meta_forward!(Box);
156impl_meta_forward!(Rc);
157impl_meta_forward!(Arc);
158impl_meta_mut_forward!(wrapper = Box, mode = direct);
159impl_meta_mut_forward!(wrapper = Rc, mode = unique);
160impl_meta_mut_forward!(wrapper = Arc, mode = unique);
161
162fn move_vec_item<T>(value: &mut [T], from: usize, to: usize) -> Result<(), crate::MoveItemError> {
163  let len = value.len();
164  if from >= len || to > len {
165    return Err(crate::MoveItemError::IndexOutOfBounds);
166  }
167  if from == to {
168    return Ok(());
169  }
170
171  if from < to {
172    value[from..to].rotate_left(1);
173  } else {
174    value[to..=from].rotate_right(1);
175  }
176  Ok(())
177}
178
179fn move_vec_deque_item<T>(
180  value: &mut VecDeque<T>,
181  from: usize,
182  to: usize,
183) -> Result<(), crate::MoveItemError> {
184  let len = value.len();
185  if from >= len || to > len {
186    return Err(crate::MoveItemError::IndexOutOfBounds);
187  }
188  if from == to {
189    return Ok(());
190  }
191
192  let value = value.make_contiguous();
193  if from < to {
194    value[from..to].rotate_left(1);
195  } else {
196    value[to..=from].rotate_right(1);
197  }
198  Ok(())
199}
200
201fn move_linked_list_item<T>(
202  value: &mut LinkedList<T>,
203  from: usize,
204  to: usize,
205) -> Result<(), crate::MoveItemError> {
206  let len = value.len();
207  if from >= len || to > len {
208    return Err(crate::MoveItemError::IndexOutOfBounds);
209  }
210  if from == to {
211    return Ok(());
212  }
213
214  let mut tail = value.split_off(from);
215  let item = tail.pop_front().expect("validated source index");
216  value.append(&mut tail);
217  let insert_at = if from < to { to - 1 } else { to };
218  let mut suffix = value.split_off(insert_at);
219  value.push_back(item);
220  value.append(&mut suffix);
221  Ok(())
222}
223
224// Compares two sequences item by item in iteration order. Callers check the
225// lengths first.
226fn ordered_eq<'a, T, I>(a: I, b: I) -> bool
227where
228  T: Meta + 'a,
229  I: IntoIterator<Item = &'a T>,
230{
231  a.into_iter().zip(b).all(|(a, b)| a.eq_dyn(b))
232}
233
234// Compares two sequences as sorted multisets. `BinaryHeap` iteration order
235// depends on insertion history, so equal heaps can iterate differently.
236fn sorted_eq<'a, T, I>(a: I, b: I) -> bool
237where
238  T: Meta + Ord + 'a,
239  I: IntoIterator<Item = &'a T>,
240{
241  let mut a = a.into_iter().collect::<Vec<_>>();
242  let mut b = b.into_iter().collect::<Vec<_>>();
243  a.sort_unstable();
244  b.sort_unstable();
245  ordered_eq(a, b)
246}
247
248macro_rules! impl_seq_meta {
249  (
250    type = $ty:ty,
251    generics = [$($generics:tt)*],
252    bounds = [$($bounds:tt)*],
253    item = get,
254    len = method $(,)?
255  ) => {
256    impl_seq_meta!(@meta $ty, [$($generics)*], [$($bounds)*]);
257
258    impl<$($generics)*> SequenceAccess for $ty
259    where
260      $($bounds)*
261    {
262      fn len(&self) -> usize {
263        self.len()
264      }
265
266      fn item(&self, index: usize) -> Option<ObjectRef<'_>> {
267        self.get(index).map(|value| ObjectRef::new(value))
268      }
269    }
270  };
271  (
272    type = $ty:ty,
273    generics = [$($generics:tt)*],
274    bounds = [$($bounds:tt)*],
275    item = get,
276    len = const $len:ident $(,)?
277  ) => {
278    impl_seq_meta!(@meta $ty, [$($generics)*], [$($bounds)*]);
279
280    impl<$($generics)*> SequenceAccess for $ty
281    where
282      $($bounds)*
283    {
284      fn len(&self) -> usize {
285        $len
286      }
287
288      fn item(&self, index: usize) -> Option<ObjectRef<'_>> {
289        self.get(index).map(|value| ObjectRef::new(value))
290      }
291    }
292  };
293  (
294    type = $ty:ty,
295    generics = [$($generics:tt)*],
296    bounds = [$($bounds:tt)*],
297    item = iter,
298    len = method,
299    eq = $eq:ident $(,)?
300  ) => {
301    impl<$($generics)*> Meta for $ty
302    where
303      $($bounds)*
304    {
305      fn reflect(&self) -> Reflect<'_> {
306        Reflect::Sequence(self)
307      }
308
309      fn eq_dyn(&self, other: &dyn Meta) -> bool {
310        other
311          .as_any()
312          .downcast_ref::<Self>()
313          .is_some_and(|other| self.len() == other.len() && $eq(self, other))
314      }
315
316      fn into_any(self: Box<Self>) -> Box<dyn Any> {
317        self
318      }
319
320      fn as_any(&self) -> &dyn Any {
321        self
322      }
323    }
324
325    impl<$($generics)*> SequenceAccess for $ty
326    where
327      $($bounds)*
328    {
329      fn len(&self) -> usize {
330        self.len()
331      }
332
333      fn item(&self, index: usize) -> Option<ObjectRef<'_>> {
334        self.iter().nth(index).map(|value| ObjectRef::new(value))
335      }
336    }
337  };
338  (@meta $ty:ty, [$($generics:tt)*], [$($bounds:tt)*]) => {
339    impl<$($generics)*> Meta for $ty
340    where
341      $($bounds)*
342    {
343      fn reflect(&self) -> Reflect<'_> {
344        Reflect::Sequence(self)
345      }
346
347      fn into_any(self: Box<Self>) -> Box<dyn Any> {
348        self
349      }
350
351      fn as_any(&self) -> &dyn Any {
352        self
353      }
354    }
355  };
356}
357
358// Implements `MetaMut` for a sequence whose mutable shape is `Self`.
359macro_rules! impl_seq_meta_mut {
360  (type = $ty:ty, generics = [$($generics:tt)*], bounds = [$($bounds:tt)*] $(,)?) => {
361    impl<$($generics)*> MetaMut for $ty
362    where
363      $($bounds)*
364    {
365      set_body!();
366
367      fn reflect_mut(&mut self) -> ReflectMut<'_> {
368        ReflectMut::Sequence(self)
369      }
370
371      fn as_any_mut(&mut self) -> &mut dyn Any {
372        self
373      }
374    }
375  };
376}
377
378macro_rules! impl_indexed_meta_mut {
379  (
380    type = $ty:ty,
381    generics = [$($generics:tt)*],
382    bounds = [$($bounds:tt)*],
383    access_mut = $access_mut:ident,
384    push = $push:ident,
385    last = $last:ident,
386    insert = $insert:ident,
387    move_item = $move_item:path,
388    $($extra:item)*
389  ) => {
390    impl_seq_meta_mut!(type = $ty, generics = [$($generics)*], bounds = [$($bounds)*]);
391
392    impl<$($generics)*> SequenceAccessMut for $ty
393    where
394      $($bounds)*
395    {
396      fn item_mut(&mut self, index: usize) -> Option<ObjectRefMut<'_>> {
397        self
398          .$access_mut(index)
399          .map(|value| ObjectRefMut::new(value))
400      }
401
402      fn push_item(&mut self, value: Object) -> Result<ObjectRefMut<'_>, Object> {
403        let value = into_typed(value)?;
404        self.$push(value);
405
406        Ok(ObjectRefMut::new(
407          self.$last().expect("just pushed")
408        ))
409      }
410
411      fn insert_item(&mut self, index: usize, value: Object) -> Result<ObjectRefMut<'_>, Object> {
412        if index > self.len() {
413          return Err(value);
414        }
415
416        let value = into_typed(value)?;
417        self.$insert(index, value);
418
419        Ok(ObjectRefMut::new(
420          self.$access_mut(index).expect("just inserted"),
421        ))
422      }
423
424      $($extra)*
425
426      fn move_item(&mut self, from: usize, to: usize) -> Result<(), crate::MoveItemError> {
427        $move_item(self, from, to)
428      }
429    }
430  };
431}
432
433impl_seq_meta!(
434  type = Vec<T>,
435  generics = [T],
436  bounds = [T: Meta + 'static],
437  item = get,
438  len = method,
439);
440
441impl_indexed_meta_mut!(
442  type = Vec<T>,
443  generics = [T],
444  bounds = [T: MetaMut + 'static],
445  access_mut = get_mut,
446  push = push,
447  last = last_mut,
448  insert = insert,
449  move_item = move_vec_item,
450  fn remove_item(&mut self, index: usize) -> Option<Object> {
451    (index < self.len()).then(|| Object::new(self.remove(index)))
452  }
453);
454
455impl_seq_meta!(
456  type = [T; N],
457  generics = [T, const N: usize],
458  bounds = [T: Meta + 'static],
459  item = get,
460  len = const N,
461);
462impl_seq_meta_mut!(
463  type = [T; N],
464  generics = [T, const N: usize],
465  bounds = [T: MetaMut + 'static],
466);
467
468impl<T, const N: usize> SequenceAccessMut for [T; N]
469where
470  T: MetaMut + 'static,
471{
472  fn item_mut(&mut self, index: usize) -> Option<ObjectRefMut<'_>> {
473    self.get_mut(index).map(|value| ObjectRefMut::new(value))
474  }
475}
476
477impl_seq_meta!(
478  type = VecDeque<T>,
479  generics = [T],
480  bounds = [T: Meta + 'static],
481  item = get,
482  len = method,
483);
484impl_indexed_meta_mut!(
485  type = VecDeque<T>,
486  generics = [T],
487  bounds = [T: MetaMut + 'static],
488  access_mut = get_mut,
489  push = push_back,
490  last = back_mut,
491  insert = insert,
492  move_item = move_vec_deque_item,
493  fn remove_item(&mut self, index: usize) -> Option<Object> {
494    self.remove(index).map(Object::new)
495  }
496);
497
498impl_seq_meta!(
499  type = LinkedList<T>,
500  generics = [T],
501  bounds = [T: Meta + 'static],
502  item = iter,
503  len = method,
504  eq = ordered_eq,
505);
506impl_seq_meta_mut!(
507  type = LinkedList<T>,
508  generics = [T],
509  bounds = [T: MetaMut + 'static],
510);
511
512impl<T> SequenceAccessMut for LinkedList<T>
513where
514  T: MetaMut + 'static,
515{
516  fn item_mut(&mut self, index: usize) -> Option<ObjectRefMut<'_>> {
517    self
518      .iter_mut()
519      .nth(index)
520      .map(|value| ObjectRefMut::new(value))
521  }
522
523  fn push_item(&mut self, value: Object) -> Result<ObjectRefMut<'_>, Object> {
524    let value = into_typed(value)?;
525    self.push_back(value);
526
527    Ok(ObjectRefMut::new(self.back_mut().expect("just pushed")))
528  }
529
530  fn insert_item(&mut self, index: usize, value: Object) -> Result<ObjectRefMut<'_>, Object> {
531    if index > self.len() {
532      return Err(value);
533    }
534
535    let value = into_typed(value)?;
536    let mut tail = self.split_off(index);
537    self.push_back(value);
538    self.append(&mut tail);
539
540    Ok(ObjectRefMut::new(
541      self.iter_mut().nth(index).expect("just inserted"),
542    ))
543  }
544
545  fn remove_item(&mut self, index: usize) -> Option<Object> {
546    (index < self.len()).then(|| {
547      let mut tail = self.split_off(index);
548      let value = tail.pop_front().expect("just split at a valid index");
549      self.append(&mut tail);
550      Object::new(value)
551    })
552  }
553
554  fn move_item(&mut self, from: usize, to: usize) -> Result<(), crate::MoveItemError> {
555    move_linked_list_item(self, from, to)
556  }
557}
558
559impl_seq_meta!(
560  type = BTreeSet<T>,
561  generics = [T],
562  bounds = [T: Meta + Ord + 'static],
563  item = iter,
564  len = method,
565  eq = ordered_eq,
566);
567
568/// Mutating a `BTreeSet` element in place could break its sort order, and
569/// appending has no index or key to target since position is decided by
570/// ordering. A sequence push uses the old length as its rollback index,
571/// which cannot reliably identify an item inserted into a set.
572/// The set therefore exposes no mutable structure; use
573/// `to_mut::<BTreeSet<T>>()` for `insert`/`remove`.
574impl<T> MetaMut for BTreeSet<T>
575where
576  T: Meta + Ord + 'static,
577{
578  set_body!();
579
580  fn reflect_mut(&mut self) -> ReflectMut<'_> {
581    ReflectMut::Opaque
582  }
583
584  fn as_any_mut(&mut self) -> &mut dyn Any {
585    self
586  }
587}
588
589impl_seq_meta!(
590  type = BinaryHeap<T>,
591  generics = [T],
592  bounds = [T: Meta + Ord + 'static],
593  item = iter,
594  len = method,
595  eq = sorted_eq,
596);
597
598/// `BinaryHeap` only allows mutable access to its max element, via
599/// `peek_mut`, and `push` sifts the new value to an arbitrary position. The
600/// heap therefore exposes no mutable structure; use
601/// `to_mut::<BinaryHeap<T>>()` for the heap's own API.
602impl<T> MetaMut for BinaryHeap<T>
603where
604  T: Meta + Ord + 'static,
605{
606  set_body!();
607
608  fn reflect_mut(&mut self) -> ReflectMut<'_> {
609    ReflectMut::Opaque
610  }
611
612  fn as_any_mut(&mut self) -> &mut dyn Any {
613    self
614  }
615}
616
617impl<T> Meta for Option<T>
618where
619  T: Meta + 'static,
620{
621  fn reflect(&self) -> Reflect<'_> {
622    Reflect::Option(self.as_ref().map(|value| ObjectRef::new(value)))
623  }
624
625  // The defaults of `field_dyn`, `key_dyn`, `access_kind_dyn`,
626  // `field_names_dyn` and `visit_map_entries_dyn` match on `Reflect::Option`
627  // and reach the contained value through a type-erased `ObjectRef`, which adds
628  // a dynamic call. These overrides call the methods of `T` directly.
629  fn field_dyn(&self, name: &str) -> Option<ObjectRef<'_>> {
630    self.as_ref()?.field_dyn(name)
631  }
632
633  fn key_dyn(&self, key: &str) -> Option<ObjectRef<'_>> {
634    self.as_ref()?.key_dyn(key)
635  }
636
637  fn access_kind_dyn(&self) -> Option<AccessKind> {
638    self.as_ref()?.access_kind_dyn()
639  }
640
641  fn field_names_dyn(&self) -> &'static [&'static str] {
642    self.as_ref().map_or(&[], Meta::field_names_dyn)
643  }
644
645  fn visit_map_entries_dyn(&self, visitor: &mut MapEntryVisitor<'_>) -> bool {
646    self
647      .as_ref()
648      .is_some_and(|value| value.visit_map_entries_dyn(visitor))
649  }
650
651  fn into_any(self: Box<Self>) -> Box<dyn Any> {
652    self
653  }
654
655  fn as_any(&self) -> &dyn Any {
656    self
657  }
658}
659
660impl<T> MetaMut for Option<T>
661where
662  T: MetaMut + 'static,
663{
664  set_body!();
665
666  fn reflect_mut(&mut self) -> ReflectMut<'_> {
667    ReflectMut::Option(self)
668  }
669
670  // The default `field_mut_dyn` and `key_mut_dyn` match on `ReflectMut::Option`
671  // and reach the contained value through `OptionAccessMut` and a type-erased
672  // `ObjectRefMut`, which add two dynamic calls. These overrides call
673  // `T::field_mut_dyn` and `T::key_mut_dyn` directly.
674  fn field_mut_dyn(&mut self, name: &str) -> Option<ObjectRefMut<'_>> {
675    self.as_mut()?.field_mut_dyn(name)
676  }
677
678  fn key_mut_dyn(&mut self, key: &str) -> Option<ObjectRefMut<'_>> {
679    self.as_mut()?.key_mut_dyn(key)
680  }
681
682  fn item_mut_dyn(&mut self, index: usize) -> Option<ObjectRefMut<'_>> {
683    if index == 0 {
684      OptionAccessMut::value_mut(self)
685    } else {
686      None
687    }
688  }
689
690  fn as_any_mut(&mut self) -> &mut dyn Any {
691    self
692  }
693}
694
695impl<T> OptionAccessMut for Option<T>
696where
697  T: MetaMut + 'static,
698{
699  fn value_mut(&mut self) -> Option<ObjectRefMut<'_>> {
700    self.as_mut().map(|value| ObjectRefMut::new(value))
701  }
702
703  fn insert_value(&mut self, value: Object) -> Result<ObjectRefMut<'_>, Object> {
704    if self.is_some() {
705      return Err(value);
706    }
707
708    let value = into_typed(value)?;
709    Ok(ObjectRefMut::new(self.insert(value)))
710  }
711
712  fn take_value(&mut self) -> Option<Object> {
713    self.take().map(Object::new)
714  }
715}
716
717impl<T, E> Meta for Result<T, E>
718where
719  T: Meta + 'static,
720  E: Meta + 'static,
721{
722  fn reflect(&self) -> Reflect<'_> {
723    Reflect::Enum(self)
724  }
725
726  fn is_variant_dyn(&self, name: &str) -> Option<bool> {
727    Some(match self {
728      Self::Ok(_) => name == "Ok",
729      Self::Err(_) => name == "Err",
730    })
731  }
732
733  fn eq_dyn(&self, other: &dyn Meta) -> bool {
734    match (self, other.as_any().downcast_ref::<Self>()) {
735      (Self::Ok(value), Some(Self::Ok(other))) => value.eq_dyn(other),
736      (Self::Err(error), Some(Self::Err(other))) => error.eq_dyn(other),
737      _ => false,
738    }
739  }
740
741  fn into_any(self: Box<Self>) -> Box<dyn Any> {
742    self
743  }
744
745  fn as_any(&self) -> &dyn Any {
746    self
747  }
748}
749
750/// Exposes `Ok` and `Err` as tuple variants whose payload is item 0, so a
751/// `Result` reflects like a derived `enum { Ok(T), Err(E) }`.
752impl<T, E> EnumAccess for Result<T, E>
753where
754  T: Meta + 'static,
755  E: Meta + 'static,
756{
757  fn variant_name(&self) -> &'static str {
758    match self {
759      Self::Ok(_) => "Ok",
760      Self::Err(_) => "Err",
761    }
762  }
763
764  fn fields(&self) -> VariantFields<'_> {
765    VariantFields::Positional(self)
766  }
767}
768
769impl<T, E> TupleAccess for Result<T, E>
770where
771  T: Meta + 'static,
772  E: Meta + 'static,
773{
774  fn item(&self, index: usize) -> Option<ObjectRef<'_>> {
775    match (self, index) {
776      (Self::Ok(value), 0) => Some(ObjectRef::new(value)),
777      (Self::Err(error), 0) => Some(ObjectRef::new(error)),
778      _ => None,
779    }
780  }
781
782  fn len(&self) -> usize {
783    1
784  }
785}
786
787impl<T, E> MetaMut for Result<T, E>
788where
789  T: MetaMut + 'static,
790  E: MetaMut + 'static,
791{
792  set_body!();
793
794  fn reflect_mut(&mut self) -> ReflectMut<'_> {
795    ReflectMut::Enum(self)
796  }
797
798  fn as_any_mut(&mut self) -> &mut dyn Any {
799    self
800  }
801}
802
803impl<T, E> EnumAccessMut for Result<T, E>
804where
805  T: MetaMut + 'static,
806  E: MetaMut + 'static,
807{
808  fn fields_mut(&mut self) -> VariantFieldsMut<'_> {
809    VariantFieldsMut::Positional(self)
810  }
811}
812
813impl<T, E> TupleAccessMut for Result<T, E>
814where
815  T: MetaMut + 'static,
816  E: MetaMut + 'static,
817{
818  fn item_mut(&mut self, index: usize) -> Option<ObjectRefMut<'_>> {
819    match (self, index) {
820      (Self::Ok(value), 0) => Some(ObjectRefMut::new(value)),
821      (Self::Err(error), 0) => Some(ObjectRefMut::new(error)),
822      _ => None,
823    }
824  }
825}
826
827macro_rules! impl_tuple_meta {
828  ($(($($idx:tt => $ty:ident),+)),* $(,)?) => {
829    $(
830      impl<$($ty),+> Meta for ($($ty,)+)
831      where
832        $($ty: Meta + 'static,)+
833      {
834        fn reflect(&self) -> Reflect<'_> {
835          Reflect::Tuple(self)
836        }
837
838        fn eq_dyn(&self, other: &dyn Meta) -> bool {
839          other
840            .as_any()
841            .downcast_ref::<Self>()
842            .is_some_and(|other| true $(&& self.$idx.eq_dyn(&other.$idx))+)
843        }
844
845        fn into_any(self: Box<Self>) -> Box<dyn Any> {
846          self
847        }
848
849        fn as_any(&self) -> &dyn Any {
850          self
851        }
852      }
853
854      impl<$($ty),+> TupleAccess for ($($ty,)+)
855      where
856        $($ty: Meta + 'static,)+
857      {
858        fn item(&self, index: usize) -> Option<ObjectRef<'_>> {
859          match index {
860            $($idx => Some(ObjectRef::new(&self.$idx)),)+
861            _ => None,
862          }
863        }
864
865        fn len(&self) -> usize {
866          <[_]>::len(&[$($idx),+])
867        }
868      }
869
870      impl<$($ty),+> MetaMut for ($($ty,)+)
871      where
872        $($ty: MetaMut + 'static,)+
873      {
874        set_body!();
875
876        fn reflect_mut(&mut self) -> ReflectMut<'_> {
877          ReflectMut::Tuple(self)
878        }
879
880        fn as_any_mut(&mut self) -> &mut dyn Any {
881          self
882        }
883      }
884
885      impl<$($ty),+> TupleAccessMut for ($($ty,)+)
886      where
887        $($ty: MetaMut + 'static,)+
888      {
889        fn item_mut(&mut self, index: usize) -> Option<ObjectRefMut<'_>> {
890          match index {
891            $($idx => Some(ObjectRefMut::new(&mut self.$idx)),)+
892            _ => None,
893          }
894        }
895      }
896    )*
897  };
898}
899
900impl_tuple_meta!(
901  (0 => T0),
902  (0 => T0, 1 => T1),
903  (0 => T0, 1 => T1, 2 => T2),
904  (0 => T0, 1 => T1, 2 => T2, 3 => T3),
905  (0 => T0, 1 => T1, 2 => T2, 3 => T3, 4 => T4),
906  (0 => T0, 1 => T1, 2 => T2, 3 => T3, 4 => T4, 5 => T5),
907  (0 => T0, 1 => T1, 2 => T2, 3 => T3, 4 => T4, 5 => T5, 6 => T6),
908  (0 => T0, 1 => T1, 2 => T2, 3 => T3, 4 => T4, 5 => T5, 6 => T6, 7 => T7),
909);
910
911macro_rules! impl_map_meta {
912  (
913    type = $ty:ty,
914    generics = [$($generics:tt)*],
915    bounds = [$($bounds:tt)*],
916    lookup = $lookup:ident,
917    equality = $eq:ident $(,)?
918  ) => {
919    impl<$($generics)*> Meta for $ty
920    where
921      $($bounds)*
922    {
923      fn reflect(&self) -> Reflect<'_> {
924        Reflect::Map(self)
925      }
926
927      fn eq_dyn(&self, other: &dyn Meta) -> bool {
928        $eq(self, other)
929      }
930
931      fn into_any(self: Box<Self>) -> Box<dyn Any> {
932        self
933      }
934
935      fn as_any(&self) -> &dyn Any {
936        self
937      }
938    }
939
940    impl<$($generics)*> MapAccess for $ty
941    where
942      $($bounds)*
943    {
944      fn len(&self) -> usize {
945        self.len()
946      }
947
948      fn key(&self, key: &str) -> Option<ObjectRef<'_>> {
949        $lookup(self, key).map(|value| ObjectRef::new(value))
950      }
951
952      fn keys(&self) -> Option<Vec<String>> {
953        self.keys().map(as_map_key).collect()
954      }
955
956      #[inline]
957      fn visit_entries(&self, visitor: &mut MapEntryVisitor<'_>) {
958        for (key, value) in self {
959          if !visitor(AnyRef::new(key), ObjectRef::new(value)) {
960            break;
961          }
962        }
963      }
964    }
965  };
966}
967
968/// Compares keys via `K`'s own `Ord`/`PartialEq` and values via
969/// [Meta::eq_dyn], bypassing `keys`/`key`'s string round-trip.
970/// Both maps iterate in the same `K`-sorted order, so this is a single
971/// zipped pass rather than the generic default's per-key string lookup,
972/// and it works for any `K`, not just string-like keys.
973fn btree_map_eq<K, V>(this: &BTreeMap<K, V>, other: &dyn Meta) -> bool
974where
975  K: Ord + 'static,
976  V: Meta + 'static,
977{
978  let Some(other) = other.as_any().downcast_ref::<BTreeMap<K, V>>() else {
979    return false;
980  };
981
982  this.len() == other.len()
983    && this
984      .iter()
985      .zip(other)
986      .all(|((key, value), (other_key, other_value))| key == other_key && value.eq_dyn(other_value))
987}
988
989/// Compares native keys with `Eq`/`Hash` and values with [Meta::eq_dyn].
990/// This avoids `keys`/`key`'s string conversion and is
991/// independent of `HashMap` iteration order. Each key lookup takes `O(1)`
992/// time on average, so equality takes `O(n)` time on average.
993#[cfg(feature = "std")]
994fn hash_map_eq<K, V, S>(this: &HashMap<K, V, S>, other: &dyn Meta) -> bool
995where
996  K: Eq + Hash + 'static,
997  V: Meta + 'static,
998  S: core::hash::BuildHasher + 'static,
999{
1000  let Some(other) = other.as_any().downcast_ref::<HashMap<K, V, S>>() else {
1001    return false;
1002  };
1003
1004  this.len() == other.len()
1005    && this.iter().all(|(key, value)| {
1006      other
1007        .get(key)
1008        .is_some_and(|other_value| value.eq_dyn(other_value))
1009    })
1010}
1011
1012macro_rules! impl_typed_map_access {
1013  (
1014    type = $ty:ty,
1015    generics = [$($generics:tt)*],
1016    read_bounds = [$($read_bounds:tt)*],
1017    mut_bounds = [$($mut_bounds:tt)*] $(,)?
1018  ) => {
1019    impl<$($generics)*> TypedMapAccess<K> for $ty
1020    where
1021      $($read_bounds)*
1022    {
1023      fn key_typed(&self, key: &K) -> Option<ObjectRef<'_>> {
1024        self
1025          .get(key)
1026          .map(|value| ObjectRef::new(value))
1027      }
1028    }
1029
1030    impl<$($generics)*> TypedMapAccessMut<K> for $ty
1031    where
1032      $($mut_bounds)*
1033    {
1034      fn key_typed_mut(&mut self, key: &K) -> Option<ObjectRefMut<'_>> {
1035        self
1036          .get_mut(key)
1037          .map(|value| ObjectRefMut::new(value))
1038      }
1039    }
1040  };
1041}
1042
1043macro_rules! impl_map_mut {
1044  (
1045    type = $ty:ty,
1046    string_map = $string_map:ty,
1047    static_str_map = $static_str_map:ty,
1048    generics = [$($generics:tt)*],
1049    bounds = [$($bounds:tt)*],
1050    lookup = $lookup:ident $(,)?
1051  ) => {
1052    impl<$($generics)*> MetaMut for $ty
1053    where
1054      $($bounds)*
1055    {
1056      set_body!();
1057
1058      fn reflect_mut(&mut self) -> ReflectMut<'_> {
1059        ReflectMut::Map(self)
1060      }
1061
1062      fn as_any_mut(&mut self) -> &mut dyn Any {
1063        self
1064      }
1065    }
1066
1067    impl<$($generics)*> MapAccessMut for $ty
1068    where
1069      $($bounds)*
1070    {
1071      fn key_mut(&mut self, key: &str) -> Option<ObjectRefMut<'_>> {
1072        $lookup(self, key).map(|value| ObjectRefMut::new(value))
1073      }
1074
1075      fn insert_key(&mut self, key: &str, value: Object) -> Result<ObjectRefMut<'_>, Object> {
1076        if !value.is::<V>() {
1077          return Err(value);
1078        }
1079
1080        if TypeId::of::<K>() == TypeId::of::<String>() {
1081          // The type ID check guarantees that this downcast succeeds.
1082          let value = *value.into_inner().into_any().downcast::<V>().unwrap();
1083          let map = (self as &mut dyn Any)
1084            .downcast_mut::<$string_map>()
1085            .unwrap();
1086          map.insert(key.to_owned(), value);
1087          return Ok(MapAccessMut::key_mut(self, key).expect("just inserted"));
1088        }
1089
1090        // Any other `K` can't be built from a borrowed `&str`, so there's no
1091        // key to insert with.
1092        Err(value)
1093      }
1094
1095      fn remove_key(&mut self, key: &str) -> Option<Object> {
1096        if TypeId::of::<K>() == TypeId::of::<String>() {
1097          let map = (self as &mut dyn Any)
1098            .downcast_mut::<$string_map>()
1099            .unwrap();
1100          return map.remove(key).map(Object::new);
1101        }
1102        if TypeId::of::<K>() == TypeId::of::<&'static str>() {
1103          let map = (self as &mut dyn Any)
1104            .downcast_mut::<$static_str_map>()
1105            .unwrap();
1106          return map.remove(key).map(Object::new);
1107        }
1108
1109        // Any other `K` can't be matched against a borrowed `&str`.
1110        None
1111      }
1112    }
1113  };
1114}
1115impl_map_meta!(
1116  type = BTreeMap<K, V>,
1117  generics = [K, V],
1118  bounds = [K: Ord + 'static, V: Meta + 'static],
1119  lookup = btree_map_get,
1120  equality = btree_map_eq,
1121);
1122
1123impl_typed_map_access!(
1124  type = BTreeMap<K, V>,
1125  generics = [K, V],
1126  read_bounds = [K: Ord + 'static, V: Meta + 'static],
1127  mut_bounds = [K: Ord + 'static, V: MetaMut + 'static],
1128);
1129
1130impl_map_mut!(
1131  type = BTreeMap<K, V>,
1132  string_map = BTreeMap<String, V>,
1133  static_str_map = BTreeMap<&'static str, V>,
1134  generics = [K, V],
1135  bounds = [K: Ord + 'static, V: MetaMut + 'static],
1136  lookup = btree_map_get_mut,
1137);
1138
1139#[cfg(feature = "std")]
1140impl_map_meta!(
1141  type = HashMap<K, V, S>,
1142  generics = [K, V, S],
1143  bounds = [K: Eq + Hash + 'static, V: Meta + 'static, S: core::hash::BuildHasher + 'static],
1144  lookup = hash_map_get,
1145  equality = hash_map_eq,
1146);
1147
1148#[cfg(feature = "std")]
1149impl_typed_map_access!(
1150  type = HashMap<K, V, S>,
1151  generics = [K, V, S],
1152  read_bounds = [K: Eq + Hash + 'static, V: Meta + 'static, S: core::hash::BuildHasher + 'static],
1153  mut_bounds = [K: Eq + Hash + 'static, V: MetaMut + 'static, S: core::hash::BuildHasher + 'static],
1154);
1155
1156#[cfg(feature = "std")]
1157impl_map_mut!(
1158  type = HashMap<K, V, S>,
1159  string_map = HashMap<String, V, S>,
1160  static_str_map = HashMap<&'static str, V, S>,
1161  generics = [K, V, S],
1162  bounds = [K: Eq + Hash + 'static, V: MetaMut + 'static, S: core::hash::BuildHasher + 'static],
1163  lookup = hash_map_get_mut,
1164);