use std::num::NonZero;
pub use error::Error;
pub use iter::Iter;
use crate::{
base::marker::ThreadBound,
buffer,
buffer::{resident, segments, storage, storage::regions},
};
mod error;
mod iter;
pub mod retain;
#[repr(C)]
#[derive(Debug)]
pub struct Set<'source, 'ranges, S: ?Sized, N = u32> {
source: &'source S,
ranges: &'ranges [(N, N)],
len: usize,
thread: ThreadBound,
}
impl<'source, 'ranges, S: buffer::raw::Source + ?Sized, N: buffer::raw::Length>
Set<'source, 'ranges, S, N>
{
pub(in crate::buffer::hold) fn new(
source: &'source S,
ranges: &'ranges [(N, N)],
len: usize,
) -> Self {
const { assert!(N::MAX <= u32::MAX as usize) };
Self {
source,
ranges,
len,
thread: ThreadBound::NEW,
}
}
fn view(&self, start: N, end: N) -> buffer::View<'source, S> {
let bytes = unsafe {
self.source
.as_ref()
.get_unchecked(start.into_usize()..end.into_usize())
};
buffer::View {
source: self.source,
bytes,
}
}
pub fn try_new(
source: &'source S,
ranges: &'ranges [(N, N)],
expected: usize,
) -> Result<Self, Error<N>> {
const { assert!(N::MAX <= u32::MAX as usize) };
if ranges.len() > u32::MAX as usize {
return Err(Error::Count {
actual: ranges.len(),
});
}
let len = source.as_ref().len();
let mut actual = 0usize;
for (index, &(start, end)) in ranges.iter().enumerate() {
let index = index as u32;
let first = start.into_usize();
let last = end.into_usize();
if first >= last {
return Err(Error::Order { index, start, end });
}
if last > len {
return Err(Error::Bounds {
index,
start,
end,
len,
});
}
actual = actual.wrapping_add(last - first);
}
if actual != expected {
return Err(Error::Length { expected, actual });
}
Ok(Self::new(source, ranges, actual))
}
pub fn get(&self, index: usize) -> Option<buffer::View<'source, S>> {
let &(start, end) = self.ranges.get(index)?;
Some(self.view(start, end))
}
pub fn iter(&self) -> Iter<'_, 'source, 'ranges, S, N> {
Iter::new(self)
}
pub const fn is_empty(&self) -> bool {
self.len() == 0
}
pub const fn len(&self) -> usize {
self.len
}
pub const fn count(&self) -> segments::Count {
segments::Count::new(self.ranges.len() as u32)
}
pub fn contiguous(&self) -> Option<&'source [u8]> {
match self.ranges {
[] => Some(&[]),
&[(start, end)] => Some(self.view(start, end).as_slice()),
_ => None,
}
}
}
impl<N: buffer::raw::Length> Set<'_, '_, storage::Shared, N> {
pub fn try_retain<'d>(&self) -> Result<segments::Shape<resident::Shared<'d>>, retain::Error> {
if !self.count().is_many() {
return self
.iter()
.next()
.map_or(Ok(segments::Shape::Empty), |view| {
share((0, view)).map(segments::Shape::One)
});
}
let actual = self.ranges.len();
let added = crate::buffer::Residency::resident(self.source);
let Some(resident) = actual.checked_mul(added) else {
let added = unsafe { NonZero::new_unchecked(added) };
let index = usize::MAX / added;
return Err(retain::Error::Resident {
index: index as u32,
current: index * added.get(),
added: added.get(),
});
};
let source = Retain {
source: self,
resident,
};
segments::Exact::try_new(&source)?
.try_collect()
.map(segments::Shape::Many)
}
}
#[inline]
fn share<'d>(
(index, view): (usize, buffer::View<'_, storage::Shared>),
) -> Result<segments::Item<resident::Shared<'d>>, retain::Error> {
let view = unsafe { regions::NonEmpty::assume(&view) };
<storage::Shared as segments::Seal>::try_share(view)
.map(segments::Item::from)
.map_err(|error| retain::Error::Retain { index, error })
}
struct Retain<'a, 'b, 'c, N = u32> {
source: &'a Set<'b, 'c, storage::Shared, N>,
resident: usize,
}
unsafe impl<'d, N: buffer::raw::Length> buffer::raw::Sequence<resident::Shared<'d>>
for &Retain<'_, '_, '_, N>
{
type Item = Result<segments::Item<resident::Shared<'d>>, retain::Error>;
type Error = retain::Error;
fn owners(self) -> (impl Iterator<Item = Self::Item>, impl buffer::raw::Total) {
(self.source.iter().enumerate().map(share), self)
}
fn reject(self, error: crate::alloc::Error) -> Self::Error {
retain::Error::Metadata(error)
}
}
impl<N: buffer::raw::Length> buffer::raw::Total for &Retain<'_, '_, '_, N> {
fn count(&self) -> segments::Count {
self.source.count()
}
fn len(&self) -> usize {
self.source.len
}
fn resident(&self) -> usize {
self.resident
}
}
const _: () = {
assert!(size_of::<Set<'static, 'static, [u8]>>() == 5 * size_of::<usize>());
assert!(size_of::<Set<'static, 'static, storage::Shared>>() == 4 * size_of::<usize>());
assert!(size_of::<Retain<'static, 'static, 'static>>() == 2 * size_of::<usize>());
};