use super::*;
use crate::ule::{AsULE, EncodeAsVarULE, UleError, VarULE};
use crate::{VarZeroVec, ZeroSlice, ZeroVec};
use alloc::boxed::Box;
use core::borrow::Borrow;
use core::cmp::Ordering;
use core::fmt;
use core::iter::FromIterator;
pub struct ZeroMap<'a, K, V>
where
K: ZeroMapKV<'a> + ?Sized,
V: ZeroMapKV<'a> + ?Sized,
{
pub(crate) keys: K::Container,
pub(crate) values: V::Container,
}
impl<'a, K, V> Default for ZeroMap<'a, K, V>
where
K: ZeroMapKV<'a> + ?Sized,
V: ZeroMapKV<'a> + ?Sized,
{
fn default() -> Self {
Self::new()
}
}
impl<'a, K, V> ZeroMap<'a, K, V>
where
K: ZeroMapKV<'a> + ?Sized,
V: ZeroMapKV<'a> + ?Sized,
{
pub fn new() -> Self {
Self {
keys: K::Container::zvl_with_capacity(0),
values: V::Container::zvl_with_capacity(0),
}
}
#[doc(hidden)] pub const unsafe fn from_parts_unchecked(keys: K::Container, values: V::Container) -> Self {
Self { keys, values }
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
keys: K::Container::zvl_with_capacity(capacity),
values: V::Container::zvl_with_capacity(capacity),
}
}
pub fn as_borrowed(&'a self) -> ZeroMapBorrowed<'a, K, V> {
ZeroMapBorrowed {
keys: self.keys.zvl_as_borrowed(),
values: self.values.zvl_as_borrowed(),
}
}
pub fn len(&self) -> usize {
self.values.zvl_len()
}
pub fn is_empty(&self) -> bool {
self.values.zvl_len() == 0
}
pub fn clear(&mut self) {
self.keys.zvl_clear();
self.values.zvl_clear();
}
pub fn reserve(&mut self, additional: usize) {
self.keys.zvl_reserve(additional);
self.values.zvl_reserve(additional);
}
}
impl<'a, K, V> ZeroMap<'a, K, V>
where
K: ZeroMapKV<'a> + ?Sized + Ord,
V: ZeroMapKV<'a> + ?Sized,
{
pub fn get(&self, key: &K) -> Option<&V::GetType> {
let index = self.keys.zvl_binary_search(key).ok()?;
self.values.zvl_get(index)
}
pub fn get_by(&self, predicate: impl FnMut(&K) -> Ordering) -> Option<&V::GetType> {
let index = self.keys.zvl_binary_search_by(predicate).ok()?;
self.values.zvl_get(index)
}
pub fn contains_key(&self, key: &K) -> bool {
self.keys.zvl_binary_search(key).is_ok()
}
pub fn insert(&mut self, key: &K, value: &V) -> Option<V::OwnedType> {
match self.keys.zvl_binary_search(key) {
Ok(index) => Some(self.values.zvl_replace(index, value)),
Err(index) => {
self.keys.zvl_insert(index, key);
self.values.zvl_insert(index, value);
None
}
}
}
pub fn remove(&mut self, key: &K) -> Option<V::OwnedType> {
let idx = self.keys.zvl_binary_search(key).ok()?;
self.keys.zvl_remove(idx);
Some(self.values.zvl_remove(idx))
}
#[must_use]
pub fn try_append<'b>(&mut self, key: &'b K, value: &'b V) -> Option<(&'b K, &'b V)> {
if self.keys.zvl_len() != 0 {
if let Some(last) = self.keys.zvl_get(self.keys.zvl_len() - 1) {
if K::Container::t_cmp_get(key, last) != Ordering::Greater {
return Some((key, value));
}
}
}
self.keys.zvl_push(key);
self.values.zvl_push(value);
None
}
}
impl<'a, K, V> ZeroMap<'a, K, V>
where
K: ZeroMapKV<'a> + ?Sized,
V: ZeroMapKV<'a> + ?Sized,
{
pub fn iter<'b>(
&'b self,
) -> impl ExactSizeIterator<
Item = (
&'b <K as ZeroMapKV<'a>>::GetType,
&'b <V as ZeroMapKV<'a>>::GetType,
),
> {
(0..self.keys.zvl_len()).map(move |idx| {
(
#[expect(clippy::unwrap_used)] self.keys.zvl_get(idx).unwrap(),
#[expect(clippy::unwrap_used)] self.values.zvl_get(idx).unwrap(),
)
})
}
pub fn iter_keys<'b>(
&'b self,
) -> impl ExactSizeIterator<Item = &'b <K as ZeroMapKV<'a>>::GetType> {
#[expect(clippy::unwrap_used)] (0..self.keys.zvl_len()).map(move |idx| self.keys.zvl_get(idx).unwrap())
}
pub fn iter_values<'b>(
&'b self,
) -> impl ExactSizeIterator<Item = &'b <V as ZeroMapKV<'a>>::GetType> {
#[expect(clippy::unwrap_used)] (0..self.values.zvl_len()).map(move |idx| self.values.zvl_get(idx).unwrap())
}
}
impl<'a, K, V> ZeroMap<'a, K, V>
where
K: AsULE + ZeroMapKV<'a, Container = ZeroVec<'a, K>>,
V: ZeroMapKV<'a> + ?Sized,
{
pub fn cast_zv_k_unchecked<P>(self) -> ZeroMap<'a, P, V>
where
P: AsULE<ULE = K::ULE> + ZeroMapKV<'a, Container = ZeroVec<'a, P>>,
{
ZeroMap {
keys: self.keys.cast(),
values: self.values,
}
}
pub fn try_convert_zv_k_unchecked<P>(self) -> Result<ZeroMap<'a, P, V>, UleError>
where
P: AsULE + ZeroMapKV<'a, Container = ZeroVec<'a, P>>,
{
Ok(ZeroMap {
keys: self.keys.try_into_converted()?,
values: self.values,
})
}
}
impl<'a, K, V> ZeroMap<'a, K, V>
where
K: ZeroMapKV<'a> + ?Sized,
V: AsULE + ZeroMapKV<'a, Container = ZeroVec<'a, V>>,
{
pub fn cast_zv_v_unchecked<P>(self) -> ZeroMap<'a, K, P>
where
P: AsULE<ULE = V::ULE> + ZeroMapKV<'a, Container = ZeroVec<'a, P>>,
{
ZeroMap {
keys: self.keys,
values: self.values.cast(),
}
}
pub fn try_convert_zv_v_unchecked<P>(self) -> Result<ZeroMap<'a, K, P>, UleError>
where
P: AsULE + ZeroMapKV<'a, Container = ZeroVec<'a, P>>,
{
Ok(ZeroMap {
keys: self.keys,
values: self.values.try_into_converted()?,
})
}
}
impl<'a, K, V> ZeroMap<'a, K, V>
where
K: ZeroMapKV<'a> + ?Sized + Ord,
V: ZeroMapKV<'a, Container = VarZeroVec<'a, V>> + ?Sized,
V: VarULE,
{
pub fn insert_var_v<VE: EncodeAsVarULE<V>>(&mut self, key: &K, value: &VE) -> Option<Box<V>> {
match self.keys.zvl_binary_search(key) {
Ok(index) => {
#[expect(clippy::unwrap_used)] let ret = self.values.get(index).unwrap().to_boxed();
self.values.make_mut().replace(index, value);
Some(ret)
}
Err(index) => {
self.keys.zvl_insert(index, key);
self.values.make_mut().insert(index, value);
None
}
}
}
}
impl<'a, K, V> ZeroMap<'a, K, V>
where
K: ZeroMapKV<'a> + ?Sized + Ord,
V: Copy + ZeroMapKV<'a>,
{
#[inline]
pub fn get_copied(&self, key: &K) -> Option<V> {
let index = self.keys.zvl_binary_search(key).ok()?;
self.get_copied_at(index)
}
#[inline]
pub fn get_copied_by(&self, predicate: impl FnMut(&K) -> Ordering) -> Option<V> {
let index = self.keys.zvl_binary_search_by(predicate).ok()?;
self.get_copied_at(index)
}
fn get_copied_at(&self, index: usize) -> Option<V> {
let ule = self.values.zvl_get(index)?;
let mut result = Option::<V>::None;
V::Container::zvl_get_as_t(ule, |v| result.replace(*v));
#[expect(clippy::unwrap_used)] Some(result.unwrap())
}
}
impl<'a, K, V> ZeroMap<'a, K, V>
where
K: ZeroMapKV<'a> + ?Sized,
V: AsULE + ZeroMapKV<'a, Container = ZeroVec<'a, V>>,
{
pub fn iter_copied_values<'b>(
&'b self,
) -> impl Iterator<Item = (&'b <K as ZeroMapKV<'a>>::GetType, V)> {
(0..self.keys.zvl_len()).map(move |idx| {
(
#[expect(clippy::unwrap_used)] self.keys.zvl_get(idx).unwrap(),
#[expect(clippy::unwrap_used)] ZeroSlice::get(&*self.values, idx).unwrap(),
)
})
}
}
impl<'a, K, V> ZeroMap<'a, K, V>
where
K: AsULE + ZeroMapKV<'a, Container = ZeroVec<'a, K>>,
V: AsULE + ZeroMapKV<'a, Container = ZeroVec<'a, V>>,
{
pub fn iter_copied<'b>(&'b self) -> impl Iterator<Item = (K, V)> + 'b {
let keys = &self.keys;
let values = &self.values;
(0..keys.len()).map(move |idx| {
(
#[expect(clippy::unwrap_used)] ZeroSlice::get(&**keys, idx).unwrap(),
#[expect(clippy::unwrap_used)] ZeroSlice::get(&**values, idx).unwrap(),
)
})
}
}
impl<'a, K, V> From<ZeroMapBorrowed<'a, K, V>> for ZeroMap<'a, K, V>
where
K: ZeroMapKV<'a>,
V: ZeroMapKV<'a>,
K: ?Sized,
V: ?Sized,
{
fn from(other: ZeroMapBorrowed<'a, K, V>) -> Self {
Self {
keys: K::Container::zvl_from_borrowed(other.keys),
values: V::Container::zvl_from_borrowed(other.values),
}
}
}
impl<'a, 'b, K, V> PartialEq<ZeroMap<'b, K, V>> for ZeroMap<'a, K, V>
where
K: for<'c> ZeroMapKV<'c> + ?Sized,
V: for<'c> ZeroMapKV<'c> + ?Sized,
<K as ZeroMapKV<'a>>::Container: PartialEq<<K as ZeroMapKV<'b>>::Container>,
<V as ZeroMapKV<'a>>::Container: PartialEq<<V as ZeroMapKV<'b>>::Container>,
{
fn eq(&self, other: &ZeroMap<'b, K, V>) -> bool {
self.keys.eq(&other.keys) && self.values.eq(&other.values)
}
}
impl<'a, K, V> fmt::Debug for ZeroMap<'a, K, V>
where
K: ZeroMapKV<'a> + ?Sized,
V: ZeroMapKV<'a> + ?Sized,
<K as ZeroMapKV<'a>>::Container: fmt::Debug,
<V as ZeroMapKV<'a>>::Container: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.debug_struct("ZeroMap")
.field("keys", &self.keys)
.field("values", &self.values)
.finish()
}
}
impl<'a, K, V> Clone for ZeroMap<'a, K, V>
where
K: ZeroMapKV<'a> + ?Sized,
V: ZeroMapKV<'a> + ?Sized,
<K as ZeroMapKV<'a>>::Container: Clone,
<V as ZeroMapKV<'a>>::Container: Clone,
{
fn clone(&self) -> Self {
Self {
keys: self.keys.clone(),
values: self.values.clone(),
}
}
}
impl<'a, A, B, K, V> FromIterator<(A, B)> for ZeroMap<'a, K, V>
where
A: Borrow<K>,
B: Borrow<V>,
K: ZeroMapKV<'a> + ?Sized + Ord,
V: ZeroMapKV<'a> + ?Sized,
{
fn from_iter<T>(iter: T) -> Self
where
T: IntoIterator<Item = (A, B)>,
{
let iter = iter.into_iter();
let mut map = match iter.size_hint() {
(_, Some(upper)) => Self::with_capacity(upper),
(lower, None) => Self::with_capacity(lower),
};
for (key, value) in iter {
if let Some((key, value)) = map.try_append(key.borrow(), value.borrow()) {
map.insert(key, value);
}
}
map
}
}