use alloc::vec::Vec;
const NONE: u32 = u32::MAX;
pub(crate) struct Paged<'a, const PAGE: usize> {
inner: Inner<'a, PAGE>,
}
enum Inner<'a, const PAGE: usize> {
Owned(Vec<u8>),
Cow {
base: &'a [u8],
base_pages: usize,
grown: Vec<u8>,
over_pool: Vec<u8>,
over_slot: Vec<u32>,
},
}
impl<'a, const PAGE: usize> Paged<'a, PAGE> {
pub(crate) const fn owned_empty() -> Self {
Self {
inner: Inner::Owned(Vec::new()),
}
}
pub(crate) fn owned_from(bytes: Vec<u8>) -> Self {
Self {
inner: Inner::Owned(bytes),
}
}
pub(crate) fn borrowed(base: &'a [u8]) -> Self {
let base_pages = base.len() / PAGE;
Self {
inner: Inner::Cow {
base,
base_pages,
grown: Vec::new(),
over_pool: Vec::new(),
over_slot: alloc::vec![NONE; base_pages],
},
}
}
pub(crate) fn len(&self) -> usize {
match &self.inner {
Inner::Owned(v) => v.len(),
Inner::Cow { base, grown, .. } => base.len() + grown.len(),
}
}
pub(crate) fn page(&self, idx: u32) -> &[u8] {
match &self.inner {
Inner::Owned(v) => {
let start = idx as usize * PAGE;
&v[start..start + PAGE]
}
Inner::Cow {
base,
base_pages,
grown,
over_pool,
over_slot,
} => {
let idx = idx as usize;
if idx >= *base_pages {
let start = (idx - *base_pages) * PAGE;
&grown[start..start + PAGE]
} else if over_slot[idx] != NONE {
let start = over_slot[idx] as usize * PAGE;
&over_pool[start..start + PAGE]
} else {
let start = idx * PAGE;
&base[start..start + PAGE]
}
}
}
}
pub(crate) fn page_mut(&mut self, idx: u32) -> &mut [u8] {
match &mut self.inner {
Inner::Owned(v) => {
let start = idx as usize * PAGE;
&mut v[start..start + PAGE]
}
Inner::Cow {
base,
base_pages,
grown,
over_pool,
over_slot,
} => {
let idx = idx as usize;
if idx >= *base_pages {
let start = (idx - *base_pages) * PAGE;
&mut grown[start..start + PAGE]
} else {
if over_slot[idx] == NONE {
let slot = over_pool.len() / PAGE;
let src = idx * PAGE;
over_pool.extend_from_slice(&base[src..src + PAGE]);
over_slot[idx] = slot as u32;
}
let start = over_slot[idx] as usize * PAGE;
&mut over_pool[start..start + PAGE]
}
}
}
}
pub(crate) fn grown_tail_mut(&mut self) -> &mut Vec<u8> {
match &mut self.inner {
Inner::Owned(v) => v,
Inner::Cow { grown, .. } => grown,
}
}
}