#[cfg(test)]
mod test;
use crate::{
basic::{
mapx_ord::{Entry, MapxOrdValues, MapxOrdValuesMut},
mapx_ord_rawkey::{
self, MapxOrdRawKey, MapxOrdRawKeyBatch, MapxOrdRawKeyIter,
MapxOrdRawKeyIterMut, ValueMut,
},
},
common::{
RawBytes,
ende::{KeyEnDe, KeyRef, ValueEnDe},
error::Result,
macros::define_map_wrapper,
},
};
use std::{
borrow::Borrow,
marker::PhantomData,
ops::{Deref, DerefMut},
};
define_map_wrapper! {
#[doc = "A disk-based, `HashMap`-like data structure with typed keys and values."]
#[doc = ""]
#[doc = "`Mapx` stores key-value pairs on disk, encoding both keys and values"]
#[doc = "for type safety and persistence."]
#[doc = ""]
#[doc = "# Key determinism"]
#[doc = ""]
#[doc = "`K` must encode deterministically. Do not use `HashMap`, `HashSet`,"]
#[doc = "or wrappers containing them as keys; their randomized iteration order"]
#[doc = "can produce different storage bytes for logically equal keys."]
pub struct Mapx<K, V> {
inner: MapxOrdRawKey<V>,
_p: PhantomData<K>,
}
where K: KeyEnDe, V: ValueEnDe
}
impl<K, V> Mapx<K, V>
where
K: KeyEnDe,
V: ValueEnDe,
{
#[inline(always)]
pub fn get<Q>(&self, key: &Q) -> Option<V>
where
K: Borrow<Q>,
Q: KeyRef + ?Sized,
{
self.inner.get(Self::query_bytes(key)?)
}
#[inline(always)]
pub fn get_mut<Q>(&mut self, key: &Q) -> Option<ValueMut<'_, V>>
where
K: Borrow<Q>,
Q: KeyRef + ?Sized,
{
self.inner.get_mut(Self::query_bytes(key)?)
}
#[inline(always)]
pub fn contains_key<Q>(&self, key: &Q) -> bool
where
K: Borrow<Q>,
Q: KeyRef + ?Sized,
{
Self::query_bytes(key).is_some_and(|bytes| self.inner.contains_key(bytes))
}
#[inline(always)]
pub fn insert(&mut self, key: &K, value: &V) {
self.inner.insert(key.encode(), value)
}
#[inline(always)]
pub fn entry(&mut self, key: &K) -> Entry<'_, V> {
Entry {
key: key.encode(),
hdr: &mut self.inner,
}
}
#[inline(always)]
pub fn iter(&self) -> MapxIter<'_, K, V> {
MapxIter {
iter: self.inner.iter(),
_p: PhantomData,
}
}
#[inline(always)]
pub fn iter_mut(&mut self) -> MapxIterMut<'_, K, V> {
MapxIterMut {
inner: self.inner.iter_mut(),
_p: PhantomData,
}
}
#[inline(always)]
pub fn values(&self) -> MapxValues<'_, V> {
MapxValues {
inner: self.inner.iter(),
}
}
#[inline(always)]
pub fn values_mut(&mut self) -> MapxValuesMut<'_, V> {
MapxValuesMut {
inner: self.inner.iter_mut(),
_p: PhantomData,
}
}
#[inline(always)]
pub fn remove<Q>(&mut self, key: &Q)
where
K: Borrow<Q>,
Q: KeyRef + ?Sized,
{
if let Some(bytes) = Self::query_bytes(key) {
self.inner.remove(bytes);
}
}
fn query_bytes<Q>(key: &Q) -> Option<RawBytes>
where
K: Borrow<Q>,
Q: KeyRef + ?Sized,
{
let Some(slice) = key.as_byte_slice() else {
return Some(key.key_bytes());
};
let matches = |owned: &K| owned.borrow().as_byte_slice() == Some(slice);
if let Ok(owned) = K::decode(slice)
&& matches(&owned)
{
return Some(owned.encode());
}
let owned = K::decode(&key.key_bytes()).ok()?;
matches(&owned).then(|| owned.encode())
}
#[inline(always)]
pub fn batch(&mut self) -> MapxBatch<'_, K, V> {
MapxBatch {
inner: self.inner.batch(),
_marker: PhantomData,
}
}
#[inline(always)]
pub fn keys(&self) -> impl DoubleEndedIterator<Item = K> + '_ {
self.inner.keys().map(|k| K::decode(&k).unwrap())
}
}
impl<'a, K, V> IntoIterator for &'a Mapx<K, V>
where
K: KeyEnDe,
V: ValueEnDe,
{
type Item = (K, V);
type IntoIter = MapxIter<'a, K, V>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<K, V> PartialEq for Mapx<K, V>
where
K: KeyEnDe,
V: ValueEnDe + PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.inner.iter().eq(other.inner.iter())
}
}
impl<K, V> Eq for Mapx<K, V>
where
K: KeyEnDe,
V: ValueEnDe + Eq,
{
}
impl<'a, K, V> IntoIterator for &'a mut Mapx<K, V>
where
K: KeyEnDe,
V: ValueEnDe,
{
type Item = (K, ValueIterMut<'a, V>);
type IntoIter = MapxIterMut<'a, K, V>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
pub struct MapxBatch<'a, K, V>
where
K: KeyEnDe,
V: ValueEnDe,
{
inner: MapxOrdRawKeyBatch<'a, V>,
_marker: PhantomData<K>,
}
impl<'a, K, V> MapxBatch<'a, K, V>
where
K: KeyEnDe,
V: ValueEnDe,
{
pub fn insert(&mut self, key: &K, value: &V) {
self.inner.insert(key.encode(), value);
}
pub fn remove(&mut self, key: &K) {
self.inner.remove(key.encode());
}
pub fn commit(self) -> Result<()> {
self.inner.commit()
}
pub fn commit_sync(self) -> Result<()> {
self.inner.commit_sync()
}
}
pub struct MapxIter<'a, K, V>
where
K: KeyEnDe,
V: ValueEnDe,
{
iter: MapxOrdRawKeyIter<'a, V>,
_p: PhantomData<K>,
}
impl<K, V> Iterator for MapxIter<'_, K, V>
where
K: KeyEnDe,
V: ValueEnDe,
{
type Item = (K, V);
fn next(&mut self) -> Option<Self::Item> {
self.iter
.next()
.map(|(k, v)| (<K as KeyEnDe>::decode(&k).unwrap(), v))
}
}
impl<K, V> DoubleEndedIterator for MapxIter<'_, K, V>
where
K: KeyEnDe,
V: ValueEnDe,
{
fn next_back(&mut self) -> Option<Self::Item> {
self.iter
.next_back()
.map(|(k, v)| (<K as KeyEnDe>::decode(&k).unwrap(), v))
}
}
pub struct MapxIterMut<'a, K, V>
where
K: KeyEnDe,
V: ValueEnDe,
{
inner: MapxOrdRawKeyIterMut<'a, V>,
_p: PhantomData<K>,
}
impl<'a, K, V> Iterator for MapxIterMut<'a, K, V>
where
K: KeyEnDe,
V: ValueEnDe,
{
type Item = (K, ValueIterMut<'a, V>);
fn next(&mut self) -> Option<Self::Item> {
self.inner.next().map(|(k, v)| {
(
<K as KeyEnDe>::decode(&k).unwrap(),
ValueIterMut { inner: v },
)
})
}
}
impl<K, V> DoubleEndedIterator for MapxIterMut<'_, K, V>
where
K: KeyEnDe,
V: ValueEnDe,
{
fn next_back(&mut self) -> Option<Self::Item> {
self.inner.next_back().map(|(k, v)| {
(
<K as KeyEnDe>::decode(&k).unwrap(),
ValueIterMut { inner: v },
)
})
}
}
type MapxValues<'a, V> = MapxOrdValues<'a, V>;
type MapxValuesMut<'a, V> = MapxOrdValuesMut<'a, V>;
#[derive(Debug)]
pub struct ValueIterMut<'a, V>
where
V: ValueEnDe,
{
pub(crate) inner: mapx_ord_rawkey::ValueIterMut<'a, V>,
}
impl<V> Deref for ValueIterMut<'_, V>
where
V: ValueEnDe,
{
type Target = V;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<V> DerefMut for ValueIterMut<'_, V>
where
V: ValueEnDe,
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}