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