parity_wasm/elements/
index_map.rs

1use crate::io;
2use alloc::vec::Vec;
3
4use super::{Deserialize, Error, Serialize, VarUint32};
5
6use alloc::vec;
7use core::{
8	cmp::min,
9	iter::{FromIterator, IntoIterator},
10	mem, slice,
11};
12
13/// A map from non-contiguous `u32` keys to values of type `T`, which is
14/// serialized and deserialized ascending order of the keys. Normally used for
15/// relative dense maps with occasional "holes", and stored as an array.
16///
17/// **SECURITY WARNING:** This code is currently subject to a denial of service
18/// attack if you create a map containing the key `u32::MAX`, which should never
19/// happen in normal data. It would be pretty easy to provide a safe
20/// deserializing mechanism which addressed this problem.
21#[derive(Debug, Default)]
22pub struct IndexMap<T> {
23	/// The number of non-`None` entries in this map.
24	len: usize,
25
26	/// A vector of entries. Missing entries are represented as `None`.
27	entries: Vec<Option<T>>,
28}
29
30impl<T> IndexMap<T> {
31	/// Create an empty `IndexMap`, preallocating enough space to store
32	/// `capacity` entries without needing to reallocate the underlying memory.
33	pub fn with_capacity(capacity: usize) -> IndexMap<T> {
34		IndexMap { len: 0, entries: Vec::with_capacity(capacity) }
35	}
36
37	/// Clear the map.
38	pub fn clear(&mut self) {
39		self.entries.clear();
40		self.len = 0;
41	}
42
43	/// Return the name for the specified index, if it exists.
44	pub fn get(&self, idx: u32) -> Option<&T> {
45		match self.entries.get(idx as usize) {
46			Some(&Some(ref value)) => Some(value),
47			Some(&None) | None => None,
48		}
49	}
50
51	/// Does the map contain an entry for the specified index?
52	pub fn contains_key(&self, idx: u32) -> bool {
53		match self.entries.get(idx as usize) {
54			Some(&Some(_)) => true,
55			Some(&None) | None => false,
56		}
57	}
58
59	/// Insert a name into our map, returning the existing value if present.
60	///
61	/// Note: This API is designed for reasonably dense indices based on valid
62	/// data. Inserting a huge `idx` will use up a lot of RAM, and this function
63	/// will not try to protect you against that.
64	pub fn insert(&mut self, idx: u32, value: T) -> Option<T> {
65		let idx = idx as usize;
66		let result = if idx >= self.entries.len() {
67			// We need to grow the array, and add the new element at the end.
68			for _ in 0..(idx - self.entries.len()) {
69				// We can't use `extend(repeat(None)).take(n)`, because that
70				// would require `T` to implement `Clone`.
71				self.entries.push(None);
72			}
73			self.entries.push(Some(value));
74			debug_assert_eq!(idx + 1, self.entries.len());
75			self.len += 1;
76			None
77		} else {
78			// We're either replacing an existing element, or filling in a
79			// missing one.
80			let existing = self.entries[idx].take();
81			if existing.is_none() {
82				self.len += 1;
83			}
84			self.entries[idx] = Some(value);
85			existing
86		};
87		if mem::size_of::<usize>() > 4 {
88			debug_assert!(self.entries.len() <= (u32::max_value() as usize) + 1);
89		}
90		#[cfg(slow_assertions)]
91		debug_assert_eq!(self.len, self.slow_len());
92		result
93	}
94
95	/// Remove an item if present and return it.
96	pub fn remove(&mut self, idx: u32) -> Option<T> {
97		let result = match self.entries.get_mut(idx as usize) {
98			Some(value @ &mut Some(_)) => {
99				self.len -= 1;
100				value.take()
101			},
102			Some(&mut None) | None => None,
103		};
104		#[cfg(slow_assertions)]
105		debug_assert_eq!(self.len, self.slow_len());
106		result
107	}
108
109	/// The number of items in this map.
110	pub fn len(&self) -> usize {
111		#[cfg(slow_assertions)]
112		debug_assert_eq!(self.len, self.slow_len());
113		self.len
114	}
115
116	/// Is this map empty?
117	pub fn is_empty(&self) -> bool {
118		self.len == 0
119	}
120
121	/// This function is only compiled when `--cfg slow_assertions` is enabled.
122	/// It computes the `len` value using a slow algorithm.
123	///
124	/// WARNING: This turns a bunch of O(n) operations into O(n^2) operations.
125	/// We may want to remove it once the code is tested, or to put it behind
126	/// a feature flag named `slow_debug_checks`, or something like that.
127	#[cfg(slow_assertions)]
128	fn slow_len(&self) -> usize {
129		self.entries.iter().filter(|entry| entry.is_some()).count()
130	}
131
132	/// Create a non-consuming iterator over this `IndexMap`'s keys and values.
133	pub fn iter(&self) -> Iter<T> {
134		// Note that this does the right thing because we use `&self`.
135		self.into_iter()
136	}
137
138	/// Custom deserialization routine.
139	///
140	/// We will allocate an underlying array no larger than `max_entry_space` to
141	/// hold the data, so the maximum index must be less than `max_entry_space`.
142	/// This prevents mallicious *.wasm files from having a single entry with
143	/// the index `u32::MAX`, which would consume far too much memory.
144	///
145	/// The `deserialize_value` function will be passed the index of the value
146	/// being deserialized, and must deserialize the value.
147	pub fn deserialize_with<R, F>(
148		max_entry_space: usize,
149		deserialize_value: &F,
150		rdr: &mut R,
151	) -> Result<IndexMap<T>, Error>
152	where
153		R: io::Read,
154		F: Fn(u32, &mut R) -> Result<T, Error>,
155	{
156		let len: u32 = VarUint32::deserialize(rdr)?.into();
157		let mut map = IndexMap::with_capacity(len as usize);
158		let mut prev_idx = None;
159		for _ in 0..len {
160			let idx: u32 = VarUint32::deserialize(rdr)?.into();
161			if idx as usize >= max_entry_space {
162				return Err(Error::Other("index is larger than expected"))
163			}
164			match prev_idx {
165				Some(prev) if prev >= idx => {
166					// Supposedly these names must be "sorted by index", so
167					// let's try enforcing that and seeing what happens.
168					return Err(Error::Other("indices are out of order"))
169				},
170				_ => {
171					prev_idx = Some(idx);
172				},
173			}
174			let val = deserialize_value(idx, rdr)?;
175			map.insert(idx, val);
176		}
177		Ok(map)
178	}
179}
180
181impl<T: Clone> Clone for IndexMap<T> {
182	fn clone(&self) -> IndexMap<T> {
183		IndexMap { len: self.len, entries: self.entries.clone() }
184	}
185}
186
187impl<T: PartialEq> PartialEq<IndexMap<T>> for IndexMap<T> {
188	fn eq(&self, other: &IndexMap<T>) -> bool {
189		if self.len() != other.len() {
190			// If the number of non-`None` entries is different, we can't match.
191			false
192		} else {
193			// This is tricky, because one `Vec` might have a bunch of empty
194			// entries at the end which we want to ignore.
195			let smallest_len = min(self.entries.len(), other.entries.len());
196			self.entries[0..smallest_len].eq(&other.entries[0..smallest_len])
197		}
198	}
199}
200
201impl<T: Eq> Eq for IndexMap<T> {}
202
203impl<T> FromIterator<(u32, T)> for IndexMap<T> {
204	/// Create an `IndexMap` from an iterator.
205	///
206	/// Note: This API is designed for reasonably dense indices based on valid
207	/// data. Inserting a huge `idx` will use up a lot of RAM, and this function
208	/// will not try to protect you against that.
209	fn from_iter<I>(iter: I) -> Self
210	where
211		I: IntoIterator<Item = (u32, T)>,
212	{
213		let iter = iter.into_iter();
214		let (lower, upper_opt) = iter.size_hint();
215		let mut map = IndexMap::with_capacity(upper_opt.unwrap_or(lower));
216		for (idx, value) in iter {
217			map.insert(idx, value);
218		}
219		map
220	}
221}
222
223/// An iterator over an `IndexMap` which takes ownership of it.
224pub struct IntoIter<T> {
225	next_idx: u32,
226	remaining_len: usize,
227	iter: vec::IntoIter<Option<T>>,
228}
229
230impl<T> Iterator for IntoIter<T> {
231	type Item = (u32, T);
232
233	fn size_hint(&self) -> (usize, Option<usize>) {
234		(self.remaining_len, Some(self.remaining_len))
235	}
236
237	fn next(&mut self) -> Option<Self::Item> {
238		// Bail early if we know there are no more items. This also keeps us
239		// from repeatedly calling `self.iter.next()` once it has been
240		// exhausted, which is not guaranteed to keep returning `None`.
241		if self.remaining_len == 0 {
242			return None
243		}
244		for value_opt in &mut self.iter {
245			let idx = self.next_idx;
246			self.next_idx += 1;
247			if let Some(value) = value_opt {
248				self.remaining_len -= 1;
249				return Some((idx, value))
250			}
251		}
252		debug_assert_eq!(self.remaining_len, 0);
253		None
254	}
255}
256
257impl<T> IntoIterator for IndexMap<T> {
258	type Item = (u32, T);
259	type IntoIter = IntoIter<T>;
260
261	fn into_iter(self) -> IntoIter<T> {
262		IntoIter { next_idx: 0, remaining_len: self.len, iter: self.entries.into_iter() }
263	}
264}
265
266/// An iterator over a borrowed `IndexMap`.
267pub struct Iter<'a, T: 'static> {
268	next_idx: u32,
269	remaining_len: usize,
270	iter: slice::Iter<'a, Option<T>>,
271}
272
273impl<'a, T: 'static> Iterator for Iter<'a, T> {
274	type Item = (u32, &'a T);
275
276	fn size_hint(&self) -> (usize, Option<usize>) {
277		(self.remaining_len, Some(self.remaining_len))
278	}
279
280	fn next(&mut self) -> Option<Self::Item> {
281		// Bail early if we know there are no more items. This also keeps us
282		// from repeatedly calling `self.iter.next()` once it has been
283		// exhausted, which is not guaranteed to keep returning `None`.
284		if self.remaining_len == 0 {
285			return None
286		}
287		for value_opt in &mut self.iter {
288			let idx = self.next_idx;
289			self.next_idx += 1;
290			if let Some(ref value) = *value_opt {
291				self.remaining_len -= 1;
292				return Some((idx, value))
293			}
294		}
295		debug_assert_eq!(self.remaining_len, 0);
296		None
297	}
298}
299
300impl<'a, T: 'static> IntoIterator for &'a IndexMap<T> {
301	type Item = (u32, &'a T);
302	type IntoIter = Iter<'a, T>;
303
304	fn into_iter(self) -> Iter<'a, T> {
305		Iter { next_idx: 0, remaining_len: self.len, iter: self.entries.iter() }
306	}
307}
308
309impl<T> Serialize for IndexMap<T>
310where
311	T: Serialize,
312	Error: From<<T as Serialize>::Error>,
313{
314	type Error = Error;
315
316	fn serialize<W: io::Write>(self, wtr: &mut W) -> Result<(), Self::Error> {
317		VarUint32::from(self.len()).serialize(wtr)?;
318		for (idx, value) in self {
319			VarUint32::from(idx).serialize(wtr)?;
320			value.serialize(wtr)?;
321		}
322		Ok(())
323	}
324}
325
326impl<T: Deserialize> IndexMap<T>
327where
328	T: Deserialize,
329	Error: From<<T as Deserialize>::Error>,
330{
331	/// Deserialize a map containing simple values that support `Deserialize`.
332	/// We will allocate an underlying array no larger than `max_entry_space` to
333	/// hold the data, so the maximum index must be less than `max_entry_space`.
334	pub fn deserialize<R: io::Read>(max_entry_space: usize, rdr: &mut R) -> Result<Self, Error> {
335		let deserialize_value: fn(u32, &mut R) -> Result<T, Error> =
336			|_idx, rdr| T::deserialize(rdr).map_err(Error::from);
337		Self::deserialize_with(max_entry_space, &deserialize_value, rdr)
338	}
339}
340
341#[cfg(test)]
342mod tests {
343	use super::*;
344	use crate::io;
345
346	#[test]
347	fn default_is_empty_no_matter_how_we_look_at_it() {
348		let map = IndexMap::<String>::default();
349		assert_eq!(map.len(), 0);
350		assert!(map.is_empty());
351		assert_eq!(map.iter().count(), 0);
352		assert_eq!(map.into_iter().count(), 0);
353	}
354
355	#[test]
356	fn with_capacity_creates_empty_map() {
357		let map = IndexMap::<String>::with_capacity(10);
358		assert!(map.is_empty());
359	}
360
361	#[test]
362	fn clear_removes_all_values() {
363		let mut map = IndexMap::<String>::default();
364		map.insert(0, "sample value".to_string());
365		assert_eq!(map.len(), 1);
366		map.clear();
367		assert_eq!(map.len(), 0);
368	}
369
370	#[test]
371	fn get_returns_elements_that_are_there_but_nothing_else() {
372		let mut map = IndexMap::<String>::default();
373		map.insert(1, "sample value".to_string());
374		assert_eq!(map.len(), 1);
375		assert_eq!(map.get(0), None);
376		assert_eq!(map.get(1), Some(&"sample value".to_string()));
377		assert_eq!(map.get(2), None);
378	}
379
380	#[test]
381	fn contains_key_returns_true_when_a_key_is_present() {
382		let mut map = IndexMap::<String>::default();
383		map.insert(1, "sample value".to_string());
384		assert!(!map.contains_key(0));
385		assert!(map.contains_key(1));
386		assert!(!map.contains_key(2));
387	}
388
389	#[test]
390	fn insert_behaves_like_other_maps() {
391		let mut map = IndexMap::<String>::default();
392
393		// Insert a key which requires extending our storage.
394		assert_eq!(map.insert(1, "val 1".to_string()), None);
395		assert_eq!(map.len(), 1);
396		assert!(map.contains_key(1));
397
398		// Insert a key which requires filling in a hole.
399		assert_eq!(map.insert(0, "val 0".to_string()), None);
400		assert_eq!(map.len(), 2);
401		assert!(map.contains_key(0));
402
403		// Insert a key which replaces an existing key.
404		assert_eq!(map.insert(1, "val 1.1".to_string()), Some("val 1".to_string()));
405		assert_eq!(map.len(), 2);
406		assert!(map.contains_key(1));
407		assert_eq!(map.get(1), Some(&"val 1.1".to_string()));
408	}
409
410	#[test]
411	fn remove_behaves_like_other_maps() {
412		let mut map = IndexMap::<String>::default();
413		assert_eq!(map.insert(1, "val 1".to_string()), None);
414
415		// Remove an out-of-bounds element.
416		assert_eq!(map.remove(2), None);
417		assert_eq!(map.len(), 1);
418
419		// Remove an in-bounds but missing element.
420		assert_eq!(map.remove(0), None);
421		assert_eq!(map.len(), 1);
422
423		// Remove an existing element.
424		assert_eq!(map.remove(1), Some("val 1".to_string()));
425		assert_eq!(map.len(), 0);
426	}
427
428	#[test]
429	fn partial_eq_works_as_expected_in_simple_cases() {
430		let mut map1 = IndexMap::<String>::default();
431		let mut map2 = IndexMap::<String>::default();
432		assert_eq!(map1, map2);
433
434		map1.insert(1, "a".to_string());
435		map2.insert(1, "a".to_string());
436		assert_eq!(map1, map2);
437
438		map1.insert(0, "b".to_string());
439		assert_ne!(map1, map2);
440		map1.remove(0);
441		assert_eq!(map1, map2);
442
443		map1.insert(1, "not a".to_string());
444		assert_ne!(map1, map2);
445	}
446
447	#[test]
448	fn partial_eq_is_smart_about_none_values_at_the_end() {
449		let mut map1 = IndexMap::<String>::default();
450		let mut map2 = IndexMap::<String>::default();
451
452		map1.insert(1, "a".to_string());
453		map2.insert(1, "a".to_string());
454
455		// Both maps have the same (idx, value) pairs, but map2 has extra space.
456		map2.insert(10, "b".to_string());
457		map2.remove(10);
458		assert_eq!(map1, map2);
459
460		// Both maps have the same (idx, value) pairs, but map1 has extra space.
461		map1.insert(100, "b".to_string());
462		map1.remove(100);
463		assert_eq!(map1, map2);
464
465		// Let's be paranoid.
466		map2.insert(1, "b".to_string());
467		assert_ne!(map1, map2);
468	}
469
470	#[test]
471	fn from_iterator_builds_a_map() {
472		let data = &[
473			// We support out-of-order values here!
474			(3, "val 3"),
475			(2, "val 2"),
476			(5, "val 5"),
477		];
478		let iter = data.iter().map(|&(idx, val)| (idx, val.to_string()));
479		let map = iter.collect::<IndexMap<_>>();
480		assert_eq!(map.len(), 3);
481		assert_eq!(map.get(2), Some(&"val 2".to_string()));
482		assert_eq!(map.get(3), Some(&"val 3".to_string()));
483		assert_eq!(map.get(5), Some(&"val 5".to_string()));
484	}
485
486	#[test]
487	fn iterators_are_well_behaved() {
488		// Create a map with reasonably complex internal structure, making
489		// sure that we have both internal missing elements, and a bunch of
490		// missing elements at the end.
491		let data = &[(3, "val 3"), (2, "val 2"), (5, "val 5")];
492		let src_iter = data.iter().map(|&(idx, val)| (idx, val.to_string()));
493		let mut map = src_iter.collect::<IndexMap<_>>();
494		map.remove(5);
495
496		// Make sure `size_hint` and `next` behave as we expect at each step.
497		{
498			let mut iter1 = map.iter();
499			assert_eq!(iter1.size_hint(), (2, Some(2)));
500			assert_eq!(iter1.next(), Some((2, &"val 2".to_string())));
501			assert_eq!(iter1.size_hint(), (1, Some(1)));
502			assert_eq!(iter1.next(), Some((3, &"val 3".to_string())));
503			assert_eq!(iter1.size_hint(), (0, Some(0)));
504			assert_eq!(iter1.next(), None);
505			assert_eq!(iter1.size_hint(), (0, Some(0)));
506			assert_eq!(iter1.next(), None);
507			assert_eq!(iter1.size_hint(), (0, Some(0)));
508		}
509
510		// Now do the same for a consuming iterator.
511		let mut iter2 = map.into_iter();
512		assert_eq!(iter2.size_hint(), (2, Some(2)));
513		assert_eq!(iter2.next(), Some((2, "val 2".to_string())));
514		assert_eq!(iter2.size_hint(), (1, Some(1)));
515		assert_eq!(iter2.next(), Some((3, "val 3".to_string())));
516		assert_eq!(iter2.size_hint(), (0, Some(0)));
517		assert_eq!(iter2.next(), None);
518		assert_eq!(iter2.size_hint(), (0, Some(0)));
519		assert_eq!(iter2.next(), None);
520		assert_eq!(iter2.size_hint(), (0, Some(0)));
521	}
522
523	#[test]
524	fn serialize_and_deserialize() {
525		let mut map = IndexMap::<String>::default();
526		map.insert(1, "val 1".to_string());
527
528		let mut output = vec![];
529		map.clone().serialize(&mut output).expect("serialize failed");
530
531		let mut input = io::Cursor::new(&output);
532		let deserialized = IndexMap::deserialize(2, &mut input).expect("deserialize failed");
533
534		assert_eq!(deserialized, map);
535	}
536
537	#[test]
538	fn deserialize_requires_elements_to_be_in_order() {
539		// Build a in-order example by hand.
540		let mut valid = vec![];
541		VarUint32::from(2u32).serialize(&mut valid).unwrap();
542		VarUint32::from(0u32).serialize(&mut valid).unwrap();
543		"val 0".to_string().serialize(&mut valid).unwrap();
544		VarUint32::from(1u32).serialize(&mut valid).unwrap();
545		"val 1".to_string().serialize(&mut valid).unwrap();
546		let map = IndexMap::<String>::deserialize(2, &mut io::Cursor::new(valid))
547			.expect("unexpected error deserializing");
548		assert_eq!(map.len(), 2);
549
550		// Build an out-of-order example by hand.
551		let mut invalid = vec![];
552		VarUint32::from(2u32).serialize(&mut invalid).unwrap();
553		VarUint32::from(1u32).serialize(&mut invalid).unwrap();
554		"val 1".to_string().serialize(&mut invalid).unwrap();
555		VarUint32::from(0u32).serialize(&mut invalid).unwrap();
556		"val 0".to_string().serialize(&mut invalid).unwrap();
557		let res = IndexMap::<String>::deserialize(2, &mut io::Cursor::new(invalid));
558		assert!(res.is_err());
559	}
560
561	#[test]
562	fn deserialize_enforces_max_idx() {
563		// Build an example with an out-of-bounds index by hand.
564		let mut invalid = vec![];
565		VarUint32::from(1u32).serialize(&mut invalid).unwrap();
566		VarUint32::from(5u32).serialize(&mut invalid).unwrap();
567		"val 5".to_string().serialize(&mut invalid).unwrap();
568		let res = IndexMap::<String>::deserialize(1, &mut io::Cursor::new(invalid));
569		assert!(res.is_err());
570	}
571}