use super::{Memtable, PhantomRangeDeletionSpan, PhantomRangeKey, PhantomRangeUpdateSpan};
use core::{
cmp::Ordering,
ops::{Bound, ControlFlow},
};
use either::Either;
use skl::generic::{
multiple_version::sync::{Entry as MapEntry, VersionedEntry as MapVersionedEntry},
Comparable, KeyRef, Type,
};
pub(super) enum EntryValue<'a, K, V>
where
K: ?Sized + Type,
V: ?Sized + Type,
{
Range(MapEntry<'a, PhantomRangeKey<K>, PhantomRangeUpdateSpan<K, V>>),
Point(V::Ref<'a>),
}
impl<K, V> Clone for EntryValue<'_, K, V>
where
K: ?Sized + Type,
V: ?Sized + Type,
{
#[inline]
fn clone(&self) -> Self {
match self {
Self::Range(ent) => Self::Range(ent.clone()),
Self::Point(ent) => Self::Point(*ent),
}
}
}
impl<'a, K, V> EntryValue<'a, K, V>
where
K: ?Sized + Type,
V: ?Sized + Type,
{
#[inline]
fn value(&self) -> &V::Ref<'a> {
match self {
Self::Range(ent) => ent.value().value(),
Self::Point(ent) => ent,
}
}
}
pub struct Entry<'a, K, V>
where
K: ?Sized + Type,
V: ?Sized + Type,
{
table: &'a Memtable<K, V>,
key: MapEntry<'a, K, V>,
value: EntryValue<'a, K, V>,
version: u64,
query_version: u64,
}
impl<K, V> core::fmt::Debug for Entry<'_, K, V>
where
K: core::fmt::Debug + Type + ?Sized,
V: core::fmt::Debug + Type + ?Sized,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Entry")
.field("key", self.key())
.field("value", self.value())
.field("version", &self.version)
.finish()
}
}
impl<K, V> Clone for Entry<'_, K, V>
where
K: ?Sized + Type,
V: ?Sized + Type,
{
#[inline]
fn clone(&self) -> Self {
Self {
table: self.table,
key: self.key.clone(),
value: self.value.clone(),
version: self.version,
query_version: self.query_version,
}
}
}
impl<'a, K, V> Entry<'a, K, V>
where
K: ?Sized + Type,
V: ?Sized + Type,
{
#[inline]
pub(super) fn new(
table: &'a Memtable<K, V>,
query_version: u64,
key: MapEntry<'a, K, V>,
value: EntryValue<'a, K, V>,
) -> Self {
Self {
table,
version: key.version(),
key,
value,
query_version,
}
}
#[inline]
pub fn key(&self) -> &K::Ref<'a> {
self.key.key()
}
#[inline]
pub fn value(&self) -> &V::Ref<'a> {
self.value.value()
}
#[inline]
pub const fn version(&self) -> u64 {
self.version
}
}
impl<K, V> Entry<'_, K, V>
where
K: ?Sized + Type + 'static,
for<'a> K::Ref<'a>: KeyRef<'a, K>,
V: ?Sized + Type + 'static,
{
#[inline]
pub fn next(&self) -> Option<Self> {
let mut next = self.key.next();
while let Some(ent) = next {
match self.table.validate(self.query_version, ent) {
ControlFlow::Break(entry) => return entry,
ControlFlow::Continue(ent) => next = ent.next(),
}
}
None
}
#[inline]
pub fn prev(&self) -> Option<Self> {
let mut prev = self.key.prev();
while let Some(ent) = prev {
match self.table.validate(self.query_version, ent) {
ControlFlow::Break(entry) => return entry,
ControlFlow::Continue(ent) => prev = ent.prev(),
}
}
None
}
}
macro_rules! bulk_entry {
($(
$(#[$meta:meta])*
$name:ident($span:ty)($ent:ident, $versioned_ent:ident) $( => $value:ident)?
),+$(,)?) => {
$(
$(#[$meta])*
pub struct $name<'a, K, V>
where
K: ?Sized + Type,
V: ?Sized + Type,
{
table: &'a Memtable<K, V>,
ent: Either<$ent<'a, PhantomRangeKey<K>, $span>, $versioned_ent<'a, PhantomRangeKey<K>, $span>>,
version: u64,
query_version: u64,
}
impl<K, V> core::fmt::Debug for $name<'_, K, V>
where
K: core::fmt::Debug + Type + ?Sized,
V: core::fmt::Debug + Type + ?Sized,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct(stringify!($name))
.field("version", &self.version())
.field("start_bound", &self.start_bound())
.field("end_bound", &self.end_bound())
$(.field("value", self.$value()))?
.finish()
}
}
impl<K, V> Clone for $name<'_, K, V>
where
K: ?Sized + Type,
V: ?Sized + Type,
{
#[inline]
fn clone(&self) -> Self {
Self {
table: self.table,
ent: self.ent.clone(),
version: self.version,
query_version: self.query_version,
}
}
}
impl<'a, K, V> $name<'a, K, V>
where
K: ?Sized + Type,
V: ?Sized + Type,
{
#[inline]
pub(super) fn new(
table: &'a Memtable<K, V>,
query_version: u64,
ent: $ent<'a, PhantomRangeKey<K>, $span>,
) -> Self {
Self {
version: ent.version(),
table,
ent: Either::Left(ent),
query_version,
}
}
#[inline]
pub(super) fn versioned(
table: &'a Memtable<K, V>,
query_version: u64,
ent: $versioned_ent<'a, PhantomRangeKey<K>, $span>,
) -> Self {
Self {
version: ent.version(),
table,
ent: Either::Right(ent),
query_version,
}
}
#[inline]
pub fn contains<Q>(&self, key: &Q) -> bool
where
Q: ?Sized + Comparable<K::Ref<'a>>,
{
(match self.start_bound() {
Bound::Included(start) => key.compare(start) != Ordering::Less,
Bound::Excluded(start) => key.compare(start) == Ordering::Greater,
Bound::Unbounded => true,
}) && (match self.end_bound() {
Bound::Included(end) => key.compare(end) != Ordering::Greater,
Bound::Excluded(end) => key.compare(end) == Ordering::Less,
Bound::Unbounded => true,
})
}
#[inline]
pub fn bounds(&self) -> (Bound<&K::Ref<'a>>, Bound<&K::Ref<'a>>) {
(self.start_bound(), self.end_bound())
}
#[inline]
pub fn start_bound(&self) -> Bound<&K::Ref<'a>> {
let k = match &self.ent {
Either::Left(ent) => ent.key(),
Either::Right(ent) => ent.key(),
};
k.bound()
}
#[inline]
pub fn end_bound(&self) -> Bound<&K::Ref<'a>> {
match &self.ent {
Either::Left(ent) => ent.value().bound(),
Either::Right(ent) => ent.value().unwrap().bound(),
}
}
#[inline]
pub const fn version(&self) -> u64 {
self.version
}
#[inline]
pub fn next(&self) -> Option<Self>
where
for<'b> K::Ref<'b>: KeyRef<'b, K>,
{
match &self.ent {
Either::Left(ent) => {
ent.next().map(|ent| $name::new(self.table, self.query_version, ent))
},
Either::Right(ent) => {
ent.next().map(|ent| $name::versioned(self.table, self.query_version, ent))
},
}
}
#[inline]
pub fn prev(&self) -> Option<Self>
where
for<'b> K::Ref<'b>: KeyRef<'b, K>,
{
match &self.ent {
Either::Left(ent) => {
ent.prev().map(|ent| $name::new(self.table, self.query_version, ent))
},
Either::Right(ent) => {
ent.prev().map(|ent| $name::versioned(self.table, self.query_version, ent))
},
}
}
$(
#[inline]
pub fn $value(&self) -> &V::Ref<'a> {
match &self.ent {
Either::Left(ent) => ent.value().value(),
Either::Right(ent) => ent.value().unwrap().value(),
}
}
)?
}
impl<'a, K, V> core::ops::RangeBounds<K::Ref<'a>> for $name<'a, K, V>
where
K: ?Sized + Type,
V: ?Sized + Type,
{
#[inline]
fn start_bound(&self) -> Bound<&K::Ref<'a>> {
self.start_bound()
}
#[inline]
fn end_bound(&self) -> Bound<&K::Ref<'a>> {
self.end_bound()
}
}
)*
};
}
bulk_entry!(
BulkDeletionEntry(PhantomRangeDeletionSpan<K>)(MapEntry, MapVersionedEntry),
);
bulk_entry!(
BulkUpdateEntry(PhantomRangeUpdateSpan<K, V>)(MapEntry, MapVersionedEntry) => value,
);