rkyv/collections/hash_map/
validation.rs1use crate::{
4 collections::{
5 hash_index::validation::HashIndexError,
6 hash_map::ArchivedHashMap,
7 util::{validation::ArchivedEntryError, Entry},
8 ArchivedHashIndex,
9 },
10 validation::ArchiveContext,
11 RelPtr,
12};
13use bytecheck::{CheckBytes, Error, SliceCheckError};
14use core::{
15 alloc::{Layout, LayoutError},
16 convert::Infallible,
17 fmt,
18 hash::Hash,
19 ptr,
20};
21
22#[derive(Debug)]
24pub enum HashMapError<K, V, C> {
25 HashIndexError(HashIndexError<C>),
27 LayoutError(LayoutError),
29 CheckEntryError(SliceCheckError<ArchivedEntryError<K, V>>),
31 InvalidKeyPosition {
33 index: usize,
35 },
36 ContextError(C),
38}
39
40impl<K: fmt::Display, V: fmt::Display, E: fmt::Display> fmt::Display for HashMapError<K, V, E> {
41 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42 match self {
43 HashMapError::HashIndexError(e) => write!(f, "hash index check error: {}", e),
44 HashMapError::LayoutError(e) => write!(f, "layout error: {}", e),
45 HashMapError::CheckEntryError(e) => write!(f, "entry check error: {}", e),
46 HashMapError::InvalidKeyPosition { index } => {
47 write!(f, "invalid key position: at index {}", index)
48 }
49 HashMapError::ContextError(e) => e.fmt(f),
50 }
51 }
52}
53
54#[cfg(feature = "std")]
55const _: () = {
56 use std::error::Error;
57
58 impl<K, V, C> Error for HashMapError<K, V, C>
59 where
60 K: Error + 'static,
61 V: Error + 'static,
62 C: Error + 'static,
63 {
64 fn source(&self) -> Option<&(dyn Error + 'static)> {
65 match self {
66 HashMapError::HashIndexError(e) => Some(e as &dyn Error),
67 HashMapError::LayoutError(e) => Some(e as &dyn Error),
68 HashMapError::CheckEntryError(e) => Some(e as &dyn Error),
69 HashMapError::InvalidKeyPosition { .. } => None,
70 HashMapError::ContextError(e) => Some(e as &dyn Error),
71 }
72 }
73 }
74};
75
76impl<K, V, C> From<Infallible> for HashMapError<K, V, C> {
77 fn from(_: Infallible) -> Self {
78 unsafe { core::hint::unreachable_unchecked() }
79 }
80}
81
82impl<K, V, C> From<SliceCheckError<Infallible>> for HashMapError<K, V, C> {
83 #[inline]
84 fn from(_: SliceCheckError<Infallible>) -> Self {
85 unsafe { core::hint::unreachable_unchecked() }
86 }
87}
88
89impl<K, V, C> From<HashIndexError<C>> for HashMapError<K, V, C> {
90 #[inline]
91 fn from(e: HashIndexError<C>) -> Self {
92 Self::HashIndexError(e)
93 }
94}
95
96impl<K, V, C> From<LayoutError> for HashMapError<K, V, C> {
97 #[inline]
98 fn from(e: LayoutError) -> Self {
99 Self::LayoutError(e)
100 }
101}
102
103impl<K, V, C> From<SliceCheckError<ArchivedEntryError<K, V>>> for HashMapError<K, V, C> {
104 #[inline]
105 fn from(e: SliceCheckError<ArchivedEntryError<K, V>>) -> Self {
106 Self::CheckEntryError(e)
107 }
108}
109
110impl<K, V, C> CheckBytes<C> for ArchivedHashMap<K, V>
111where
112 K: CheckBytes<C> + Eq + Hash,
113 V: CheckBytes<C>,
114 C: ArchiveContext + ?Sized,
115 C::Error: Error,
116{
117 type Error = HashMapError<K::Error, V::Error, C::Error>;
118
119 unsafe fn check_bytes<'a>(
120 value: *const Self,
121 context: &mut C,
122 ) -> Result<&'a Self, Self::Error> {
123 let index = ArchivedHashIndex::check_bytes(ptr::addr_of!((*value).index), context)?;
124 Layout::array::<Entry<K, V>>(index.len())?;
125
126 let entries_rel_ptr = RelPtr::manual_check_bytes(ptr::addr_of!((*value).entries), context)?;
127 let entries_ptr = context
128 .check_subtree_ptr::<[Entry<K, V>]>(
129 entries_rel_ptr.base(),
130 entries_rel_ptr.offset(),
131 index.len(),
132 )
133 .map_err(HashMapError::ContextError)?;
134
135 let range = context
136 .push_prefix_subtree(entries_ptr)
137 .map_err(HashMapError::ContextError)?;
138 let entries = <[Entry<K, V>]>::check_bytes(entries_ptr, context)?;
139 context
140 .pop_prefix_range(range)
141 .map_err(HashMapError::ContextError)?;
142
143 for (i, entry) in entries.iter().enumerate() {
144 if index.index(&entry.key) != Some(i) {
145 return Err(HashMapError::InvalidKeyPosition { index: i });
146 }
147 }
148
149 Ok(&*value)
150 }
151}