#![forbid(unsafe_code)]
#![no_std]
extern crate alloc;
mod bookmark;
mod entry;
mod fast_eq;
mod into_iter;
mod into_keys;
mod into_values;
mod iter;
mod iter_mut;
mod keys;
mod macros;
mod occupied_entry;
mod sailed;
mod vacant_entry;
mod values;
mod values_mut;
pub use bookmark::Bookmark;
pub use entry::Entry;
pub use fast_eq::FastEq;
pub use into_iter::IntoIter;
pub use into_keys::IntoKeys;
pub use into_values::IntoValues;
pub use iter::Iter;
pub use iter_mut::IterMut;
pub use keys::Keys;
pub use occupied_entry::OccupiedEntry;
pub use vacant_entry::VacantEntry;
pub use values::Values;
pub use values_mut::ValuesMut;
use sailed::{ContainsKey, Get, GetKeyValue, GetKeyValueMut, GetMut, Remove, RemoveEntry};
use alloc::vec::Vec;
use core::borrow::Borrow;
use core::fmt;
use core::hash::{Hash, Hasher};
pub struct AList<K, V> {
pairs: Vec<(K, V)>,
}
impl<K: FastEq, V> FromIterator<(K, V)> for AList<K, V> {
fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
let mut this = Self::new();
this.extend(iter);
this
}
}
impl<K, V> Default for AList<K, V> {
fn default() -> Self {
Self::new()
}
}
impl<K, V> AList<K, V> {
#[must_use]
pub const fn new() -> Self {
Self { pairs: Vec::new() }
}
#[must_use]
pub fn with_capacity(capacity: usize) -> Self {
Self {
pairs: Vec::with_capacity(capacity),
}
}
#[must_use]
pub fn bookmark<'q, Q>(&self, key: &'q Q) -> Option<Bookmark<'q, Q, K, V>>
where
K: Borrow<Q>,
Q: FastEq + ?Sized,
{
let position = self.position(key)?;
Some(Bookmark::new_with_position(key, position))
}
#[must_use]
pub fn entry(&mut self, key: K) -> Entry<'_, K, V>
where
K: FastEq,
{
if let Some(position) = self.position(&key) {
return Entry::Occupied(OccupiedEntry::new(self, position));
}
Entry::Vacant(VacantEntry::new(self, key))
}
pub fn insert(&mut self, key: K, value: V) -> Option<V>
where
K: FastEq,
{
if let Some(position) = self.position(&key) {
let (_, v) = &mut self.pairs[position];
return Some(core::mem::replace(v, value));
}
self.pairs.push((key, value));
None
}
#[must_use]
pub fn get(&self, key: impl Get<K, V>) -> Option<&V> {
key.get(self)
}
#[must_use]
pub fn get_mut(&mut self, key: impl GetMut<K, V>) -> Option<&mut V> {
key.get_mut(self)
}
#[must_use]
pub fn get_key_value(&self, key: impl GetKeyValue<K, V>) -> Option<(&K, &V)> {
key.get_key_value(self)
}
#[must_use]
pub fn get_key_value_mut(&mut self, key: impl GetKeyValueMut<K, V>) -> Option<(&K, &mut V)> {
key.get_key_value_mut(self)
}
#[must_use]
pub fn contains_key(&self, key: impl ContainsKey<K, V>) -> bool {
key.contains_key(self)
}
#[must_use]
pub fn remove(&mut self, key: impl Remove<K, V>) -> Option<V> {
key.remove(self)
}
#[must_use]
pub fn remove_entry(&mut self, key: impl RemoveEntry<K, V>) -> Option<(K, V)> {
key.remove_entry(self)
}
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(&K, &V) -> bool,
{
self.pairs.retain(|(k, v)| f(k, v));
}
pub fn retain_mut<F>(&mut self, mut f: F)
where
F: FnMut(&K, &mut V) -> bool,
{
self.pairs.retain_mut(|(k, v)| f(k, v));
}
#[inline]
#[must_use]
fn position<Q>(&self, key: &Q) -> Option<usize>
where
K: Borrow<Q>,
Q: FastEq + ?Sized,
{
self.pairs.iter().rposition(|(k, _)| k.borrow() == key)
}
#[must_use]
fn refresh_position<Q>(&self, key: &Q, previous_position: usize) -> Option<usize>
where
K: Borrow<Q>,
Q: FastEq + ?Sized,
{
let len = self.pairs.len();
if len == 0 {
return None;
}
let start = previous_position.min(len - 1);
if let Some(position) = self.pairs[..=start]
.iter()
.rposition(|(k, _)| k.borrow() == key)
{
return Some(position);
}
self.pairs[start + 1..]
.iter()
.rposition(|(k, _)| k.borrow() == key)
.map(|position| start + 1 + position)
}
#[must_use]
fn is_valid<Q>(&self, bookmark: &Bookmark<Q, K, V>) -> bool
where
K: Borrow<Q>,
Q: FastEq + ?Sized,
{
self.pairs
.get(bookmark.position)
.map(|(k, _)| k.borrow() == bookmark.key())
.unwrap_or(false)
}
}
impl<K: FastEq, V> Extend<(K, V)> for AList<K, V> {
fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
let pairs = iter.into_iter();
let (lower, _) = pairs.size_hint();
self.reserve(lower);
for (key, value) in pairs {
if let Some(position) = self.position(&key) {
let (_, v) = &mut self.pairs[position];
*v = value;
} else {
self.pairs.push((key, value));
}
}
}
}
impl<'a, K: FastEq + Clone, V: Clone> Extend<(&'a K, &'a V)> for AList<K, V> {
fn extend<T: IntoIterator<Item = (&'a K, &'a V)>>(&mut self, values: T) {
self.extend(values.into_iter().map(|(k, v)| (k.clone(), v.clone())))
}
}
impl<K, V> AList<K, V> {
pub fn shrink_to_fit(&mut self) {
self.pairs.shrink_to_fit();
}
pub fn shrink_to(&mut self, min_capacity: usize) {
self.pairs.shrink_to(min_capacity);
}
pub fn reserve(&mut self, additional: usize) {
self.pairs.reserve(additional);
}
pub fn reserve_exact(&mut self, additional: usize) {
self.pairs.reserve_exact(additional);
}
#[must_use]
pub fn capacity(&self) -> usize {
self.pairs.capacity()
}
#[must_use]
pub fn len(&self) -> usize {
self.pairs.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.pairs.is_empty()
}
pub fn clear(&mut self) {
self.pairs.clear();
}
#[must_use]
pub fn keys(&self) -> Keys<'_, K, V> {
Keys::from_delegate(self.pairs.iter())
}
#[must_use]
pub fn into_keys(self) -> IntoKeys<K, V> {
IntoKeys::from_delegate(self.pairs.into_iter())
}
#[must_use]
pub fn values(&self) -> Values<'_, K, V> {
Values::from_delegate(self.pairs.iter())
}
#[must_use]
pub fn values_mut(&mut self) -> ValuesMut<'_, K, V> {
ValuesMut::from_delegate(self.pairs.iter_mut())
}
#[must_use]
pub fn into_values(self) -> IntoValues<K, V> {
IntoValues::from_delegate(self.pairs.into_iter())
}
#[must_use]
pub fn iter(&self) -> Iter<'_, K, V> {
Iter::from_delegate(self.pairs.iter())
}
#[must_use]
pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
IterMut::from_delegate(self.pairs.iter_mut())
}
}
impl<K, V> IntoIterator for AList<K, V> {
type Item = (K, V);
type IntoIter = IntoIter<K, V>;
fn into_iter(self) -> Self::IntoIter {
IntoIter::from_delegate(self.pairs.into_iter())
}
}
impl<'a, K, V> IntoIterator for &'a AList<K, V> {
type Item = (&'a K, &'a V);
type IntoIter = Iter<'a, K, V>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, K, V> IntoIterator for &'a mut AList<K, V> {
type Item = (&'a K, &'a mut V);
type IntoIter = IterMut<'a, K, V>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
impl<K: Clone, V: Clone> Clone for AList<K, V> {
fn clone(&self) -> Self {
Self {
pairs: self.pairs.clone(),
}
}
fn clone_from(&mut self, source: &Self) {
self.pairs.clone_from(&source.pairs)
}
}
impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for AList<K, V> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut map = f.debug_map();
self.pairs.iter().for_each(|(k, v)| {
map.entry(k, v);
});
map.finish()
}
}
impl<K: FastEq, V: PartialEq> PartialEq for AList<K, V> {
fn eq(&self, other: &Self) -> bool {
self.len() == other.len() && self.iter().all(|(k, v)| other.get(k) == Some(v))
}
}
impl<K: FastEq, V: Eq> Eq for AList<K, V> {}
impl<K: Hash, V: Hash> Hash for AList<K, V> {
fn hash<H: Hasher>(&self, state: &mut H) {
let mut sum = 0_u64;
let mut xor = 0_u64;
for pair in &self.pairs {
let hash = hash_one(pair);
sum = sum.wrapping_add(hash);
xor ^= hash.rotate_left(32);
}
state.write_usize(self.len());
state.write_u64(sum);
state.write_u64(xor);
}
}
fn hash_one<T: Hash + ?Sized>(value: &T) -> u64 {
let mut hasher = AListHasher::default();
value.hash(&mut hasher);
hasher.finish()
}
struct AListHasher(u64);
impl Default for AListHasher {
fn default() -> Self {
Self(0xcbf2_9ce4_8422_2325)
}
}
impl Hasher for AListHasher {
fn finish(&self) -> u64 {
self.0
}
fn write(&mut self, bytes: &[u8]) {
for byte in bytes {
self.0 ^= u64::from(*byte);
self.0 = self.0.wrapping_mul(0x0000_0100_0000_01b3);
}
}
}
#[cfg(test)]
mod tests {
use alloc::{format, vec, vec::Vec};
use crate::{AList, alist};
#[test]
fn hash_is_order_independent_for_equal_lists() {
let l = alist! {
'x' => 1,
'y' => 2,
'z' => 3,
};
let r = alist! {
'z' => 3,
'y' => 2,
'x' => 1,
};
assert_eq!(l, r);
assert_eq!(super::hash_one(&l), super::hash_one(&r));
}
#[test]
fn hash_includes_keys() {
let l = alist! { 'a' => 1 };
let r = alist! { 'b' => 1 };
assert_ne!(super::hash_one(&l), super::hash_one(&r));
}
#[test]
fn constructors_create_empty_lists_with_expected_capacity() {
let new: AList<char, i32> = AList::new();
let default: AList<char, i32> = AList::default();
let with_capacity: AList<char, i32> = AList::with_capacity(8);
assert!(new.is_empty());
assert!(default.is_empty());
assert!(with_capacity.is_empty());
assert!(with_capacity.capacity() >= 8);
}
#[test]
fn insert_adds_new_keys_and_replaces_existing_values() {
let mut sut = AList::new();
assert_eq!(sut.insert('a', 1), None);
assert_eq!(sut.insert('b', 2), None);
assert_eq!(sut.insert('a', 3), Some(1));
let pairs: Vec<_> = sut.iter().collect();
assert_eq!(pairs, vec![(&'a', &3), (&'b', &2)]);
}
#[test]
fn from_iter_and_extend_keep_first_key_position_for_duplicates() {
let mut sut = [('a', 1), ('b', 2), ('a', 3)]
.into_iter()
.collect::<AList<_, _>>();
sut.extend([('c', 4), ('b', 5)]);
let pairs: Vec<_> = sut.iter().collect();
assert_eq!(pairs, vec![(&'a', &3), (&'b', &5), (&'c', &4)]);
}
#[test]
fn key_based_operations_target_last_matching_internal_pair() {
let mut sut = AList {
pairs: vec![('a', 1), ('b', 2), ('a', 3)],
};
assert_eq!(sut.position(&'a'), Some(2));
assert_eq!(sut.get(&'a'), Some(&3));
assert_eq!(sut.get_key_value(&'a'), Some((&'a', &3)));
assert_eq!(sut.insert('a', 4), Some(3));
assert_eq!(sut.get_mut(&'a').map(|value| *value), Some(4));
*sut.get_key_value_mut(&'a').unwrap().1 = 5;
sut.extend([('a', 6)]);
assert_eq!(sut.remove(&'a'), Some(6));
let pairs: Vec<_> = sut.iter().collect();
assert_eq!(pairs, vec![(&'a', &1), (&'b', &2)]);
}
#[test]
fn refresh_position_searches_before_previous_position_then_after_it() {
let sut = AList {
pairs: vec![('a', 1), ('b', 2), ('c', 3), ('d', 4)],
};
assert_eq!(sut.refresh_position(&'b', 3), Some(1));
assert_eq!(sut.refresh_position(&'d', 0), Some(3));
assert_eq!(sut.refresh_position(&'c', usize::MAX), Some(2));
assert_eq!(sut.refresh_position(&'x', 2), None);
}
#[test]
fn extend_from_references_clones_keys_and_values() {
let source = [('a', 1), ('b', 2)];
let mut sut = AList::new();
sut.extend(source.iter().map(|(key, value)| (key, value)));
assert_eq!(sut.get(&'a'), Some(&1));
assert_eq!(sut.get(&'b'), Some(&2));
}
#[test]
fn retain_filters_pairs_without_reordering_survivors() {
let mut sut = alist! {
'a' => 1,
'b' => 2,
'c' => 3,
'd' => 4,
};
sut.retain(|_, value| value % 2 == 0);
let pairs: Vec<_> = sut.iter().collect();
assert_eq!(pairs, vec![(&'b', &2), (&'d', &4)]);
}
#[test]
fn retain_mut_can_modify_surviving_values() {
let mut sut = alist! {
'a' => 1,
'b' => 2,
'c' => 3,
};
sut.retain_mut(|_, value| {
if *value % 2 == 1 {
*value *= 10;
true
} else {
false
}
});
let pairs: Vec<_> = sut.iter().collect();
assert_eq!(pairs, vec![(&'a', &10), (&'c', &30)]);
}
#[test]
fn reserve_and_shrink_manage_capacity_without_changing_items() {
let mut sut = alist! { 'a' => 1, 'b' => 2 };
sut.reserve(16);
assert!(sut.capacity() >= 18);
sut.shrink_to(4);
assert!(sut.capacity() >= 4);
assert_eq!(sut.len(), 2);
assert_eq!(sut.get(&'a'), Some(&1));
assert_eq!(sut.get(&'b'), Some(&2));
sut.shrink_to_fit();
assert!(sut.capacity() >= sut.len());
}
#[test]
fn reserve_exact_handles_zero_and_existing_capacity() {
let mut sut: AList<char, i32> = AList::with_capacity(4);
let capacity = sut.capacity();
sut.reserve_exact(0);
sut.reserve_exact(2);
assert_eq!(sut.capacity(), capacity);
}
#[test]
fn clear_removes_items_but_keeps_capacity_available() {
let mut sut = AList::with_capacity(8);
sut.insert('a', 1);
sut.insert('b', 2);
let capacity = sut.capacity();
sut.clear();
assert!(sut.is_empty());
assert_eq!(sut.len(), 0);
assert!(sut.capacity() >= capacity);
}
#[test]
fn clone_is_independent_from_source_after_clone() {
let mut sut = alist! { 'a' => 1, 'b' => 2 };
let clone = sut.clone();
sut.insert('c', 3);
assert_eq!(clone.get(&'a'), Some(&1));
assert_eq!(clone.get(&'b'), Some(&2));
assert_eq!(clone.get(&'c'), None);
}
#[test]
fn equality_is_order_independent_but_checks_keys_values_and_length() {
let l = alist! { 'a' => 1, 'b' => 2 };
let same_different_order = alist! { 'b' => 2, 'a' => 1 };
let different_value = alist! { 'a' => 1, 'b' => 3 };
let different_key = alist! { 'a' => 1, 'c' => 2 };
let different_len = alist! { 'a' => 1 };
assert_eq!(l, same_different_order);
assert_ne!(l, different_value);
assert_ne!(l, different_key);
assert_ne!(l, different_len);
}
#[test]
fn debug_uses_current_insertion_order() {
let mut sut = alist! {
'b' => 2,
'a' => 1,
'c' => 3,
};
assert!(sut.remove(&'a').is_some());
assert_eq!(format!("{sut:?}"), r#"{'b': 2, 'c': 3}"#);
}
}