use super::{Bomb, DropTracker};
use crate::{Config, FullError, GenMap, InsertError, InsertWithError, Packed, Split};
use arrayvec::ArrayVec;
use std::panic::{catch_unwind, AssertUnwindSafe};
use std::vec::Vec;
struct Four;
impl Config for Four {
type Idx = u8;
type Gen = u8;
type Layout = Split;
type Storage<S> = ArrayVec<S, 4>;
}
struct Sixteen;
impl Config for Sixteen {
type Idx = u8;
type Gen = u8;
type Layout = Packed<u8, 4>;
type Storage<S> = ArrayVec<S, 16>;
}
fn full_map() -> GenMap<u32, Four> {
let mut map = GenMap::new_with_config();
for i in 0..4 {
map.insert(i);
}
map
}
#[test]
fn a_map_in_an_array_vec_works_like_any_other() {
let mut map = GenMap::<u32, Four>::new_with_config();
assert_eq!(map.capacity(), 4);
let keys: Vec<_> = (0..3).map(|i| map.insert(i)).collect();
assert_eq!(map[keys[1]], 1);
assert_eq!(map.remove(keys[1]), Some(1));
assert!(map.get(keys[1]).is_none());
let again = map.insert(10);
assert_eq!(again.idx(), keys[1].idx());
assert!(map.get(keys[1]).is_none());
let values: Vec<_> = map.values().copied().collect();
assert_eq!(values, [0, 10, 2]);
assert_eq!(map.capacity(), 4);
}
#[test]
fn a_map_in_an_array_vec_can_be_made_in_a_const() {
const EMPTY: GenMap<u32, Four> = GenMap::new_with_config();
let mut map = EMPTY;
let key = map.insert(1);
assert_eq!(map[key], 1);
}
#[test]
fn a_full_array_vec_reports_storage_full() {
let mut map = full_map();
assert_eq!(map.slots_len(), 4);
assert!(matches!(
map.try_insert(4),
Err(InsertError::StorageFull(4, _))
));
assert!(matches!(map.vacant_entry(), Err(FullError::StorageFull(_))));
let mut called = false;
let result = map.try_insert_with_key(|_| {
called = true;
Ok::<_, ()>(4)
});
assert!(matches!(
result,
Err(InsertWithError::Full(FullError::StorageFull(_)))
));
assert!(!called);
assert_eq!(map.len(), 4);
}
#[test]
#[should_panic(expected = "its storage can not make room for more than 4 slots")]
fn insert_panics_when_the_array_vec_is_full() {
let mut map = full_map();
map.insert(4);
}
#[test]
fn a_freed_slot_is_reused_when_the_array_vec_is_full() {
let mut map = full_map();
let key = map.key_at(2).unwrap();
assert_eq!(map.remove(key), Some(2));
let again = map.insert(20);
assert_eq!(again.idx(), 2);
assert_eq!(map[again], 20);
assert_eq!(map.slots_len(), 4);
assert!(map.try_insert(5).is_err());
}
#[test]
fn the_index_is_reported_when_it_runs_out_with_the_array_vec() {
let mut map = GenMap::<u32, Sixteen>::new_with_config();
for i in 0..16 {
map.insert(i);
}
assert!(matches!(
map.try_insert(16),
Err(InsertError::IndexExhausted(16))
));
}
#[test]
fn clear_and_reset_empty_an_array_vec() {
let mut map = full_map();
let old = map.key_at(0).unwrap();
map.clear();
assert!(map.is_empty());
assert_eq!(map.slots_len(), 4);
assert!(map.get(old).is_none());
map.reset();
assert_eq!(map.slots_len(), 0);
let keys: Vec<_> = (0..4).map(|i| map.insert(i)).collect();
assert_eq!(keys.len(), 4);
assert!(map.try_insert(4).is_err());
}
#[test]
fn values_in_an_array_vec_are_dropped_exactly_once() {
let tracker = DropTracker::new();
let mut map = GenMap::<_, Four>::new_with_config();
let keys: Vec<_> = (0..4).map(|_| map.insert(tracker.make_item())).collect();
drop(map.remove(keys[0]));
let mut copy = map.clone();
copy.clone_from(&map);
let mut iter = copy.into_iter();
drop(iter.next());
drop(iter);
map.retain(|key, _| key != keys[1]);
drop(map.drain().next());
drop(map);
tracker.assert_all_dropped_exactly_once(tracker.total_made());
}
#[test]
fn an_array_vec_drops_every_value_once_when_a_drop_panics() {
let tracker = DropTracker::new();
let mut map = GenMap::<_, Four>::new_with_config();
for i in 0..4 {
map.insert(Bomb::new(&tracker, i == 1));
}
assert!(catch_unwind(AssertUnwindSafe(move || drop(map))).is_err());
tracker.assert_all_dropped_exactly_once(4);
let tracker = DropTracker::new();
let mut map = GenMap::<_, Four>::new_with_config();
for i in 0..4 {
map.insert(Bomb::new(&tracker, i == 2));
}
let mut iter = map.into_iter();
drop(iter.next());
assert!(catch_unwind(AssertUnwindSafe(move || drop(iter))).is_err());
tracker.assert_all_dropped_exactly_once(4);
}