#[cfg(any(test, feature = "std"))]
extern crate std;
extern crate alloc;
use alloc::{borrow::ToOwned, vec::Vec};
use core::{
borrow::Borrow,
fmt,
ops::{Deref, DerefMut},
};
mod iter;
pub use iter::{Drain, IntoIter, Iter, IterMut};
use crate::shared::{PrefixBorrowed, PrefixOwned, ScratchSpace};
#[derive(PartialEq, Eq)]
pub struct PrefixArray<K: Borrow<str>, V>(pub(crate) Vec<(K, V)>);
impl<K: Borrow<str> + fmt::Debug, V: fmt::Debug> fmt::Debug for PrefixArray<K, V> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "PrefixArray")?;
f.debug_map().entries(self.iter()).finish()
}
}
impl<K: Borrow<str> + Clone, V: Clone> Clone for PrefixArray<K, V> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
fn clone_from(&mut self, other: &Self) {
self.0.clone_from(&other.0);
}
}
impl<K: Borrow<str>, V> Default for PrefixArray<K, V> {
fn default() -> Self {
PrefixArray::new()
}
}
impl<K: Borrow<str>, V> PrefixArray<K, V> {
#[must_use]
pub const fn new() -> Self {
Self(Vec::new())
}
#[must_use]
pub fn with_capacity(capacity: usize) -> Self {
Self(Vec::with_capacity(capacity))
}
pub fn reserve(&mut self, additional: usize) {
self.0.reserve(additional);
}
pub fn reserve_exact(&mut self, additional: usize) {
self.0.reserve_exact(additional);
}
#[must_use]
pub fn from_vec_lossy(v: Vec<(K, V)>) -> Self {
Self::from_vec_lossy_impl(v)
}
pub fn insert(&mut self, key: K, value: V) -> Option<V> {
self.insert_impl((key, value))
}
pub fn drain_all_with_prefix<'a>(&'a mut self, prefix: &str) -> Drain<'a, K, V> {
let range = self.find_all_with_prefix_idx(prefix);
Drain(self.0.drain(range))
}
pub fn drain(&mut self) -> Drain<'_, K, V> {
Drain(self.0.drain(..))
}
pub fn remove(&mut self, key: &str) -> Option<V> {
self.remove_entry(key).map(|(_, v)| v)
}
pub fn remove_entry(&mut self, key: &str) -> Option<(K, V)> {
self.remove_entry_impl(key)
}
#[must_use]
pub fn capacity(&self) -> usize {
self.0.capacity()
}
pub fn clear(&mut self) {
self.0.clear();
}
pub fn shrink_to_fit(&mut self) {
self.0.shrink_to_fit();
}
pub fn shrink_to(&mut self, min_capacity: usize) {
self.0.shrink_to(min_capacity);
}
pub(crate) fn extend_with_raw<I>(&mut self, insert: &mut Vec<(usize, (K, V))>, iter: I)
where
I: IntoIterator<Item = (K, V)>,
{
self.extend_with_impl(insert, iter);
}
pub fn extend_with<I>(&mut self, scratch: &mut ScratchSpace<Self>, iter: I)
where
I: IntoIterator<Item = (K, V)>,
{
self.extend_with_raw(&mut scratch.0, iter);
}
pub(crate) fn from_unique_iter<T: IntoIterator<Item = (K, V)>>(v: T) -> Self {
Self::from_unique_iter_impl(v)
}
}
impl<K: Borrow<str>, V> Extend<(K, V)> for PrefixArray<K, V> {
fn extend<T>(&mut self, iter: T)
where
T: IntoIterator<Item = (K, V)>,
{
self.extend_with(&mut ScratchSpace::new(), iter);
}
}
#[cfg(feature = "std")]
impl<K: Borrow<str>, V, H> From<std::collections::HashMap<K, V, H>> for PrefixArray<K, V> {
fn from(v: std::collections::HashMap<K, V, H>) -> Self {
Self::from_unique_iter(v)
}
}
impl<K: Borrow<str>, V> From<alloc::collections::BTreeMap<K, V>> for PrefixArray<K, V> {
fn from(v: alloc::collections::BTreeMap<K, V>) -> Self {
Self::from_unique_iter(v)
}
}
impl<K: Borrow<str>, V> From<PrefixArray<K, V>> for Vec<(K, V)> {
fn from(v: PrefixArray<K, V>) -> Vec<(K, V)> {
v.0
}
}
impl<K: Borrow<str>, V> Deref for PrefixArray<K, V> {
type Target = SubSlice<K, V>;
fn deref(&self) -> &Self::Target {
SubSlice::cast_from_slice(self.0.as_slice())
}
}
impl<K: Borrow<str>, V> DerefMut for PrefixArray<K, V> {
fn deref_mut(&mut self) -> &mut Self::Target {
SubSlice::cast_from_slice_mut(self.0.as_mut_slice())
}
}
impl<K: Borrow<str>, V> core::borrow::Borrow<SubSlice<K, V>> for PrefixArray<K, V> {
fn borrow(&self) -> &SubSlice<K, V> {
self
}
}
impl<K: Borrow<str>, V> core::borrow::BorrowMut<SubSlice<K, V>> for PrefixArray<K, V> {
fn borrow_mut(&mut self) -> &mut SubSlice<K, V> {
self
}
}
impl<K: Borrow<str> + Clone, V: Clone> ToOwned for SubSlice<K, V> {
type Owned = PrefixArray<K, V>;
fn to_owned(&self) -> PrefixArray<K, V> {
PrefixArray(self.to_vec())
}
fn clone_into(&self, target: &mut PrefixArray<K, V>) {
self.0.clone_into(&mut target.0);
}
}
impl<K: Borrow<str> + fmt::Debug, V: fmt::Debug> fmt::Debug for SubSlice<K, V> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "SubSlice")?;
f.debug_map().entries(self.iter()).finish()
}
}
#[repr(transparent)]
#[derive(PartialEq, Eq)]
pub struct SubSlice<K: Borrow<str>, V>(pub(crate) [(K, V)]);
#[derive(Debug)]
pub struct DuplicatesPresent<'a>(&'a str);
#[cfg(feature = "std")]
impl std::error::Error for DuplicatesPresent<'_> {}
impl fmt::Display for DuplicatesPresent<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"duplicate key found while attempting conversion to SubSlice: {}",
self.0
)
}
}
impl<K: Borrow<str>, V> SubSlice<K, V> {
pub(crate) const fn cast_from_slice_core(v: &[(K, V)]) -> &Self {
unsafe { &*(v as *const [(K, V)] as *const Self) }
}
pub(crate) fn cast_from_slice_mut_core(v: &mut [(K, V)]) -> &mut Self {
unsafe { &mut *(v as *mut [(K, V)] as *mut Self) }
}
const fn as_slice(&self) -> &[(K, V)] {
&self.0
}
pub fn from_mut_slice(data: &mut [(K, V)]) -> Result<&mut Self, DuplicatesPresent<'_>> {
Self::from_mut_slice_impl(data).map_err(|e| DuplicatesPresent(e.0))
}
pub fn iter(&self) -> Iter<'_, K, V> {
Iter(self.as_slice().iter())
}
pub fn to_vec(&self) -> Vec<(K, V)>
where
K: Clone,
V: Clone,
{
self.as_slice().to_vec()
}
fn find_all_with_prefix_idx(&self, prefix: &str) -> core::ops::Range<usize> {
self.find_all_with_prefix_idx_impl(prefix)
}
pub fn find_all_with_prefix<'a>(&'a self, prefix: &str) -> &'a Self {
let range = self.find_all_with_prefix_idx(prefix);
self.reslice(range)
}
pub fn find_all_with_prefix_mut<'a>(&'a mut self, prefix: &str) -> &'a mut Self {
let range = self.find_all_with_prefix_idx(prefix);
self.reslice_mut(range)
}
pub fn common_prefix(&self) -> &str {
self.common_prefix_impl()
}
pub fn contains_key(&self, key: &str) -> bool {
self.contains_key_impl(key)
}
pub fn get(&self, key: &str) -> Option<&V> {
self.get_impl(key).map(|(_k, v)| v)
}
pub fn get_mut(&mut self, key: &str) -> Option<&mut V> {
self.get_mut_impl(key).map(|(_k, v)| v)
}
pub fn get_key_value(&self, key: &str) -> Option<(&K, &V)> {
self.get_impl(key).map(|(k, v)| (k, v))
}
pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
IterMut(self.0.iter_mut())
}
pub const fn is_empty(&self) -> bool {
self.as_slice().is_empty()
}
pub const fn len(&self) -> usize {
self.as_slice().len()
}
#[cfg(test)]
fn assert_invariants(&self) {
let mut last = None::<&K>;
for (k, _) in self.as_slice() {
if let Some(prev) = last {
assert!(prev.borrow() < k.borrow());
}
last = Some(k);
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn mutate() {
let mut v = PrefixArray::from_iter([("among", 4i32), ("foo", 6)]);
*v.get_mut("among").unwrap() = 24;
assert_eq!(v.common_prefix(), "");
assert_eq!(Some(&24), v.get("among"));
assert_eq!(v.remove_entry("among"), Some(("among", 24)));
assert_eq!(v.len(), 1);
v.extend([("amongus", 324), ("asdfsaf", 234)]);
assert_eq!(v.len(), 3);
assert_eq!(v.find_all_with_prefix("a").common_prefix(), "a");
v.extend([("0", 324), ("01", 234)]);
assert_eq!(v.len(), 5);
v.assert_invariants();
v.extend(Some(("0", 12)));
assert_eq!(v.get("0"), Some(&12));
}
#[test]
fn weird_lifetimes() {
let v = PrefixArray::from_iter([("we".to_owned(), 1), ("woo".into(), 2)]);
let res: &i32;
{
let s = "we".to_owned();
res = v.get(&s).unwrap();
drop(s);
}
assert_eq!(res, &1);
}
#[test]
fn extend() {
let mut v = PrefixArray::new();
v.extend([("a", 0), ("a", 1)]);
assert_eq!(v.len(), 1);
}
#[test]
fn extend_with() {
let mut v = PrefixArray::from_iter([("a", 0), ("b", 2)]);
let mut scratch = ScratchSpace::with_capacity(2);
v.extend_with(&mut scratch, [("c", 4), ("d", 4)]);
assert_eq!(v.len(), 4);
assert!(scratch.0.is_empty());
assert_eq!(scratch.0.capacity(), 2);
}
#[test]
fn insert_wont_update_key() {
#[derive(Debug)]
struct TrackerStr<'a>(&'a str, u64);
impl core::borrow::Borrow<str> for TrackerStr<'_> {
fn borrow(&self) -> &str {
self.0
}
}
let mut arr = PrefixArray::<TrackerStr<'static>, u8>::new();
arr.insert(TrackerStr("abc", 0), 0);
assert_eq!(arr.get("abc"), Some(&0));
arr.insert(TrackerStr("abc", 1), 1);
assert!(matches!(
arr.get_key_value("abc"),
Some((TrackerStr("abc", 0), 1))
));
}
}