use std::ops::{BitOrAssign, RangeBounds, RangeInclusive, SubAssign};
use bytes::Bytes;
use splinter_rs::{CowSplinter, Cut, PartitionRead, PartitionWrite, Splinter};
use crate::core::{PageCount, PageIdx};
use crate::derive_newtype_proxy;
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct PageSet {
splinter: CowSplinter<Bytes>,
}
impl PageSet {
pub const EMPTY: Self = Self {
splinter: CowSplinter::Owned(Splinter::EMPTY),
};
pub const FULL: Self = Self {
splinter: CowSplinter::Owned(Splinter::FULL),
};
#[inline]
pub fn new(splinter: CowSplinter<Bytes>) -> Self {
assert!(
!splinter.contains(0),
"Invalid PageSet: Splinter contains PageIdx 0"
);
Self { splinter }
}
#[inline]
pub fn from_range(range: RangeInclusive<PageIdx>) -> Self {
Self {
splinter: Splinter::from(range.start().to_u32()..=range.end().to_u32()).into(),
}
}
#[inline]
pub fn cardinality(&self) -> usize {
self.splinter.cardinality()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.splinter.is_empty()
}
#[inline]
pub fn first(&self) -> Option<PageIdx> {
self.splinter
.select(0)
.map(|n| unsafe { PageIdx::new_unchecked(n) })
}
#[inline]
pub fn last(&self) -> Option<PageIdx> {
self.splinter
.last()
.map(|n| unsafe { PageIdx::new_unchecked(n) })
}
#[inline]
pub fn insert(&mut self, pageidx: PageIdx) -> bool {
self.splinter.insert(pageidx.to_u32())
}
#[inline]
pub fn contains(&self, pageidx: PageIdx) -> bool {
self.splinter.contains(pageidx.to_u32())
}
#[inline]
pub fn contains_all<R: RangeBounds<PageIdx>>(&self, pages: &R) -> bool {
let r = (
pages.start_bound().map(|start| start.to_u32()),
pages.end_bound().map(|end| end.to_u32()),
);
self.splinter.contains_all(r)
}
#[inline]
pub fn contains_any<R: RangeBounds<PageIdx>>(&self, pages: &R) -> bool {
let r = (
pages.start_bound().map(|start| start.to_u32()),
pages.end_bound().map(|end| end.to_u32()),
);
self.splinter.contains_any(r)
}
pub fn truncate(&mut self, page_count: PageCount) {
if page_count == PageCount::ZERO {
self.splinter = CowSplinter::Owned(Splinter::EMPTY);
} else if let Some(last_pageidx) = page_count.last_pageidx()
&& last_pageidx != PageIdx::LAST
{
self.remove_page_range(last_pageidx.saturating_next()..);
}
}
pub fn remove_page_range<R: RangeBounds<PageIdx>>(&mut self, pages: R) {
let r = (
pages.start_bound().map(|start| start.to_u32()),
pages.end_bound().map(|end| end.to_u32()),
);
self.splinter.remove_range(r);
}
pub fn cut(&mut self, rhs: &PageSet) -> PageSet {
self.splinter.to_mut().cut(&rhs.splinter).into()
}
pub fn iter(&self) -> impl Iterator<Item = PageIdx> {
self.splinter.iter().map(|v| {
unsafe { PageIdx::new_unchecked(v) }
})
}
pub fn splinter(&self) -> &CowSplinter<Bytes> {
&self.splinter
}
pub fn splinter_mut(&mut self) -> &CowSplinter<Bytes> {
&mut self.splinter
}
}
impl From<Splinter> for PageSet {
#[inline]
fn from(value: Splinter) -> Self {
Self::new(CowSplinter::Owned(value))
}
}
impl From<PageSet> for Splinter {
fn from(value: PageSet) -> Self {
value.splinter.into_owned()
}
}
derive_newtype_proxy!(
newtype (PageSet)
with empty value (PageSet::EMPTY)
with proxy type (Bytes) and encoding (bilrost::encoding::General)
with sample value (PageSet::new(CowSplinter::from_iter(1u32..10)))
into_proxy(&self) {
self.splinter.encode_to_bytes()
}
from_proxy(&mut self, proxy) {
*self = PageSet::new(
CowSplinter::from_bytes(proxy)
.map_err(|_| bilrost::DecodeErrorKind::InvalidValue)?
);
Ok(())
}
);
impl SubAssign<&Self> for PageSet {
fn sub_assign(&mut self, rhs: &Self) {
self.splinter.to_mut().sub_assign(&rhs.splinter);
}
}
impl BitOrAssign<Self> for PageSet {
fn bitor_assign(&mut self, rhs: Self) {
self.splinter.to_mut().bitor_assign(rhs.splinter);
}
}