tetsy_wasm/elements/
index_map.rs

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