bones_schema/alloc/
map.rs

1use std::{
2    any::{type_name, TypeId},
3    fmt::Debug,
4    hash::{BuildHasher, Hasher},
5    marker::PhantomData,
6    sync::OnceLock,
7};
8
9use bones_utils::{default, HashMap};
10use hashbrown::hash_map;
11use parking_lot::RwLock;
12
13use crate::{
14    prelude::*,
15    raw_fns::{RawClone, RawDefault, RawDrop},
16};
17
18/// Untyped schema-aware "HashMap".
19#[derive(Clone, Debug)]
20pub struct SchemaMap {
21    map: HashMap<SchemaBox, SchemaBox>,
22    key_schema: &'static Schema,
23    value_schema: &'static Schema,
24}
25
26impl SchemaMap {
27    /// Create a new map, with the given key and value schemas.
28    pub fn new(key_schema: &'static Schema, value_schema: &'static Schema) -> Self {
29        assert!(
30            key_schema.hash_fn.is_some() && key_schema.eq_fn.is_some(),
31            "Key schema must implement hash and eq"
32        );
33        Self {
34            map: HashMap::default(),
35            key_schema,
36            value_schema,
37        }
38    }
39
40    /// Get the number of entries in the map.
41    #[inline]
42    pub fn len(&self) -> usize {
43        self.map.len()
44    }
45
46    /// Returns `true` if the map is empty.
47    #[inline]
48    pub fn is_empty(&self) -> bool {
49        self.map.is_empty()
50    }
51
52    /// Get the schema for the map keys.
53    pub fn key_schema(&self) -> &'static Schema {
54        self.key_schema
55    }
56
57    /// Get the schema for the map values.
58    pub fn value_schema(&self) -> &'static Schema {
59        self.value_schema
60    }
61
62    /// Insert an item into the map.
63    /// # Panics
64    /// Panics if the key or value schemas do not match the map's.
65    #[inline]
66    #[track_caller]
67    pub fn insert<K: HasSchema, V: HasSchema>(&mut self, key: K, value: V) -> Option<V> {
68        self.try_insert(key, value).unwrap()
69    }
70
71    /// Insert an item into the map.
72    /// # Errors
73    /// Errors if the key or value schemas do not match the map's.
74    pub fn try_insert<K: HasSchema, V: HasSchema>(
75        &mut self,
76        key: K,
77        value: V,
78    ) -> Result<Option<V>, SchemaMismatchError> {
79        let key = SchemaBox::new(key);
80        let value = SchemaBox::new(value);
81        self.try_insert_box(key, value)
82            // SOUND: try_insert_box won't succeed unless the schema's match, so we have already
83            // checked that the value schema matches.
84            .map(|value| value.map(|x| unsafe { x.cast_into_unchecked() }))
85    }
86
87    /// Insert an untyped item into the map.
88    /// # Panics
89    /// Panics if the key or value schemas do not match the map's.
90    #[track_caller]
91    #[inline]
92    pub fn insert_box(&mut self, key: SchemaBox, value: SchemaBox) -> Option<SchemaBox> {
93        self.try_insert_box(key, value).unwrap()
94    }
95
96    /// Insert an untyped item into the map.
97    /// # Errors
98    /// Errors if the key or value schemas do not match the map's.
99    pub fn try_insert_box(
100        &mut self,
101        key: SchemaBox,
102        value: SchemaBox,
103    ) -> Result<Option<SchemaBox>, SchemaMismatchError> {
104        if key.schema() != self.key_schema || value.schema() != self.value_schema {
105            Err(SchemaMismatchError)
106        } else {
107            // SOUnD: we've checked that the schemas are matching.
108            let previous_value = unsafe { self.insert_box_unchecked(key, value) };
109            Ok(previous_value)
110        }
111    }
112
113    /// # Safety
114    /// Key schema and value schema must match the map's.
115    pub unsafe fn insert_box_unchecked(
116        &mut self,
117        key: SchemaBox,
118        mut value: SchemaBox,
119    ) -> Option<SchemaBox> {
120        let hash = {
121            let mut hasher = self.map.hasher().build_hasher();
122            hasher.write_u64(key.hash());
123            hasher.finish()
124        };
125        let entry = self
126            .map
127            .raw_entry_mut()
128            .from_hash(hash, |other| other == &key);
129        // Return the previous value.
130        match entry {
131            hash_map::RawEntryMut::Occupied(mut occupied) => {
132                std::mem::swap(occupied.get_mut(), &mut value);
133                Some(value)
134            }
135            hash_map::RawEntryMut::Vacant(vacant) => {
136                vacant.insert(key, value);
137                None
138            }
139        }
140    }
141
142    /// Get a value out of the map for the given key.
143    /// # Panics
144    /// Panics if the schemas of the key and value don't match the schemas of the map.
145    #[track_caller]
146    #[inline]
147    pub fn get<K: HasSchema, V: HasSchema>(&self, key: &K) -> Option<&V> {
148        self.try_get(key).unwrap()
149    }
150
151    /// Get a value out of the map for the given key.
152    /// # Errors
153    /// Errors if the schemas of the key and value don't match the schemas of the map.
154    #[track_caller]
155    pub fn try_get<K: HasSchema, V: HasSchema>(
156        &self,
157        key: &K,
158    ) -> Result<Option<&V>, SchemaMismatchError> {
159        if K::schema() != self.key_schema || V::schema() != self.value_schema {
160            Err(SchemaMismatchError)
161        } else {
162            // SOUND: we've veriried that they key schema matches the map's
163            let value = unsafe { self.get_ref_unchecked(SchemaRef::new(key)) }
164                // SOUND: we've verified that the value schema maches the map's
165                .map(|x| unsafe { x.cast_into_unchecked() });
166
167            Ok(value)
168        }
169    }
170
171    /// Get an untyped reference to an item in the map.
172    /// # Panics
173    /// Panics if the schema of the key doesn't match.
174    #[inline]
175    #[track_caller]
176    pub fn get_ref(&self, key: SchemaRef) -> Option<SchemaRef<'_>> {
177        self.try_get_ref(key).unwrap()
178    }
179
180    /// Get an untyped reference to an item in the map.
181    /// # Errors
182    /// Errors if the schema of the key doesn't match.
183    pub fn try_get_ref(
184        &self,
185        key: SchemaRef,
186    ) -> Result<Option<SchemaRef<'_>>, SchemaMismatchError> {
187        if key.schema() != self.key_schema {
188            Err(SchemaMismatchError)
189        } else {
190            // SOUND: we've check the key schema matches.
191            Ok(unsafe { self.get_ref_unchecked(key) })
192        }
193    }
194
195    /// # Safety
196    /// The key's schema must match this map's key schema.
197    pub unsafe fn get_ref_unchecked(&self, key: SchemaRef) -> Option<SchemaRef<'_>> {
198        let Some(hash_fn) = &self.key_schema.hash_fn else {
199            panic!("Key schema doesn't implement hash");
200        };
201        let Some(eq_fn) = &self.key_schema.eq_fn else {
202            panic!("Key schema doesn't implement eq");
203        };
204        let key_ptr = key.as_ptr();
205        // SOUND: caller asserts the key schema matches
206        let raw_hash = unsafe { (hash_fn.get())(key_ptr) };
207        let hash = {
208            let mut hasher = self.map.hasher().build_hasher();
209            hasher.write_u64(raw_hash);
210            hasher.finish()
211        };
212        self.map
213            .raw_entry()
214            .from_hash(hash, |key| {
215                let other_ptr = key.as_ref().as_ptr();
216                // SOUND: caller asserts the key schema matches.
217                unsafe { (eq_fn.get())(key_ptr, other_ptr) }
218            })
219            .map(|x| x.1.as_ref())
220    }
221
222    /// Get an untyped reference to an item in the map.
223    /// # Panics
224    /// Panics if the schema of the key doesn't match.
225    #[inline]
226    #[track_caller]
227    pub fn get_ref_mut(&mut self, key: SchemaRef) -> Option<SchemaRefMut<'_>> {
228        self.try_get_ref_mut(key).unwrap()
229    }
230
231    /// Get an untyped reference to an item in the map.
232    /// # Errors
233    /// Errors if the schema of the key doesn't match.
234    pub fn try_get_ref_mut(
235        &mut self,
236        key: SchemaRef,
237    ) -> Result<Option<SchemaRefMut<'_>>, SchemaMismatchError> {
238        if key.schema() != self.key_schema {
239            Err(SchemaMismatchError)
240        } else {
241            // SOUND: we've checked that the key schema matches.
242            Ok(unsafe { self.get_ref_unchecked_mut(key) })
243        }
244    }
245
246    /// # Safety
247    /// The key's schema must match this map's key schema.
248    pub unsafe fn get_ref_unchecked_mut(&mut self, key: SchemaRef) -> Option<SchemaRefMut<'_>> {
249        let Some(hash_fn) = &self.key_schema.hash_fn else {
250            panic!("Key schema doesn't implement hash");
251        };
252        let Some(eq_fn) = &self.key_schema.eq_fn else {
253            panic!("Key schema doesn't implement eq");
254        };
255        let key_ptr = key.as_ptr();
256        // SOUND: caller asserts the key schema matches
257        let raw_hash = unsafe { (hash_fn.get())(key_ptr) };
258        let hash = {
259            let mut hasher = self.map.hasher().build_hasher();
260            hasher.write_u64(raw_hash);
261            hasher.finish()
262        };
263        let entry = self.map.raw_entry_mut().from_hash(hash, |key| {
264            let other_ptr = key.as_ref().as_ptr();
265            // SOUND: caller asserts the key schema matches.
266            unsafe { (eq_fn.get())(key_ptr, other_ptr) }
267        });
268        match entry {
269            hash_map::RawEntryMut::Occupied(entry) => Some(entry.into_mut()),
270            hash_map::RawEntryMut::Vacant(_) => None,
271        }
272        .map(|x| x.as_mut())
273    }
274
275    /// Get a value out of the map for the given key.
276    /// # Panics
277    /// Panics if the schemas of the key and value don't match the schemas of the map.
278    #[track_caller]
279    #[inline]
280    pub fn get_mut<K: HasSchema, V: HasSchema>(&mut self, key: &K) -> Option<&mut V> {
281        self.try_get_mut(key).unwrap()
282    }
283
284    /// Get a value out of the map for the given key.
285    /// # Errors
286    /// Errors if the schemas of the key and value don't match the schemas of the map.
287    #[track_caller]
288    pub fn try_get_mut<K: HasSchema, V: HasSchema>(
289        &mut self,
290        key: &K,
291    ) -> Result<Option<&mut V>, SchemaMismatchError> {
292        if K::schema() != self.key_schema || V::schema() != self.value_schema {
293            Err(SchemaMismatchError)
294        } else {
295            // SOUND: we've checked that the key schema matches.
296            let value = unsafe { self.get_ref_unchecked_mut(SchemaRef::new(key)) }
297                // SOUND: we've checked that the value schema matches.
298                .map(|x| unsafe { x.cast_into_mut_unchecked() });
299            Ok(value)
300        }
301    }
302
303    /// Remove an item.
304    /// # Panics
305    /// Panics if the schemas of the key and value don't match the map.
306    #[inline]
307    #[track_caller]
308    pub fn remove<K: HasSchema, V: HasSchema>(&mut self, key: &K) -> Option<V> {
309        self.try_remove(key).unwrap()
310    }
311
312    /// Remove an item.
313    /// # Errors
314    /// Errors if the schemas of the key and value don't match the map.
315    pub fn try_remove<K: HasSchema, V: HasSchema>(
316        &mut self,
317        key: &K,
318    ) -> Result<Option<V>, SchemaMismatchError> {
319        if K::schema() != self.key_schema || V::schema() != self.value_schema {
320            Err(SchemaMismatchError)
321        } else {
322            // SOUND: we've checked that the key schema matches.
323            let value = unsafe { self.remove_unchecked(SchemaRef::new(key)) }
324                // SOUND: we've checked that the value schema matches.
325                .map(|x| unsafe { x.cast_into_unchecked() });
326            Ok(value)
327        }
328    }
329
330    /// Untypededly remove an item.
331    /// # Panics
332    /// Panics if the key schema does not match the map's.
333    #[inline]
334    #[track_caller]
335    pub fn remove_box(&mut self, key: SchemaRef) -> Option<SchemaBox> {
336        self.try_remove_box(key).unwrap()
337    }
338
339    /// Untypededly remove an item.
340    /// # Errors
341    /// Errors if the key schema does not match the map's.
342    pub fn try_remove_box(
343        &mut self,
344        key: SchemaRef,
345    ) -> Result<Option<SchemaBox>, SchemaMismatchError> {
346        if key.schema() != self.key_schema {
347            Err(SchemaMismatchError)
348        } else {
349            // SOUND: we've checked the key schema matches.
350            Ok(unsafe { self.remove_unchecked(key) })
351        }
352    }
353
354    /// # Safety
355    /// The key schema must match the map's.
356    pub unsafe fn remove_unchecked(&mut self, key: SchemaRef) -> Option<SchemaBox> {
357        let Some(hash_fn) = &self.key_schema.hash_fn else {
358            panic!("Key schema doesn't implement hash");
359        };
360        let Some(eq_fn) = &self.key_schema.eq_fn else {
361            panic!("Key schema doesn't implement eq");
362        };
363        let key_ptr = key.as_ptr();
364        // SOUND: caller asserts the key schema matches
365        let hash = unsafe { (hash_fn.get())(key_ptr) };
366        let hash = {
367            let mut hasher = self.map.hasher().build_hasher();
368            hasher.write_u64(hash);
369            hasher.finish()
370        };
371        let entry = self.map.raw_entry_mut().from_hash(hash, |key| {
372            let other_ptr = key.as_ref().as_ptr();
373            // SOUND: caller asserts the key schema matches
374            unsafe { (eq_fn.get())(key_ptr, other_ptr) }
375        });
376        match entry {
377            hash_map::RawEntryMut::Occupied(entry) => Some(entry.remove()),
378            hash_map::RawEntryMut::Vacant(_) => None,
379        }
380    }
381
382    /// Convert into a typed [`SMap`].
383    /// # Panics
384    /// Panics if the schemas of K and V don't match the [`SchemaMap`].
385    #[inline]
386    #[track_caller]
387    pub fn into_smap<K: HasSchema, V: HasSchema>(self) -> SMap<K, V> {
388        self.try_into_smap().unwrap()
389    }
390
391    /// Convert into a typed [`SMap`].
392    /// # Errors
393    /// Errors if the schemas of K and V don't match the [`SchemaMap`].
394    pub fn try_into_smap<K: HasSchema, V: HasSchema>(
395        self,
396    ) -> Result<SMap<K, V>, SchemaMismatchError> {
397        if K::schema() == self.key_schema && V::schema() == self.value_schema {
398            Ok(SMap {
399                map: self,
400                _phantom: PhantomData,
401            })
402        } else {
403            Err(SchemaMismatchError)
404        }
405    }
406}
407
408impl<K: HasSchema, V: HasSchema> FromIterator<(K, V)> for SMap<K, V> {
409    fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
410        let mut this = Self::default();
411        for (k, v) in iter {
412            this.insert(k, v);
413        }
414        this
415    }
416}
417
418impl<K: HasSchema, V: HasSchema> std::ops::Index<&K> for SMap<K, V> {
419    type Output = V;
420    fn index(&self, index: &K) -> &Self::Output {
421        self.get(index).unwrap()
422    }
423}
424impl<K: HasSchema, V: HasSchema> std::ops::IndexMut<&K> for SMap<K, V> {
425    fn index_mut(&mut self, index: &K) -> &mut Self::Output {
426        self.get_mut(index).unwrap()
427    }
428}
429
430type SchemaMapIter<'iter> = std::iter::Map<
431    hash_map::Iter<'iter, SchemaBox, SchemaBox>,
432    for<'a> fn((&'a SchemaBox, &'a SchemaBox)) -> (SchemaRef<'a>, SchemaRef<'a>),
433>;
434type SchemaMapIterMut<'iter> = std::iter::Map<
435    hash_map::IterMut<'iter, SchemaBox, SchemaBox>,
436    for<'a> fn((&'a SchemaBox, &'a mut SchemaBox)) -> (SchemaRef<'a>, SchemaRefMut<'a>),
437>;
438impl SchemaMap {
439    /// Iterate over entries in the map.
440    #[allow(clippy::type_complexity)]
441    pub fn iter(&self) -> SchemaMapIter<'_> {
442        fn map_fn<'a>(
443            (key, value): (&'a SchemaBox, &'a SchemaBox),
444        ) -> (SchemaRef<'a>, SchemaRef<'a>) {
445            (key.as_ref(), value.as_ref())
446        }
447        self.map.iter().map(map_fn)
448    }
449
450    /// Iterate over entries in the map.
451    #[allow(clippy::type_complexity)]
452    pub fn iter_mut(&mut self) -> SchemaMapIterMut<'_> {
453        fn map_fn<'a>(
454            (key, value): (&'a SchemaBox, &'a mut SchemaBox),
455        ) -> (SchemaRef<'a>, SchemaRefMut<'a>) {
456            (key.as_ref(), value.as_mut())
457        }
458        self.map.iter_mut().map(map_fn)
459    }
460
461    /// Iterate over keys in the map.
462    #[allow(clippy::type_complexity)]
463    pub fn keys(
464        &self,
465    ) -> std::iter::Map<
466        hash_map::Keys<'_, SchemaBox, SchemaBox>,
467        for<'a> fn(&'a SchemaBox) -> SchemaRef<'a>,
468    > {
469        fn map_fn(key: &SchemaBox) -> SchemaRef<'_> {
470            key.as_ref()
471        }
472        self.map.keys().map(map_fn)
473    }
474
475    /// Iterate over values in the map.
476    #[allow(clippy::type_complexity)]
477    pub fn values(
478        &self,
479    ) -> std::iter::Map<
480        hash_map::Values<'_, SchemaBox, SchemaBox>,
481        for<'a> fn(&'a SchemaBox) -> SchemaRef<'a>,
482    > {
483        fn map_fn(key: &SchemaBox) -> SchemaRef<'_> {
484            key.as_ref()
485        }
486        self.map.values().map(map_fn)
487    }
488
489    /// Iterate over values in the map.
490    #[allow(clippy::type_complexity)]
491    pub fn values_mut(
492        &mut self,
493    ) -> std::iter::Map<
494        hash_map::ValuesMut<'_, SchemaBox, SchemaBox>,
495        for<'a> fn(&'a mut SchemaBox) -> SchemaRefMut<'a>,
496    > {
497        fn map_fn(key: &mut SchemaBox) -> SchemaRefMut<'_> {
498            key.as_mut()
499        }
500        self.map.values_mut().map(map_fn)
501    }
502}
503impl<'a> IntoIterator for &'a SchemaMap {
504    type Item = (SchemaRef<'a>, SchemaRef<'a>);
505    type IntoIter = SchemaMapIter<'a>;
506    fn into_iter(self) -> Self::IntoIter {
507        self.iter()
508    }
509}
510impl<'a> IntoIterator for &'a mut SchemaMap {
511    type Item = (SchemaRef<'a>, SchemaRefMut<'a>);
512    type IntoIter = SchemaMapIterMut<'a>;
513    fn into_iter(self) -> Self::IntoIter {
514        self.iter_mut()
515    }
516}
517
518/// Typed version of a [`SchemaMap`].
519///
520/// This works essentially like a [`HashMap`], but is compatible with the schema ecosystem.
521///
522/// It is also slightly more efficient to access an [`SMap`] compared to a [`SchemaMap`] because it
523/// doesn't need to do a runtime schema check every time the map is accessed.
524pub struct SMap<K: HasSchema, V: HasSchema> {
525    map: SchemaMap,
526    _phantom: PhantomData<(K, V)>,
527}
528impl<K: HasSchema + Debug, V: HasSchema + Debug> Debug for SMap<K, V> {
529    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
530        let mut f = f.debug_map();
531        for (k, v) in self {
532            f.entry(k, v);
533        }
534        f.finish()
535    }
536}
537impl<K: HasSchema, V: HasSchema> Clone for SMap<K, V> {
538    fn clone(&self) -> Self {
539        Self {
540            map: self.map.clone(),
541            _phantom: self._phantom,
542        }
543    }
544}
545impl<K: HasSchema, V: HasSchema> Default for SMap<K, V> {
546    fn default() -> Self {
547        Self {
548            map: SchemaMap::new(K::schema(), V::schema()),
549            _phantom: Default::default(),
550        }
551    }
552}
553unsafe impl<K: HasSchema, V: HasSchema> HasSchema for SMap<K, V> {
554    fn schema() -> &'static Schema {
555        static S: OnceLock<RwLock<HashMap<TypeId, &'static Schema>>> = OnceLock::new();
556        let schema = {
557            S.get_or_init(default)
558                .read()
559                .get(&TypeId::of::<Self>())
560                .copied()
561        };
562        schema.unwrap_or_else(|| {
563            let schema = SCHEMA_REGISTRY.register(SchemaData {
564                name: type_name::<Self>().into(),
565                full_name: format!("{}::{}", module_path!(), type_name::<Self>()).into(),
566                kind: SchemaKind::Map {
567                    key: K::schema(),
568                    value: V::schema(),
569                },
570                type_id: Some(TypeId::of::<Self>()),
571                clone_fn: Some(<Self as RawClone>::raw_clone_cb()),
572                drop_fn: Some(<Self as RawDrop>::raw_drop_cb()),
573                default_fn: Some(<Self as RawDefault>::raw_default_cb()),
574                hash_fn: Some(unsafe {
575                    Unsafe::new(Box::leak(Box::new(|a| SchemaVec::raw_hash(a))))
576                }),
577                eq_fn: Some(unsafe {
578                    Unsafe::new(Box::leak(Box::new(|a, b| SchemaVec::raw_eq(a, b))))
579                }),
580                type_data: Default::default(),
581            });
582
583            S.get_or_init(default)
584                .write()
585                .insert(TypeId::of::<Self>(), schema);
586
587            schema
588        })
589    }
590}
591
592impl<K: HasSchema, V: HasSchema> SMap<K, V> {
593    /// Initialize the [`SMap`].
594    pub fn new() -> Self {
595        Self::default()
596    }
597
598    /// Insert an entry into the map, returning the previous value, if it exists.
599    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
600        // SOUND: schemas are checked to match when SMap is constructed.
601        unsafe {
602            self.map
603                .insert_box_unchecked(SchemaBox::new(k), SchemaBox::new(v))
604                .map(|x| x.cast_into_unchecked())
605        }
606    }
607
608    /// Get a reference to an item in the map.
609    pub fn get(&self, key: &K) -> Option<&V> {
610        // SOUND: schemas are checked to match when SMap is constructed.
611        unsafe {
612            self.map
613                .get_ref_unchecked(SchemaRef::new(key))
614                .map(|x| x.cast_into_unchecked())
615        }
616    }
617
618    /// Get a mutable reference to an item in the map.
619    pub fn get_mut(&mut self, key: &K) -> Option<&mut V> {
620        // SOUND: schemas are checked to match when SMap is constructed.
621        unsafe {
622            self.map
623                .get_ref_unchecked_mut(SchemaRef::new(key))
624                .map(|x| x.cast_into_mut_unchecked())
625        }
626    }
627
628    /// Remove an item from the map.
629    pub fn remove(&mut self, key: &K) -> Option<V> {
630        // SOUND: schemas are checked to match when SMap is constructed.
631        unsafe {
632            self.map
633                .remove_unchecked(SchemaRef::new(key))
634                .map(|x| x.cast_into_unchecked())
635        }
636    }
637
638    /// Convert into an untyped [`SchemaMap`].
639    pub fn into_schema_map(self) -> SchemaMap {
640        self.map
641    }
642
643    /// Returns true if the map contains a value for the specified key.
644    pub fn contains_key(&self, key: &K) -> bool {
645        self.map.get::<K, V>(key).is_some()
646    }
647
648    /// Returns the number of elements in the map.
649    pub fn len(&self) -> usize {
650        self.map.len()
651    }
652
653    /// Returns true if the map contains no elements.
654    pub fn is_empty(&self) -> bool {
655        self.map.is_empty()
656    }
657}
658
659type SMapIter<'iter, K, V> = std::iter::Map<
660    hash_map::Iter<'iter, SchemaBox, SchemaBox>,
661    for<'a> fn((&'a SchemaBox, &'a SchemaBox)) -> (&'a K, &'a V),
662>;
663type SMapIterMut<'iter, K, V> = std::iter::Map<
664    hash_map::IterMut<'iter, SchemaBox, SchemaBox>,
665    for<'a> fn((&'a SchemaBox, &'a mut SchemaBox)) -> (&'a K, &'a mut V),
666>;
667impl<K: HasSchema, V: HasSchema> SMap<K, V> {
668    /// Iterate over entries in the map.
669    #[allow(clippy::type_complexity)]
670    pub fn iter(&self) -> SMapIter<'_, K, V> {
671        fn map_fn<'a, K: HasSchema, V: HasSchema>(
672            (key, value): (&'a SchemaBox, &'a SchemaBox),
673        ) -> (&'a K, &'a V) {
674            // SOUND: SMap ensures K and V schemas always match.
675            unsafe {
676                (
677                    key.as_ref().cast_into_unchecked(),
678                    value.as_ref().cast_into_unchecked(),
679                )
680            }
681        }
682        self.map.map.iter().map(map_fn)
683    }
684
685    /// Iterate over entries in the map.
686    #[allow(clippy::type_complexity)]
687    pub fn iter_mut(&mut self) -> SMapIterMut<'_, K, V> {
688        fn map_fn<'a, K: HasSchema, V: HasSchema>(
689            (key, value): (&'a SchemaBox, &'a mut SchemaBox),
690        ) -> (&'a K, &'a mut V) {
691            // SOUND: SMap ensures K and V schemas always match.
692            unsafe {
693                (
694                    key.as_ref().cast_into_unchecked(),
695                    value.as_mut().cast_into_mut_unchecked(),
696                )
697            }
698        }
699        self.map.map.iter_mut().map(map_fn)
700    }
701
702    /// Iterate over keys in the map.
703    #[allow(clippy::type_complexity)]
704    pub fn keys(
705        &self,
706    ) -> std::iter::Map<hash_map::Keys<'_, SchemaBox, SchemaBox>, for<'a> fn(&'a SchemaBox) -> &'a K>
707    {
708        fn map_fn<K: HasSchema>(key: &SchemaBox) -> &K {
709            // SOUND: SMap ensures key schema always match
710            unsafe { key.as_ref().cast_into_unchecked() }
711        }
712        self.map.map.keys().map(map_fn)
713    }
714
715    /// Iterate over values in the map.
716    #[allow(clippy::type_complexity)]
717    pub fn values(
718        &self,
719    ) -> std::iter::Map<
720        hash_map::Values<'_, SchemaBox, SchemaBox>,
721        for<'a> fn(&'a SchemaBox) -> &'a V,
722    > {
723        fn map_fn<V: HasSchema>(value: &SchemaBox) -> &V {
724            // SOUND: SMap ensures value schema always matches.
725            unsafe { value.as_ref().cast_into_unchecked() }
726        }
727        self.map.map.values().map(map_fn)
728    }
729
730    /// Iterate over values in the map.
731    #[allow(clippy::type_complexity)]
732    pub fn values_mut(
733        &mut self,
734    ) -> std::iter::Map<
735        hash_map::ValuesMut<'_, SchemaBox, SchemaBox>,
736        for<'a> fn(&'a mut SchemaBox) -> &'a mut V,
737    > {
738        fn map_fn<V>(value: &mut SchemaBox) -> &mut V {
739            // SOUND: SMap ensures value schema always matches
740            unsafe { value.as_mut().cast_into_mut_unchecked() }
741        }
742        self.map.map.values_mut().map(map_fn)
743    }
744}
745impl<'a, K: HasSchema, V: HasSchema> IntoIterator for &'a SMap<K, V> {
746    type Item = (&'a K, &'a V);
747    type IntoIter = SMapIter<'a, K, V>;
748    fn into_iter(self) -> Self::IntoIter {
749        self.iter()
750    }
751}
752impl<'a, K: HasSchema, V: HasSchema> IntoIterator for &'a mut SMap<K, V> {
753    type Item = (&'a K, &'a mut V);
754    type IntoIter = SMapIterMut<'a, K, V>;
755    fn into_iter(self) -> Self::IntoIter {
756        self.iter_mut()
757    }
758}