blob: dd8cc376981b249c4bb8d010d465719832f78790 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! Common data structures.
pub use id_map::Entry;
pub(crate) use id_map::IdMap;
pub use id_map_collection::{IdMapCollection, IdMapCollectionKey};
/// Identifier map data structure.
///
/// Defines the [`IdMap`] data structure: A generic container mapped keyed
/// by an internally managed pool of identifiers kept densely packed.
pub(crate) mod id_map {
use std::collections::BTreeSet;
type Key = usize;
/// A generic container for `T` keyed by densily packed integers.
///
/// `IdMap` is a generic container keyed by `usize` that manages its own
/// key pool. `IdMap` reuses keys that are free to keep its key pool as
/// dense as possible.
///
/// The main guarantee provided by `IdMap` is that all `get` operations are
/// provided in O(1) without the need to hash the keys. The only operations
/// of `IdMap` that are used in the hot path are the `get` operations.
///
/// All operations that mutate the `IdMap` are O(log(n)) average.
///
/// `push` will grab the lowest free `id` and assign it to the given value,
/// returning the assigned `id`. `insert` can be used for assigning a
/// specific `id` to an object, and returns the previous object at that `id`
/// if any.
pub(crate) struct IdMap<T> {
data: Vec<Option<T>>,
avail: BTreeSet<Key>,
}
impl<T> IdMap<T> {
/// Creates a new empty [`IdMap`].
pub(crate) fn new() -> Self {
Self { data: Vec::new(), avail: BTreeSet::new() }
}
/// Returns `true` if there are no items in [`IdMap`].
pub(crate) fn is_empty(&self) -> bool {
!self.data.iter().any(|f| f.is_some())
}
/// Returns a reference to the item indexed by `key`, or `None` if
/// the `key` doesn't exist.
pub(crate) fn get(&self, key: Key) -> Option<&T> {
self.data.get(key).and_then(|v| v.as_ref())
}
/// Returns a mutable reference to the item indexed by `key`, or `None`
/// if the `key` doesn't exist.
pub(crate) fn get_mut(&mut self, key: Key) -> Option<&mut T> {
self.data.get_mut(key).and_then(|v| v.as_mut())
}
/// Removes item indexed by `key` from the container.
///
/// Returns the removed item if it exists, or `None` otherwise.
///
/// Note: the worst case complexity of `remove` is O(key) if the
/// backing data structure of the [`IdMap`] is too sparse.
pub(crate) fn remove(&mut self, key: Key) -> Option<T> {
let r = self.data.get_mut(key).and_then(|v| v.take());
if r.is_some() {
self.mark_avail(key);
// compress will also truncate available keys, if necessary.
self.compress();
}
r
}
/// Inserts `item` at `key`.
///
/// If the [`IdMap`] already contained an item indexed by `key`,
/// `insert` returns it, or `None` otherwise.
///
/// Note: The worst case complexity of `insert` is O(key) if `key` is
/// larger than the number of items currently held by the [`IdMap`].
pub(crate) fn insert(&mut self, key: Key, item: T) -> Option<T> {
if key < self.data.len() {
self.mark_unavail(key);
self.data[key].replace(item)
} else {
for idx in self.data.len()..key {
self.mark_avail(idx);
}
self.data.resize_with(key, Option::default);
self.data.push(Some(item));
None
}
}
/// Inserts `item` into the [`IdMap`].
///
/// `push` inserts a new `item` into the [`IdMap`] and returns the
/// key value allocated for `item`. `push` will allocate *any* key that
/// is currently free in the internal structure, so it may return a key
/// that was used previously but has since been removed.
///
/// Note: The worst case complexity of `push` is O(n) where n is the
/// number of items held by the [`IdMap`]. This can happen if the
/// internal structure gets fragmented.
// NOTE(brunodalbo) We could make push be O(1) if we kept a pool of
// available IDs as a separate vec inside IdMap. We expect that n will
// not get large enough for it to make too much of a difference here,
// but we may want to revisit this decision if it turns out that IdMap
// gets used for larger n's and fragmentation is concentrated at the
// end of the internal vec.
pub(crate) fn push(&mut self, item: T) -> Key {
let k = self.get_avail();
self.data[k].replace(item);
k
}
/// Compresses the tail of the internal `Vec`.
///
/// `compress` removes all trailing elements in `data` that are `None`,
/// reducing the internal `Vec`.
fn compress(&mut self) {
if let Some(idx) = self.data.iter().enumerate().rev().find_map(|(k, v)| {
if v.is_some() {
Some(k)
} else {
None
}
}) {
self.data.truncate(idx + 1);
self.truncate_avail(idx);
} else {
self.data.clear();
self.avail.clear();
}
}
/// Creates an iterator over the containing items and their associated
/// keys.
pub(crate) fn iter(&self) -> impl Iterator<Item = (Key, &T)> {
self.data.iter().enumerate().filter_map(|(k, v)| v.as_ref().map(|t| (k, t)))
}
/// Creates a mutable iterator over the containing items and their
/// associated keys.
pub(crate) fn iter_mut(&mut self) -> impl Iterator<Item = (Key, &mut T)> {
self.data.iter_mut().enumerate().filter_map(|(k, v)| v.as_mut().map(|t| (k, t)))
}
/// Gets the given key's corresponding entry in the map for in-place
/// manipulation.
pub(crate) fn entry(&mut self, key: usize) -> Entry<'_, usize, T> {
if key < self.data.len() {
let slot = &mut self.data[key];
if slot.is_some() {
Entry::Occupied(OccupiedEntry { key, value: slot })
} else {
Entry::Vacant(VacantEntry { key, slot: LazyEntry::Allocated(slot) })
}
} else {
Entry::Vacant(VacantEntry { key, slot: LazyEntry::Lazy(self) })
}
}
/// Gets the lowest available key that does not have an associated value. If no keys are
/// available, storage is extended by 1 and the key for the new space is returned. O(n)
/// worst case, O(log(n)) average.
fn get_avail(&mut self) -> Key {
if let Some(k) = self.avail.iter().next() {
let mut key = k.clone();
self.avail.take(&key).unwrap()
} else {
self.data.push(None);
self.data.len() - 1
}
}
/// Returns the given key to the pool of unused keys. O(log(n)) average.
fn mark_avail(&mut self, key: Key) {
self.avail.insert(key);
}
/// Marks the key as being in use. O(log(n)) average.
fn mark_unavail(&mut self, key: Key) {
self.avail.remove(&key);
}
/// Truncates the set of available keys, removing all keys equal to or above the given
/// value. O(log(n)) average.
fn truncate_avail(&mut self, trunc_key: Key) {
self.avail.split_off(&trunc_key);
}
}
impl<T> Default for IdMap<T> {
fn default() -> Self {
Self::new()
}
}
pub trait EntryKey {
fn get_key_index(&self) -> usize;
}
impl EntryKey for usize {
fn get_key_index(&self) -> usize {
*self
}
}
enum LazyEntry<'a, T> {
Allocated(&'a mut Option<T>),
Lazy(&'a mut IdMap<T>),
}
/// A view into a vacant entry in a map. It is part of the [`Entry`] enum.
pub struct VacantEntry<'a, K, T> {
key: K,
slot: LazyEntry<'a, T>,
}
impl<'a, K, T> VacantEntry<'a, K, T> {
/// Sets the value of the entry with the VacantEntry's key, and returns
/// a mutable reference to it.
pub fn insert(self, value: T) -> &'a mut T
where
K: EntryKey,
{
match self.slot {
LazyEntry::Allocated(slot) => {
assert!(slot.replace(value).is_none());
slot.as_mut().unwrap()
}
LazyEntry::Lazy(id_map) => {
assert!(id_map.insert(self.key.get_key_index(), value).is_none());
id_map.data[self.key.get_key_index()].as_mut().unwrap()
}
}
}
/// Gets a reference to the key that would be used when inserting a
/// value through the `VacantEntry`.
pub fn key(&self) -> &K {
&self.key
}
/// Take ownership of the key.
pub fn into_key(self) -> K {
self.key
}
/// Changes the key type of this `VacantEntry` to another key `X` that
/// still maps to the same index in an `IdMap`.
///
/// # Panics
///
/// Panics if the resulting mapped key from `f` does not return the
/// same value for [`EntryKey::get_key_index`] as the old key did.
pub(crate) fn map_key<X, F>(self, f: F) -> VacantEntry<'a, X, T>
where
K: EntryKey,
X: EntryKey,
F: FnOnce(K) -> X,
{
let idx = self.key.get_key_index();
let key = f(self.key);
assert_eq!(idx, key.get_key_index());
VacantEntry { key, slot: self.slot }
}
}
/// A view into an occupied entry in a map. It is part of the
/// [`Entry`] enum.
pub struct OccupiedEntry<'a, K, T> {
key: K,
value: &'a mut Option<T>,
}
impl<'a, K, T> OccupiedEntry<'a, K, T> {
/// Gets a reference to the key in the entry.
pub fn key(&self) -> &K {
&self.key
}
/// Gets a reference to the value in the entry.
pub fn get(&self) -> &T {
// we can unwrap because value is always Some for OccupiedEntry
self.value.as_ref().unwrap()
}
/// Gets a mutable reference to the value in the entry.
///
/// If you need a reference to the `OccupiedEntry` which may outlive the
/// destruction of the entry value, see [`OccupiedEntry::into_mut`].
pub fn get_mut(&mut self) -> &mut T {
// we can unwrap because value is always Some for OccupiedEntry
self.value.as_mut().unwrap()
}
/// Converts the `OccupiedEntry` into a mutable reference to the value
/// in the entry with a lifetime bound to the map itself.
///
/// If you need multiple references to the `OccupiedEntry`, see
/// [`OccupiedEntry::get_mut`].
pub fn into_mut(self) -> &'a mut T {
// we can unwrap because value is always Some for OccupiedEntry
self.value.as_mut().unwrap()
}
/// Sets the value of the entry, and returns the entry's old value.
pub fn insert(&mut self, value: T) -> T {
// we can unwrap because value is always Some for OccupiedEntry
self.value.replace(value).unwrap()
}
/// Takes the value out of the entry, and returns it.
pub fn remove(self) -> T {
// we can unwrap because value is always Some for OccupiedEntry
self.value.take().unwrap()
}
/// Changes the key type of this `OccupiedEntry` to another key `X` that
/// still maps to the same index in an `IdMap`.
///
/// # Panics
///
/// Panics if the resulting mapped key from `f` does not return the
/// same value for [`EntryKey::get_key_index`] as the old key did.
pub(crate) fn map_key<X, F>(self, f: F) -> OccupiedEntry<'a, X, T>
where
K: EntryKey,
X: EntryKey,
F: FnOnce(K) -> X,
{
let idx = self.key.get_key_index();
let key = f(self.key);
assert_eq!(idx, key.get_key_index());
OccupiedEntry { key, value: self.value }
}
}
/// A view into an in-place entry in a map that can be vacant or occupied.
pub enum Entry<'a, K, T> {
Vacant(VacantEntry<'a, K, T>),
Occupied(OccupiedEntry<'a, K, T>),
}
impl<'a, K, T> Entry<'a, K, T> {
/// Returns a reference to this entry's key.
pub fn key(&self) -> &K {
match self {
Entry::Vacant(e) => e.key(),
Entry::Occupied(e) => e.key(),
}
}
/// Ensures a value is in the entry by inserting `default` if empty,
/// and returns a mutable reference to the value in the entry.
pub fn or_insert(self, default: T) -> &'a mut T
where
K: EntryKey,
{
match self {
Entry::Vacant(e) => e.insert(default),
Entry::Occupied(e) => e.into_mut(),
}
}
/// Ensures a value is in the entry by inserting the result of the
/// function `f` if empty, and returns a mutable reference to the value
/// in the entry.
pub fn or_insert_with<F: FnOnce() -> T>(self, f: F) -> &'a mut T
where
K: EntryKey,
{
match self {
Entry::Vacant(e) => e.insert(f()),
Entry::Occupied(e) => e.into_mut(),
}
}
/// Ensures a value is in the entry by inserting the default value if
/// empty, and returns a mutable reference to the value in the entry.
pub fn or_default(self) -> &'a mut T
where
T: Default,
K: EntryKey,
{
self.or_insert_with(<T as Default>::default)
}
/// Provides in-place mutable access to an occupied entry before any
/// potential inserts into the map.
pub fn and_modify<F: FnOnce(&mut T)>(self, f: F) -> Self {
match self {
Entry::Vacant(e) => Entry::Vacant(e),
Entry::Occupied(mut e) => {
f(e.get_mut());
Entry::Occupied(e)
}
}
}
/// Changes the key type of this `Entry` to another key `X` that still
/// maps to the same index in an `IdMap`.
///
/// # Panics
///
/// Panics if the resulting mapped key from `f` does not return the
/// same value for [`EntryKey::get_key_index`] as the old key did.
pub(crate) fn map_key<X, F>(self, f: F) -> Entry<'a, X, T>
where
K: EntryKey,
X: EntryKey,
F: FnOnce(K) -> X,
{
match self {
Entry::Vacant(e) => Entry::Vacant(e.map_key(f)),
Entry::Occupied(e) => Entry::Occupied(e.map_key(f)),
}
}
}
#[cfg(test)]
mod tests {
use super::{Entry, IdMap};
use std::collections::BTreeSet;
use std::iter::FromIterator;
#[test]
fn test_push() {
let mut map = IdMap::new();
map.insert(1, 2);
assert_eq!(map.data, vec![None, Some(2)]);
assert_eq!(map.push(1), 0);
assert_eq!(map.data, vec![Some(1), Some(2)]);
assert_eq!(map.push(3), 2);
assert_eq!(map.data, vec![Some(1), Some(2), Some(3)]);
}
#[test]
fn test_get() {
let mut map = IdMap::new();
map.push(1);
map.insert(2, 3);
assert_eq!(map.data, vec![Some(1), None, Some(3)]);
assert_eq!(*map.get(0).unwrap(), 1);
assert!(map.get(1).is_none());
assert_eq!(*map.get(2).unwrap(), 3);
assert!(map.get(3).is_none());
}
#[test]
fn test_get_mut() {
let mut map = IdMap::new();
map.push(1);
map.insert(2, 3);
assert_eq!(map.data, vec![Some(1), None, Some(3)]);
*map.get_mut(2).unwrap() = 10;
assert_eq!(*map.get(0).unwrap(), 1);
assert_eq!(*map.get(2).unwrap(), 10);
assert!(map.get_mut(1).is_none());
assert!(map.get_mut(3).is_none());
}
#[test]
fn test_is_empty() {
let mut map = IdMap::<i32>::new();
assert!(map.is_empty());
map.push(1);
assert!(!map.is_empty());
}
#[test]
fn test_remove() {
let mut map = IdMap::new();
map.push(1);
map.push(2);
map.push(3);
assert_eq!(map.data, vec![Some(1), Some(2), Some(3)]);
assert_eq!(map.avail, BTreeSet::new());
assert_eq!(map.remove(1).unwrap(), 2);
assert_eq!(map.avail, BTreeSet::from_iter(vec![1].into_iter()));
assert!(map.remove(1).is_none());
assert_eq!(map.data, vec![Some(1), None, Some(3)]);
}
#[test]
fn test_remove_compress() {
let mut map = IdMap::new();
map.push(1);
map.insert(2, 3);
assert_eq!(map.data, vec![Some(1), None, Some(3)]);
assert_eq!(map.avail, BTreeSet::from_iter(vec![1].into_iter()));
assert_eq!(map.remove(2).unwrap(), 3);
assert_eq!(map.data, vec![Some(1)]);
assert!(map.avail.is_empty());
assert_eq!(map.remove(0).unwrap(), 1);
assert!(map.data.is_empty());
assert!(map.avail.is_empty());
}
#[test]
fn test_insert() {
let mut map = IdMap::new();
assert!(map.insert(1, 2).is_none());
assert_eq!(map.data, vec![None, Some(2)]);
assert_eq!(map.avail, BTreeSet::from_iter(vec![0].into_iter()));
assert!(map.insert(3, 4).is_none());
assert_eq!(map.data, vec![None, Some(2), None, Some(4)]);
assert_eq!(map.avail, BTreeSet::from_iter(vec![0, 2].into_iter()));
assert!(map.insert(0, 1).is_none());
assert_eq!(map.data, vec![Some(1), Some(2), None, Some(4)]);
assert_eq!(map.avail, BTreeSet::from_iter(vec![2].into_iter()));
assert_eq!(map.insert(3, 5).unwrap(), 4);
assert_eq!(map.data, vec![Some(1), Some(2), None, Some(5)]);
assert_eq!(map.avail, BTreeSet::from_iter(vec![2].into_iter()));
}
#[test]
fn test_iter() {
let mut map = IdMap::new();
map.insert(1, 0);
map.insert(3, 1);
map.insert(6, 2);
assert_eq!(map.data, vec![None, Some(0), None, Some(1), None, None, Some(2)]);
let mut c = 0;
for (i, (k, v)) in map.iter().enumerate() {
assert_eq!(i, *v as usize);
assert_eq!(map.get(k).unwrap(), v);
c += 1;
}
assert_eq!(c, 3);
}
#[test]
fn test_iter_mut() {
let mut map = IdMap::new();
map.insert(1, 0);
map.insert(3, 1);
map.insert(6, 2);
assert_eq!(map.data, vec![None, Some(0), None, Some(1), None, None, Some(2)]);
for (k, v) in map.iter_mut() {
*v += k as u32;
}
assert_eq!(map.data, vec![None, Some(1), None, Some(4), None, None, Some(8)]);
}
#[test]
fn test_entry() {
let mut map = IdMap::new();
assert_eq!(*map.entry(1).or_insert(2), 2);
assert_eq!(map.data, vec![None, Some(2)]);
assert_eq!(
*map.entry(1)
.and_modify(|v| {
*v = 10;
})
.or_insert(5),
10
);
assert_eq!(map.data, vec![None, Some(10)]);
assert_eq!(
*map.entry(2)
.and_modify(|v| {
*v = 10;
})
.or_insert(5),
5
);
assert_eq!(map.data, vec![None, Some(10), Some(5)]);
assert_eq!(*map.entry(4).or_default(), 0);
assert_eq!(map.data, vec![None, Some(10), Some(5), None, Some(0)]);
assert_eq!(*map.entry(3).or_insert_with(|| 7), 7);
assert_eq!(map.data, vec![None, Some(10), Some(5), Some(7), Some(0)]);
assert_eq!(*map.entry(0).or_insert(1), 1);
assert_eq!(map.data, vec![Some(1), Some(10), Some(5), Some(7), Some(0)]);
match map.entry(0) {
Entry::Occupied(mut e) => {
assert_eq!(*e.key(), 0);
assert_eq!(*e.get(), 1);
*e.get_mut() = 2;
assert_eq!(*e.get(), 2);
assert_eq!(e.remove(), 2);
}
_ => panic!("Wrong entry type, should be occupied"),
}
assert_eq!(map.data, vec![None, Some(10), Some(5), Some(7), Some(0)]);
match map.entry(0) {
Entry::Vacant(mut e) => {
assert_eq!(*e.key(), 0);
assert_eq!(*e.insert(4), 4);
}
_ => panic!("Wrong entry type, should be vacant"),
}
assert_eq!(map.data, vec![Some(4), Some(10), Some(5), Some(7), Some(0)]);
}
}
}
/// Identifier map collection data structure.
///
/// Defines [`IdMapCollection`], which is a generic map collection that can be
/// keyed on [`IdMapCollectionKey`], which is a two-level key structure.
///
/// Used to provide collections keyed on [`crate::DeviceId`] that match hot path
/// performance requirements.
pub mod id_map_collection {
use super::id_map::{Entry, EntryKey};
use super::IdMap;
/// A key that can index items in [`IdMapCollection`].
///
/// An `IdMapCollectionKey` is a key with two levels: `variant` and `id`.
/// The number of `variant`s must be fixed and known at compile time, and is
/// typically mapped to a number of `enum` variants (nested or not).
pub trait IdMapCollectionKey {
/// The number of variants this key supports.
const VARIANT_COUNT: usize;
/// Get the variant index for this key.
///
/// # Panics
///
/// Callers may assume that `get_variant` returns a value in the range
/// `[0, VARIANT_COUNT)`, and may panic if that assumption is violated.
fn get_variant(&self) -> usize;
/// Get the id index for this key.
fn get_id(&self) -> usize;
}
impl<O> EntryKey for O
where
O: IdMapCollectionKey,
{
fn get_key_index(&self) -> usize {
<O as IdMapCollectionKey>::get_id(self)
}
}
/// A generic collection indexed by an [`IdMapCollectionKey`].
///
/// `IdMapCollection` provides the same performance guarantees as [`IdMap`],
/// but provides a two-level keying scheme that matches the pattern used
/// in [`crate::DeviceId`].
pub struct IdMapCollection<K: IdMapCollectionKey, T> {
// TODO(brunodalbo): we define a vector container here because we can't
// just define a fixed array length based on an associated const in
// IdMapCollectionKey. When rust issue #43408 gets resolved we can
// switch this to use the associated const and just have a fixed length
// array.
data: Vec<IdMap<T>>,
_marker: std::marker::PhantomData<K>,
}
impl<K: IdMapCollectionKey, T> IdMapCollection<K, T> {
/// Creates a new empty `IdMapCollection`.
pub fn new() -> Self {
let mut data = Vec::new();
data.resize_with(K::VARIANT_COUNT, IdMap::default);
Self { data, _marker: std::marker::PhantomData }
}
fn get_map(&self, key: &K) -> &IdMap<T> {
&self.data[key.get_variant()]
}
fn get_map_mut(&mut self, key: &K) -> &mut IdMap<T> {
&mut self.data[key.get_variant()]
}
/// Returns `true` if the `IdMapCollection` holds no items.
pub fn is_empty(&self) -> bool {
self.data.iter().all(|d| d.is_empty())
}
/// Returns a reference to the item indexed by `key`, or `None` if
/// the `key` doesn't exist.
pub fn get(&self, key: &K) -> Option<&T> {
self.get_map(key).get(key.get_id())
}
/// Returns a mutable reference to the item indexed by `key`, or `None`
/// if the `key` doesn't exist.
pub fn get_mut(&mut self, key: &K) -> Option<&mut T> {
self.get_map_mut(key).get_mut(key.get_id())
}
/// Removes item indexed by `key` from the container.
///
/// Returns the removed item if it exists, or `None` otherwise.
pub fn remove(&mut self, key: &K) -> Option<T> {
self.get_map_mut(key).remove(key.get_id())
}
/// Inserts `item` at `key`.
///
/// If the [`IdMapCollection`] already contained an item indexed by
/// `key`, `insert` returns it, or `None` otherwise.
pub fn insert(&mut self, key: &K, item: T) -> Option<T> {
self.get_map_mut(key).insert(key.get_id(), item)
}
/// Creates an iterator over the containing items.
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.data.iter().flat_map(|m| m.iter()).map(|(_, v)| v)
}
/// Creates a mutable iterator over the containing items.
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
self.data.iter_mut().flat_map(|m| m.iter_mut()).map(|(_, v)| v)
}
/// Gets the given key's corresponding entry in the map for in-place
/// manipulation.
pub fn entry(&mut self, key: K) -> Entry<'_, K, T> {
self.get_map_mut(&key).entry(key.get_id()).map_key(|_| key)
}
}
impl<K: IdMapCollectionKey, T> Default for IdMapCollection<K, T> {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
enum MockVariants {
A,
B,
C,
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
struct MockKey {
id: usize,
var: MockVariants,
}
impl MockKey {
const fn new(id: usize, var: MockVariants) -> Self {
Self { id, var }
}
}
impl IdMapCollectionKey for MockKey {
const VARIANT_COUNT: usize = 3;
fn get_variant(&self) -> usize {
match self.var {
MockVariants::A => 0,
MockVariants::B => 1,
MockVariants::C => 2,
}
}
fn get_id(&self) -> usize {
self.id
}
}
type TestCollection = IdMapCollection<MockKey, i32>;
const KEY_A: MockKey = MockKey::new(0, MockVariants::A);
const KEY_B: MockKey = MockKey::new(2, MockVariants::B);
const KEY_C: MockKey = MockKey::new(4, MockVariants::C);
#[test]
fn test_insert_and_get() {
let mut t = TestCollection::new();
assert!(t.data[0].is_empty());
assert!(t.data[1].is_empty());
assert!(t.data[2].is_empty());
assert!(t.insert(&KEY_A, 1).is_none());
assert!(!t.data[0].is_empty());
assert!(t.insert(&KEY_B, 2).is_none());
assert!(!t.data[1].is_empty());
assert_eq!(*t.get(&KEY_A).unwrap(), 1);
assert!(t.get(&KEY_C).is_none());
*t.get_mut(&KEY_B).unwrap() = 3;
assert_eq!(*t.get(&KEY_B).unwrap(), 3);
}
#[test]
fn test_remove() {
let mut t = TestCollection::new();
assert!(t.insert(&KEY_B, 15).is_none());
assert_eq!(t.remove(&KEY_B).unwrap(), 15);
assert!(t.remove(&KEY_B).is_none());
}
#[test]
fn test_iter() {
let mut t = TestCollection::new();
assert!(t.insert(&KEY_A, 15).is_none());
assert!(t.insert(&KEY_B, -5).is_none());
assert!(t.insert(&KEY_C, -10).is_none());
let mut c = 0;
let mut sum = 0;
for i in t.iter() {
c += 1;
sum += *i;
}
assert_eq!(c, 3);
assert_eq!(sum, 0);
}
#[test]
fn test_is_empty() {
let mut t = TestCollection::new();
assert!(t.is_empty());
assert!(t.insert(&KEY_B, 15).is_none());
assert!(!t.is_empty());
}
#[test]
fn test_iter_mut() {
let mut t = TestCollection::new();
assert!(t.insert(&KEY_A, 15).is_none());
assert!(t.insert(&KEY_B, -5).is_none());
assert!(t.insert(&KEY_C, -10).is_none());
for i in t.iter_mut() {
*i *= 2;
}
assert_eq!(*t.get(&KEY_A).unwrap(), 30);
assert_eq!(*t.get(&KEY_B).unwrap(), -10);
assert_eq!(*t.get(&KEY_C).unwrap(), -20);
}
#[test]
fn test_entry() {
let mut t = TestCollection::new();
assert_eq!(*t.entry(KEY_A).or_insert(2), 2);
assert_eq!(
*t.entry(KEY_A)
.and_modify(|v| {
*v = 10;
})
.or_insert(5),
10
);
assert_eq!(
*t.entry(KEY_B)
.and_modify(|v| {
*v = 10;
})
.or_insert(5),
5
);
assert_eq!(*t.entry(KEY_C).or_insert_with(|| 7), 7);
assert_eq!(*t.entry(KEY_C).key(), KEY_C);
assert_eq!(*t.get(&KEY_A).unwrap(), 10);
assert_eq!(*t.get(&KEY_B).unwrap(), 5);
assert_eq!(*t.get(&KEY_C).unwrap(), 7);
}
}
}