diff --git a/CHANGELOG.md b/CHANGELOG.md index 0bea10baa6..9208661036 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Added `VecView`, the `!Sized` version of `Vec`. - Added pool implementations for 64-bit architectures. - Added `IntoIterator` implementation for `LinearMap` +- Added `LinearMapView`, the `!Sized` version of `LinearMap`. ### Changed diff --git a/src/lib.rs b/src/lib.rs index b5238c672c..a57864021f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -94,7 +94,7 @@ pub use indexmap::{ ValuesMut as IndexMapValuesMut, }; pub use indexset::{FnvIndexSet, IndexSet, Iter as IndexSetIter}; -pub use linear_map::LinearMap; +pub use linear_map::{LinearMap, LinearMapView}; pub use string::String; // Workaround https://github.com/rust-lang/rust/issues/119015. This is required so that the methods on `VecView` and `Vec` are properly documented. diff --git a/src/linear_map.rs b/src/linear_map.rs index 2e376a521d..a95473ffd6 100644 --- a/src/linear_map.rs +++ b/src/linear_map.rs @@ -1,14 +1,48 @@ use core::{borrow::Borrow, fmt, mem, ops, slice}; -use crate::Vec; +use crate::{Vec, VecView}; + +mod sealed { + ///
This is private API and should not be used
+ pub struct LinearMapInner { + pub(super) buffer: V, + } +} + +// Workaround https://github.com/rust-lang/rust/issues/119015. This is required so that the methods on `VecView` and `Vec` are properly documented. +// cfg(doc) prevents `LinearMapInner` being part of the public API. +// doc(hidden) prevents the `pub use sealed::StringInner` from being visible in the documentation. +#[cfg(doc)] +#[doc(hidden)] +pub use sealed::LinearMapInner as _; /// A fixed capacity map/dictionary that performs lookups via linear search. /// /// Note that as this map doesn't use hashing so most operations are *O*(n) instead of *O*(1). +pub type LinearMap = sealed::LinearMapInner>; -pub struct LinearMap { - pub(crate) buffer: Vec<(K, V), N>, -} +/// A [`LinearMap`] with dynamic capacity +/// +/// [`LinearMap`] coerces to `LinearMapView`. `LinearMapView` is `!Sized`, meaning it can only ever be used by reference +/// +/// Unlike [`LinearMap`], `LinearMapView` does not have an `N` const-generic parameter. +/// This has the ergonomic advantage of making it possible to use functions without needing to know at +/// compile-time the size of the buffers used, for example for use in `dyn` traits. +/// +/// `LinearMapView` is to `LinearMap` what [`VecView`] is to [`Vec`]. +/// +/// ```rust +/// use heapless::{LinearMap, LinearMapView}; +/// +/// let mut map: LinearMap<_, _, 8> = LinearMap::new(); +/// let map_view: &mut LinearMapView<_, _> = &mut map; +/// map_view.insert(1, "a").unwrap(); +/// if let Some(x) = map_view.get_mut(&1) { +/// *x = "b"; +/// } +/// assert_eq!(map_view[&1], "b"); +/// ``` +pub type LinearMapView = sealed::LinearMapInner>; impl LinearMap { /// Creates an empty `LinearMap`. @@ -16,13 +50,16 @@ impl LinearMap { /// # Examples /// /// ``` - /// use heapless::LinearMap; + /// use heapless::{LinearMap, LinearMapView}; /// /// // allocate the map on the stack /// let mut map: LinearMap<&str, isize, 8> = LinearMap::new(); /// /// // allocate the map in a static variable /// static mut MAP: LinearMap<&str, isize, 8> = LinearMap::new(); + /// + /// // allocate the map in a static variable, erasing the const generic + /// static mut MAP_VIEW: &mut LinearMapView<&str, isize> = &mut LinearMap::<_, _, 8>::new(); /// ``` pub const fn new() -> Self { Self { buffer: Vec::new() } @@ -33,6 +70,58 @@ impl LinearMap where K: Eq, { + /// Get a reference to the `LinearMap`, erasing the `N` const-generic. + /// + /// ```rust + /// use heapless::{LinearMap, LinearMapView}; + /// + /// let mut map: LinearMap<_, _, 8> = LinearMap::new(); + /// map.insert(1, "a").unwrap(); + /// if let Some(x) = map.get_mut(&1) { + /// *x = "b"; + /// } + /// let map_view: &LinearMapView<_, _> = map.as_view(); + /// assert_eq!(map_view[&1], "b"); + /// ``` + /// + /// It is often preferable to do the same through type coerction, since `LinearMap` implements `Unsize>`: + /// + /// ```rust + /// # use heapless::{LinearMap, LinearMapView}; + /// + /// let map: LinearMap<&str, &str, 8> = LinearMap::new(); + /// let map_view: &LinearMapView<_, _> = ↦ + /// ``` + pub fn as_view(&self) -> &LinearMapView { + self + } + + /// Get a mutable reference to the `LinearMap`, erasing the `N` const-generic. + /// + /// ```rust + /// use heapless::{LinearMap, LinearMapView}; + /// + /// let mut map: LinearMap<_, _, 8> = LinearMap::new(); + /// let map_view: &mut LinearMapView<_, _> = map.as_mut_view(); + /// map_view.insert(1, "a").unwrap(); + /// if let Some(x) = map_view.get_mut(&1) { + /// *x = "b"; + /// } + /// assert_eq!(map_view[&1], "b"); + /// ``` + /// + /// It is often preferable to do the same through type coerction, since `LinearMap` implements `Unsize>`: + /// + /// ```rust + /// # use heapless::{LinearMap, LinearMapView}; + /// + /// let mut map: LinearMap<&str, &str, 8> = LinearMap::new(); + /// let map_view: &mut LinearMapView<_, _> = &mut map; + /// ``` + pub fn as_mut_view(&mut self) -> &mut LinearMapView { + self + } + /// Returns the number of elements that the map can hold. /// /// Computes in *O*(1) time. @@ -64,7 +153,7 @@ where /// assert!(map.is_empty()); /// ``` pub fn clear(&mut self) { - self.buffer.clear() + self.as_mut_view().clear() } /// Returns true if the map contains a value for the specified key. @@ -82,7 +171,7 @@ where /// assert_eq!(map.contains_key(&2), false); /// ``` pub fn contains_key(&self, key: &K) -> bool { - self.get(key).is_some() + self.as_view().contains_key(key) } /// Returns a reference to the value corresponding to the key. @@ -104,9 +193,7 @@ where K: Borrow, Q: Eq + ?Sized, { - self.iter() - .find(|&(k, _)| k.borrow() == key) - .map(|(_, v)| v) + self.as_view().get(key) } /// Returns a mutable reference to the value corresponding to the key. @@ -130,9 +217,7 @@ where K: Borrow, Q: Eq + ?Sized, { - self.iter_mut() - .find(|&(k, _)| k.borrow() == key) - .map(|(_, v)| v) + self.as_mut_view().get_mut(key) } /// Returns the number of elements in this map. @@ -150,7 +235,7 @@ where /// assert_eq!(a.len(), 1); /// ``` pub fn len(&self) -> usize { - self.buffer.len() + self.as_view().len() } /// Inserts a key-value pair into the map. @@ -174,14 +259,8 @@ where /// assert_eq!(map.insert(37, "c").unwrap(), Some("b")); /// assert_eq!(map[&37], "c"); /// ``` - pub fn insert(&mut self, key: K, mut value: V) -> Result, (K, V)> { - if let Some((_, v)) = self.iter_mut().find(|&(k, _)| *k == key) { - mem::swap(v, &mut value); - return Ok(Some(value)); - } - - self.buffer.push((key, value))?; - Ok(None) + pub fn insert(&mut self, key: K, value: V) -> Result, (K, V)> { + self.as_mut_view().insert(key, value) } /// Returns true if the map contains no elements. @@ -199,7 +278,7 @@ where /// assert!(!a.is_empty()); /// ``` pub fn is_empty(&self) -> bool { - self.len() == 0 + self.as_view().is_empty() } /// An iterator visiting all key-value pairs in arbitrary order. @@ -219,9 +298,7 @@ where /// } /// ``` pub fn iter(&self) -> Iter<'_, K, V> { - Iter { - iter: self.buffer.as_slice().iter(), - } + self.as_view().iter() } /// An iterator visiting all key-value pairs in arbitrary order, @@ -247,9 +324,7 @@ where /// } /// ``` pub fn iter_mut(&mut self) -> IterMut<'_, K, V> { - IterMut { - iter: self.buffer.as_mut_slice().iter_mut(), - } + self.as_mut_view().iter_mut() } /// An iterator visiting all keys in arbitrary order. @@ -269,7 +344,7 @@ where /// } /// ``` pub fn keys(&self) -> impl Iterator { - self.iter().map(|(k, _)| k) + self.as_view().keys() } /// Removes a key from the map, returning the value at @@ -292,13 +367,7 @@ where K: Borrow, Q: Eq + ?Sized, { - let idx = self - .keys() - .enumerate() - .find(|&(_, k)| k.borrow() == key) - .map(|(idx, _)| idx); - - idx.map(|idx| self.buffer.swap_remove(idx).1) + self.as_mut_view().remove(key) } /// An iterator visiting all values in arbitrary order. @@ -318,7 +387,7 @@ where /// } /// ``` pub fn values(&self) -> impl Iterator { - self.iter().map(|(_, v)| v) + self.as_view().values() } /// An iterator visiting all values mutably in arbitrary order. @@ -342,7 +411,7 @@ where /// } /// ``` pub fn values_mut(&mut self) -> impl Iterator { - self.iter_mut().map(|(_, v)| v) + self.as_mut_view().values_mut() } } @@ -354,7 +423,7 @@ where type Output = V; fn index(&self, key: &Q) -> &V { - self.get(key).expect("no entry found for key") + self.as_view().index(key) } } @@ -364,7 +433,7 @@ where Q: Eq + ?Sized, { fn index_mut(&mut self, key: &Q) -> &mut V { - self.get_mut(key).expect("no entry found for key") + self.as_mut_view().index_mut(key) } } @@ -390,6 +459,369 @@ where } impl fmt::Debug for LinearMap +where + K: Eq + fmt::Debug, + V: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.as_view().fmt(f) + } +} + +impl LinearMapView +where + K: Eq, +{ + /// Returns the number of elements that the map can hold. + /// + /// Computes in *O*(1) time. + /// + /// # Examples + /// + /// ``` + /// use heapless::{LinearMap, LinearMapView}; + /// + /// let map: LinearMap<&str, isize, 8> = LinearMap::new(); + /// let map_view: &LinearMapView<&str, isize> = ↦ + /// assert_eq!(map_view.capacity(), 8); + /// ``` + pub fn capacity(&self) -> usize { + self.buffer.capacity() + } + + /// Clears the map, removing all key-value pairs. + /// + /// Computes in *O*(1) time. + /// + /// # Examples + /// + /// ``` + /// use heapless::{LinearMap, LinearMapView}; + /// + /// let mut map: LinearMap<_, _, 8> = LinearMap::new(); + /// let map_view: &mut LinearMapView<_, _> = &mut map; + /// map_view.insert(1, "a").unwrap(); + /// map_view.clear(); + /// assert!(map_view.is_empty()); + /// ``` + pub fn clear(&mut self) { + self.buffer.clear() + } + + /// Returns true if the map contains a value for the specified key. + /// + /// Computes in *O*(n) time. + /// + /// # Examples + /// + /// ``` + /// use heapless::{LinearMap, LinearMapView}; + /// + /// let mut map: LinearMap<_, _, 8> = LinearMap::new(); + /// let map_view: &mut LinearMapView<_, _> = &mut map; + /// map_view.insert(1, "a").unwrap(); + /// assert_eq!(map_view.contains_key(&1), true); + /// assert_eq!(map_view.contains_key(&2), false); + /// ``` + pub fn contains_key(&self, key: &K) -> bool { + self.get(key).is_some() + } + + /// Returns a reference to the value corresponding to the key. + /// + /// Computes in *O*(n) time. + /// + /// # Examples + /// + /// ``` + /// use heapless::{LinearMap, LinearMapView}; + /// + /// let mut map: LinearMap<_, _, 8> = LinearMap::new(); + /// let map_view: &mut LinearMapView<_, _> = &mut map; + /// map_view.insert(1, "a").unwrap(); + /// assert_eq!(map_view.get(&1), Some(&"a")); + /// assert_eq!(map_view.get(&2), None); + /// ``` + pub fn get(&self, key: &Q) -> Option<&V> + where + K: Borrow, + Q: Eq + ?Sized, + { + self.iter() + .find(|&(k, _)| k.borrow() == key) + .map(|(_, v)| v) + } + + /// Returns a mutable reference to the value corresponding to the key. + /// + /// Computes in *O*(n) time. + /// + /// # Examples + /// + /// ``` + /// use heapless::{LinearMap, LinearMapView}; + /// + /// let mut map: LinearMap<_, _, 8> = LinearMap::new(); + /// let map_view: &mut LinearMapView<_, _> = &mut map; + /// map_view.insert(1, "a").unwrap(); + /// if let Some(x) = map_view.get_mut(&1) { + /// *x = "b"; + /// } + /// assert_eq!(map_view[&1], "b"); + /// ``` + pub fn get_mut(&mut self, key: &Q) -> Option<&mut V> + where + K: Borrow, + Q: Eq + ?Sized, + { + self.iter_mut() + .find(|&(k, _)| k.borrow() == key) + .map(|(_, v)| v) + } + + /// Returns the number of elements in this map. + /// + /// Computes in *O*(1) time. + /// + /// # Examples + /// + /// ``` + /// use heapless::{LinearMap, LinearMapView}; + /// + /// let mut a: LinearMap<_, _, 8> = LinearMap::new(); + /// let mut a_view: &mut LinearMapView<_, _> = &mut a; + /// assert_eq!(a_view.len(), 0); + /// a_view.insert(1, "a").unwrap(); + /// assert_eq!(a_view.len(), 1); + /// ``` + pub fn len(&self) -> usize { + self.buffer.len() + } + + /// Inserts a key-value pair into the map. + /// + /// If the map did not have this key present, `None` is returned. + /// + /// If the map did have this key present, the value is updated, and the old value is returned. + /// + /// Computes in *O*(n) time + /// + /// # Examples + /// + /// ``` + /// use heapless::{LinearMap, LinearMapView}; + /// + /// let mut map: LinearMap<_, _, 8> = LinearMap::new(); + /// let map_view: &mut LinearMapView<_, _> = &mut map; + /// assert_eq!(map_view.insert(37, "a").unwrap(), None); + /// assert_eq!(map_view.is_empty(), false); + /// + /// map_view.insert(37, "b").unwrap(); + /// assert_eq!(map_view.insert(37, "c").unwrap(), Some("b")); + /// assert_eq!(map_view[&37], "c"); + /// ``` + pub fn insert(&mut self, key: K, mut value: V) -> Result, (K, V)> { + if let Some((_, v)) = self.iter_mut().find(|&(k, _)| *k == key) { + mem::swap(v, &mut value); + return Ok(Some(value)); + } + + self.buffer.push((key, value))?; + Ok(None) + } + + /// Returns true if the map contains no elements. + /// + /// Computes in *O*(1) time. + /// + /// # Examples + /// + /// ``` + /// use heapless::{LinearMap, LinearMapView}; + /// + /// let mut a: LinearMap<_, _, 8> = LinearMap::new(); + /// let a_view: &mut LinearMapView<_, _> = &mut a; + /// assert!(a_view.is_empty()); + /// a_view.insert(1, "a").unwrap(); + /// assert!(!a_view.is_empty()); + /// ``` + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// An iterator visiting all key-value pairs in arbitrary order. + /// + /// # Examples + /// + /// ``` + /// use heapless::{LinearMap, LinearMapView}; + /// + /// let mut map: LinearMap<_, _, 8> = LinearMap::new(); + /// let map_view: &mut LinearMapView<_, _> = &mut map; + /// map_view.insert("a", 1).unwrap(); + /// map_view.insert("b", 2).unwrap(); + /// map_view.insert("c", 3).unwrap(); + /// + /// for (key, val) in map_view.iter() { + /// println!("key: {} val: {}", key, val); + /// } + /// ``` + pub fn iter(&self) -> Iter<'_, K, V> { + Iter { + iter: self.buffer.as_slice().iter(), + } + } + + /// An iterator visiting all key-value pairs in arbitrary order, + /// with mutable references to the values. + /// + /// # Examples + /// + /// ``` + /// use heapless::{LinearMap, LinearMapView}; + /// + /// let mut map: LinearMap<_, _, 8> = LinearMap::new(); + /// let map_view: &mut LinearMapView<_, _> = &mut map; + /// map_view.insert("a", 1).unwrap(); + /// map_view.insert("b", 2).unwrap(); + /// map_view.insert("c", 3).unwrap(); + /// + /// // Update all values + /// for (_, val) in map_view.iter_mut() { + /// *val = 2; + /// } + /// + /// for (key, val) in &*map_view { + /// println!("key: {} val: {}", key, val); + /// } + /// ``` + pub fn iter_mut(&mut self) -> IterMut<'_, K, V> { + IterMut { + iter: self.buffer.as_mut_slice().iter_mut(), + } + } + + /// An iterator visiting all keys in arbitrary order. + /// + /// # Examples + /// + /// ``` + /// use heapless::{LinearMap, LinearMapView}; + /// + /// let mut map: LinearMap<_, _, 8> = LinearMap::new(); + /// let map_view: &mut LinearMapView<_, _> = &mut map; + /// map_view.insert("a", 1).unwrap(); + /// map_view.insert("b", 2).unwrap(); + /// map_view.insert("c", 3).unwrap(); + /// + /// for key in map_view.keys() { + /// println!("{}", key); + /// } + /// ``` + pub fn keys(&self) -> impl Iterator { + self.iter().map(|(k, _)| k) + } + + /// Removes a key from the map, returning the value at + /// the key if the key was previously in the map. + /// + /// Computes in *O*(n) time + /// + /// # Examples + /// + /// ``` + /// use heapless::{LinearMap, LinearMapView}; + /// + /// let mut map: LinearMap<_, _, 8> = LinearMap::new(); + /// let map_view: &mut LinearMapView<_, _> = &mut map; + /// map_view.insert(1, "a").unwrap(); + /// assert_eq!(map_view.remove(&1), Some("a")); + /// assert_eq!(map_view.remove(&1), None); + /// ``` + pub fn remove(&mut self, key: &Q) -> Option + where + K: Borrow, + Q: Eq + ?Sized, + { + let idx = self + .keys() + .enumerate() + .find(|&(_, k)| k.borrow() == key) + .map(|(idx, _)| idx); + + idx.map(|idx| self.buffer.swap_remove(idx).1) + } + + /// An iterator visiting all values in arbitrary order. + /// + /// # Examples + /// + /// ``` + /// use heapless::{LinearMap, LinearMapView}; + /// + /// let mut map: LinearMap<_, _, 8> = LinearMap::new(); + /// let map_view: &mut LinearMapView<_, _> = &mut map; + /// map_view.insert("a", 1).unwrap(); + /// map_view.insert("b", 2).unwrap(); + /// map_view.insert("c", 3).unwrap(); + /// + /// for val in map_view.values() { + /// println!("{}", val); + /// } + /// ``` + pub fn values(&self) -> impl Iterator { + self.iter().map(|(_, v)| v) + } + + /// An iterator visiting all values mutably in arbitrary order. + /// + /// # Examples + /// + /// ``` + /// use heapless::{LinearMap, LinearMapView}; + /// + /// let mut map: LinearMap<_, _, 8> = LinearMap::new(); + /// let map_view: &mut LinearMapView<_, _> = &mut map; + /// map_view.insert("a", 1).unwrap(); + /// map_view.insert("b", 2).unwrap(); + /// map_view.insert("c", 3).unwrap(); + /// + /// for val in map_view.values_mut() { + /// *val += 10; + /// } + /// + /// for val in map_view.values() { + /// println!("{}", val); + /// } + /// ``` + pub fn values_mut(&mut self) -> impl Iterator { + self.iter_mut().map(|(_, v)| v) + } +} + +impl<'a, K, V, Q> ops::Index<&'a Q> for LinearMapView +where + K: Borrow + Eq, + Q: Eq + ?Sized, +{ + type Output = V; + + fn index(&self, key: &Q) -> &V { + self.get(key).expect("no entry found for key") + } +} + +impl<'a, K, V, Q> ops::IndexMut<&'a Q> for LinearMapView +where + K: Borrow + Eq, + Q: Eq + ?Sized, +{ + fn index_mut(&mut self, key: &Q) -> &mut V { + self.get_mut(key).expect("no entry found for key") + } +} + +impl fmt::Debug for LinearMapView where K: Eq + fmt::Debug, V: fmt::Debug, @@ -451,6 +883,18 @@ where type Item = (&'a K, &'a V); type IntoIter = Iter<'a, K, V>; + fn into_iter(self) -> Self::IntoIter { + self.as_view().iter() + } +} + +impl<'a, K, V> IntoIterator for &'a LinearMapView +where + K: Eq, +{ + type Item = (&'a K, &'a V); + type IntoIter = Iter<'a, K, V>; + fn into_iter(self) -> Self::IntoIter { self.iter() } @@ -505,6 +949,46 @@ where { } +impl PartialEq> for LinearMapView +where + K: Eq, + V: PartialEq, +{ + fn eq(&self, other: &LinearMapView) -> bool { + self.len() == other.len() + && self + .iter() + .all(|(key, value)| other.get(key).map_or(false, |v| *value == *v)) + } +} + +impl PartialEq> for LinearMapView +where + K: Eq, + V: PartialEq, +{ + fn eq(&self, other: &LinearMap) -> bool { + self.eq(other.as_view()) + } +} + +impl PartialEq> for LinearMap +where + K: Eq, + V: PartialEq, +{ + fn eq(&self, other: &LinearMapView) -> bool { + self.as_view().eq(other) + } +} + +impl Eq for LinearMapView +where + K: Eq, + V: PartialEq, +{ +} + #[cfg(test)] mod test { use static_assertions::assert_not_impl_any; diff --git a/src/ser.rs b/src/ser.rs index f929ba8b12..27f13bbf32 100644 --- a/src/ser.rs +++ b/src/ser.rs @@ -1,8 +1,8 @@ use core::hash::{BuildHasher, Hash}; use crate::{ - binary_heap::Kind as BinaryHeapKind, BinaryHeap, Deque, IndexMap, IndexSet, LinearMap, String, - Vec, + binary_heap::Kind as BinaryHeapKind, + BinaryHeap, Deque, IndexMap, IndexSet, String, Vec, {LinearMap, LinearMapView}, }; use serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer}; @@ -94,7 +94,7 @@ where } } -impl Serialize for LinearMap +impl Serialize for LinearMapView where K: Eq + Serialize, V: Serialize, @@ -111,6 +111,19 @@ where } } +impl Serialize for LinearMap +where + K: Eq + Serialize, + V: Serialize, +{ + fn serialize(&self, serializer: SER) -> Result + where + SER: Serializer, + { + self.as_view().serialize(serializer) + } +} + // String containers impl Serialize for String {