casper_wasm/elements/
index_map.rs

1use crate::io;
2use alloc::collections::BTreeMap;
3
4use super::{Deserialize, Error, Serialize, VarUint32};
5
6use core::iter::{FromIterator, IntoIterator};
7
8/// A map from non-contiguous `u32` keys to values of type `T`, which is
9/// serialized and deserialized ascending order of the keys. Normally used for
10/// relative dense maps with occasional "holes", and stored as an array.
11#[derive(Debug, Default)]
12pub struct IndexMap<T> {
13	/// An ordered map of entries. Missing entries are represented as `None`.
14	entries: BTreeMap<u32, T>,
15}
16
17impl<T> IndexMap<T> {
18	/// Create an empty `IndexMap`.
19	pub fn new() -> IndexMap<T> {
20		IndexMap { entries: BTreeMap::new() }
21	}
22
23	/// Create an empty `IndexMap`, preallocating enough space to store
24	/// `capacity` entries without needing to reallocate the underlying memory.
25	///
26	/// # Note
27	/// Currently, this method has no effect and is equivalent to [`IndexMap::new`] call.
28	#[deprecated]
29	pub fn with_capacity(_capacity: usize) -> IndexMap<T> {
30		Self::new()
31	}
32
33	/// Clear the map.
34	#[inline]
35	pub fn clear(&mut self) {
36		self.entries.clear();
37	}
38
39	/// Return the name for the specified index, if it exists.
40	#[inline]
41	pub fn get(&self, idx: u32) -> Option<&T> {
42		self.entries.get(&idx)
43	}
44
45	/// Does the map contain an entry for the specified index?
46	#[inline]
47	pub fn contains_key(&self, idx: u32) -> bool {
48		self.entries.contains_key(&idx)
49	}
50
51	/// Insert a name into our map, returning the existing value if present.
52	#[inline]
53	pub fn insert(&mut self, idx: u32, value: T) -> Option<T> {
54		self.entries.insert(idx, value)
55	}
56
57	/// Remove an item if present and return it.
58	#[inline]
59	pub fn remove(&mut self, idx: u32) -> Option<T> {
60		self.entries.remove(&idx)
61	}
62
63	/// The number of items in this map.
64	#[inline]
65	pub fn len(&self) -> usize {
66		self.entries.len()
67	}
68
69	/// Is this map empty?
70	#[inline]
71	pub fn is_empty(&self) -> bool {
72		self.entries.is_empty()
73	}
74
75	/// Create a non-consuming iterator over this `IndexMap`'s keys and values.
76	pub fn iter(&self) -> impl Iterator<Item = (u32, &T)> {
77		// Note that this does the right thing because we use `&self`.
78		self.entries.iter().map(|(k, v)| (*k, v))
79	}
80
81	// /// Create a consuming iterator over this `IndexMap`'s keys and values.
82	// pub fn into_iter(self) -> impl Iterator<Item = (u32, T)> {
83	// 	self.entries.into_iter()
84	// }
85
86	/// Custom deserialization routine.
87	///
88	/// We will allocate an underlying array no larger than `max_entry_space` to
89	/// hold the data, so the maximum index must be less than `max_entry_space`.
90	/// This prevents mallicious *.wasm files from having a single entry with
91	/// the index `u32::MAX`, which would consume far too much memory.
92	///
93	/// The `deserialize_value` function will be passed the index of the value
94	/// being deserialized, and must deserialize the value.
95	pub fn deserialize_with<R, F>(
96		max_entry_space: usize,
97		deserialize_value: &F,
98		rdr: &mut R,
99	) -> Result<IndexMap<T>, Error>
100	where
101		R: io::Read,
102		F: Fn(u32, &mut R) -> Result<T, Error>,
103	{
104		let len: u32 = VarUint32::deserialize(rdr)?.into();
105		let mut map = IndexMap::new();
106		let mut prev_idx = None;
107		for _ in 0..len {
108			let idx: u32 = VarUint32::deserialize(rdr)?.into();
109			if idx as usize >= max_entry_space {
110				return Err(Error::Other("index is larger than expected"));
111			}
112			match prev_idx {
113				Some(prev) if prev >= idx => {
114					// Supposedly these names must be "sorted by index", so
115					// let's try enforcing that and seeing what happens.
116					return Err(Error::Other("indices are out of order"));
117				},
118				_ => {
119					prev_idx = Some(idx);
120				},
121			}
122			let val = deserialize_value(idx, rdr)?;
123			map.insert(idx, val);
124		}
125		Ok(map)
126	}
127}
128
129impl<T: Clone> Clone for IndexMap<T> {
130	fn clone(&self) -> IndexMap<T> {
131		IndexMap { entries: self.entries.clone() }
132	}
133}
134
135impl<T: PartialEq> PartialEq<IndexMap<T>> for IndexMap<T> {
136	fn eq(&self, other: &IndexMap<T>) -> bool {
137		self.entries.eq(&other.entries)
138	}
139}
140
141impl<T: Eq> Eq for IndexMap<T> {}
142
143impl<T> FromIterator<(u32, T)> for IndexMap<T> {
144	/// Create an `IndexMap` from an iterator.
145	///
146	/// Note: This API is designed for reasonably dense indices based on valid
147	/// data. Inserting a huge `idx` will use up a lot of RAM, and this function
148	/// will not try to protect you against that.
149	fn from_iter<I>(iter: I) -> Self
150	where
151		I: IntoIterator<Item = (u32, T)>,
152	{
153		let iter = iter.into_iter();
154		let mut map = IndexMap::new();
155		for (idx, value) in iter {
156			map.insert(idx, value);
157		}
158		map
159	}
160}
161
162impl<T> IntoIterator for IndexMap<T> {
163	type Item = (u32, T);
164
165	type IntoIter = <BTreeMap<u32, T> as IntoIterator>::IntoIter;
166
167	#[inline]
168	fn into_iter(self) -> Self::IntoIter {
169		self.entries.into_iter()
170	}
171}
172
173impl<T> Serialize for IndexMap<T>
174where
175	T: Serialize,
176	Error: From<<T as Serialize>::Error>,
177{
178	type Error = Error;
179
180	fn serialize<W: io::Write>(self, wtr: &mut W) -> Result<(), Self::Error> {
181		VarUint32::try_from(self.len())
182			.map_err(|_| Self::Error::InvalidVarInt32)?
183			.serialize(wtr)?;
184		for (idx, value) in self.entries.into_iter() {
185			VarUint32::from(idx).serialize(wtr)?;
186			value.serialize(wtr)?;
187		}
188		Ok(())
189	}
190}
191
192impl<T: Deserialize> IndexMap<T>
193where
194	T: Deserialize,
195	Error: From<<T as Deserialize>::Error>,
196{
197	/// Deserialize a map containing simple values that support `Deserialize`.
198	/// We will allocate an underlying array no larger than `max_entry_space` to
199	/// hold the data, so the maximum index must be less than `max_entry_space`.
200	pub fn deserialize<R: io::Read>(max_entry_space: usize, rdr: &mut R) -> Result<Self, Error> {
201		let deserialize_value: fn(u32, &mut R) -> Result<T, Error> =
202			|_idx, rdr| T::deserialize(rdr).map_err(Error::from);
203		Self::deserialize_with(max_entry_space, &deserialize_value, rdr)
204	}
205}
206
207#[cfg(test)]
208mod tests {
209	use super::*;
210	use crate::{
211		alloc::string::{String, ToString},
212		io,
213	};
214
215	#[test]
216	fn default_is_empty_no_matter_how_we_look_at_it() {
217		let map = IndexMap::<String>::default();
218		assert_eq!(map.len(), 0);
219		assert!(map.is_empty());
220		assert_eq!(map.iter().count(), 0);
221		assert_eq!(map.into_iter().count(), 0);
222	}
223
224	#[test]
225	fn new_creates_empty_map() {
226		let map = IndexMap::<String>::new();
227		assert!(map.is_empty());
228	}
229
230	#[test]
231	fn clear_removes_all_values() {
232		let mut map = IndexMap::<String>::default();
233		map.insert(0, "sample value".to_string());
234		assert_eq!(map.len(), 1);
235		map.clear();
236		assert_eq!(map.len(), 0);
237	}
238
239	#[test]
240	fn get_returns_elements_that_are_there_but_nothing_else() {
241		let mut map = IndexMap::<String>::default();
242		map.insert(1, "sample value".to_string());
243		assert_eq!(map.len(), 1);
244		assert_eq!(map.get(0), None);
245		assert_eq!(map.get(1), Some(&"sample value".to_string()));
246		assert_eq!(map.get(2), None);
247	}
248
249	#[test]
250	fn contains_key_returns_true_when_a_key_is_present() {
251		let mut map = IndexMap::<String>::default();
252		map.insert(1, "sample value".to_string());
253		assert!(!map.contains_key(0));
254		assert!(map.contains_key(1));
255		assert!(!map.contains_key(2));
256	}
257
258	#[test]
259	fn insert_behaves_like_other_maps() {
260		let mut map = IndexMap::<String>::default();
261
262		// Insert a key which requires extending our storage.
263		assert_eq!(map.insert(1, "val 1".to_string()), None);
264		assert_eq!(map.len(), 1);
265		assert!(map.contains_key(1));
266
267		// Insert a key which requires filling in a hole.
268		assert_eq!(map.insert(0, "val 0".to_string()), None);
269		assert_eq!(map.len(), 2);
270		assert!(map.contains_key(0));
271
272		// Insert a key which replaces an existing key.
273		assert_eq!(map.insert(1, "val 1.1".to_string()), Some("val 1".to_string()));
274		assert_eq!(map.len(), 2);
275		assert!(map.contains_key(1));
276		assert_eq!(map.get(1), Some(&"val 1.1".to_string()));
277	}
278
279	#[test]
280	fn remove_behaves_like_other_maps() {
281		let mut map = IndexMap::<String>::default();
282		assert_eq!(map.insert(1, "val 1".to_string()), None);
283
284		// Remove an out-of-bounds element.
285		assert_eq!(map.remove(2), None);
286		assert_eq!(map.len(), 1);
287
288		// Remove an in-bounds but missing element.
289		assert_eq!(map.remove(0), None);
290		assert_eq!(map.len(), 1);
291
292		// Remove an existing element.
293		assert_eq!(map.remove(1), Some("val 1".to_string()));
294		assert_eq!(map.len(), 0);
295	}
296
297	#[test]
298	fn partial_eq_works_as_expected_in_simple_cases() {
299		let mut map1 = IndexMap::<String>::default();
300		let mut map2 = IndexMap::<String>::default();
301		assert_eq!(map1, map2);
302
303		map1.insert(1, "a".to_string());
304		map2.insert(1, "a".to_string());
305		assert_eq!(map1, map2);
306
307		map1.insert(0, "b".to_string());
308		assert_ne!(map1, map2);
309		map1.remove(0);
310		assert_eq!(map1, map2);
311
312		map1.insert(1, "not a".to_string());
313		assert_ne!(map1, map2);
314	}
315
316	#[test]
317	fn partial_eq_is_smart_about_none_values_at_the_end() {
318		let mut map1 = IndexMap::<String>::default();
319		let mut map2 = IndexMap::<String>::default();
320
321		map1.insert(1, "a".to_string());
322		map2.insert(1, "a".to_string());
323
324		// Both maps have the same (idx, value) pairs, but map2 has extra space.
325		map2.insert(10, "b".to_string());
326		map2.remove(10);
327		assert_eq!(map1, map2);
328
329		// Both maps have the same (idx, value) pairs, but map1 has extra space.
330		map1.insert(100, "b".to_string());
331		map1.remove(100);
332		assert_eq!(map1, map2);
333
334		// Let's be paranoid.
335		map2.insert(1, "b".to_string());
336		assert_ne!(map1, map2);
337	}
338
339	#[test]
340	fn from_iterator_builds_a_map() {
341		let data = &[
342			// We support out-of-order values here!
343			(3, "val 3"),
344			(2, "val 2"),
345			(5, "val 5"),
346		];
347		let iter = data.iter().map(|&(idx, val)| (idx, val.to_string()));
348		let map = iter.collect::<IndexMap<_>>();
349		assert_eq!(map.len(), 3);
350		assert_eq!(map.get(2), Some(&"val 2".to_string()));
351		assert_eq!(map.get(3), Some(&"val 3".to_string()));
352		assert_eq!(map.get(5), Some(&"val 5".to_string()));
353	}
354
355	#[test]
356	fn iterators_are_well_behaved() {
357		// Create a map with reasonably complex internal structure, making
358		// sure that we have both internal missing elements, and a bunch of
359		// missing elements at the end.
360		let data = &[(3, "val 3"), (2, "val 2"), (5, "val 5")];
361		let src_iter = data.iter().map(|&(idx, val)| (idx, val.to_string()));
362		let mut map = src_iter.collect::<IndexMap<_>>();
363		map.remove(5);
364
365		// Make sure `size_hint` and `next` behave as we expect at each step.
366		{
367			let mut iter1 = map.iter();
368			assert_eq!(iter1.size_hint(), (2, Some(2)));
369			assert_eq!(iter1.next(), Some((2, &"val 2".to_string())));
370			assert_eq!(iter1.size_hint(), (1, Some(1)));
371			assert_eq!(iter1.next(), Some((3, &"val 3".to_string())));
372			assert_eq!(iter1.size_hint(), (0, Some(0)));
373			assert_eq!(iter1.next(), None);
374			assert_eq!(iter1.size_hint(), (0, Some(0)));
375			assert_eq!(iter1.next(), None);
376			assert_eq!(iter1.size_hint(), (0, Some(0)));
377		}
378
379		// Now do the same for a consuming iterator.
380		let mut iter2 = map.into_iter();
381		assert_eq!(iter2.size_hint(), (2, Some(2)));
382		assert_eq!(iter2.next(), Some((2, "val 2".to_string())));
383		assert_eq!(iter2.size_hint(), (1, Some(1)));
384		assert_eq!(iter2.next(), Some((3, "val 3".to_string())));
385		assert_eq!(iter2.size_hint(), (0, Some(0)));
386		assert_eq!(iter2.next(), None);
387		assert_eq!(iter2.size_hint(), (0, Some(0)));
388		assert_eq!(iter2.next(), None);
389		assert_eq!(iter2.size_hint(), (0, Some(0)));
390	}
391
392	#[test]
393	fn serialize_and_deserialize() {
394		let mut map = IndexMap::<String>::default();
395		map.insert(1, "val 1".to_string());
396
397		let mut output = vec![];
398		map.clone().serialize(&mut output).expect("serialize failed");
399
400		let mut input = io::Cursor::new(&output);
401		let deserialized = IndexMap::deserialize(2, &mut input).expect("deserialize failed");
402
403		assert_eq!(deserialized, map);
404	}
405
406	#[test]
407	fn deserialize_requires_elements_to_be_in_order() {
408		// Build a in-order example by hand.
409		let mut valid = vec![];
410		VarUint32::from(2u32).serialize(&mut valid).unwrap();
411		VarUint32::from(0u32).serialize(&mut valid).unwrap();
412		"val 0".to_string().serialize(&mut valid).unwrap();
413		VarUint32::from(1u32).serialize(&mut valid).unwrap();
414		"val 1".to_string().serialize(&mut valid).unwrap();
415		let map = IndexMap::<String>::deserialize(2, &mut io::Cursor::new(valid))
416			.expect("unexpected error deserializing");
417		assert_eq!(map.len(), 2);
418
419		// Build an out-of-order example by hand.
420		let mut invalid = vec![];
421		VarUint32::from(2u32).serialize(&mut invalid).unwrap();
422		VarUint32::from(1u32).serialize(&mut invalid).unwrap();
423		"val 1".to_string().serialize(&mut invalid).unwrap();
424		VarUint32::from(0u32).serialize(&mut invalid).unwrap();
425		"val 0".to_string().serialize(&mut invalid).unwrap();
426		let res = IndexMap::<String>::deserialize(2, &mut io::Cursor::new(invalid));
427		assert!(res.is_err());
428	}
429
430	#[test]
431	fn deserialize_enforces_max_idx() {
432		// Build an example with an out-of-bounds index by hand.
433		let mut invalid = vec![];
434		VarUint32::from(1u32).serialize(&mut invalid).unwrap();
435		VarUint32::from(5u32).serialize(&mut invalid).unwrap();
436		"val 5".to_string().serialize(&mut invalid).unwrap();
437		let res = IndexMap::<String>::deserialize(1, &mut io::Cursor::new(invalid));
438		assert!(res.is_err());
439	}
440
441	#[test]
442	fn deserialize_with_capacity() {
443		let mut invalid = vec![];
444		VarUint32::from(u32::MAX).serialize(&mut invalid).unwrap();
445		VarUint32::from(5u32).serialize(&mut invalid).unwrap();
446		"fooba".to_string().serialize(&mut invalid).unwrap();
447		let _error = IndexMap::<String>::deserialize(6, &mut io::Cursor::new(invalid)).unwrap_err();
448	}
449
450	#[test]
451	fn very_large_idx() {
452		let mut invalid = vec![];
453		VarUint32::from(1u32).serialize(&mut invalid).unwrap();
454		VarUint32::from(u32::MAX - 1).serialize(&mut invalid).unwrap();
455		"fooba".to_string().serialize(&mut invalid).unwrap();
456		let indexmap =
457			IndexMap::<String>::deserialize(u32::MAX as usize, &mut io::Cursor::new(invalid))
458				.unwrap();
459		assert_eq!(indexmap.get(u32::MAX - 1), Some(&"fooba".to_string()));
460		assert_eq!(indexmap.len(), 1);
461	}
462}