use crate::BStack;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::io;
use std::ops::Range;
pub struct BStackSlice<'a, A: BStackAllocator> {
allocator: &'a A,
offset: u64,
len: u64,
}
impl<'a, A: BStackAllocator> Clone for BStackSlice<'a, A> {
fn clone(&self) -> Self {
*self
}
}
impl<'a, A: BStackAllocator> Copy for BStackSlice<'a, A> {}
impl<'a, A: BStackAllocator> fmt::Debug for BStackSlice<'a, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("BStackSlice")
.field("start", &self.start())
.field("end", &self.end())
.field("len", &self.len())
.finish_non_exhaustive()
}
}
impl<'a, A: BStackAllocator> BStackSlice<'a, A> {
#[deprecated(
since = "0.1.10",
note = "Use `unsafe { BStackSlice::from_raw_parts(allocator, offset, len) }` instead; \
see `BStackSlice::from_raw_parts` for the required safety contract."
)]
#[inline]
pub fn new(allocator: &'a A, offset: u64, len: u64) -> Self {
Self {
allocator,
offset,
len,
}
}
#[inline]
pub unsafe fn from_raw_parts(allocator: &'a A, offset: u64, len: u64) -> Self {
Self {
allocator,
offset,
len,
}
}
#[inline]
pub fn to_bytes(&self) -> [u8; 16] {
let mut out = [0u8; 16];
out[..8].copy_from_slice(&self.offset.to_le_bytes());
out[8..].copy_from_slice(&self.len.to_le_bytes());
out
}
#[inline]
pub unsafe fn from_bytes(allocator: &'a A, bytes: [u8; 16]) -> Self {
let offset = u64::from_le_bytes(bytes[..8].try_into().unwrap());
let len = u64::from_le_bytes(bytes[8..].try_into().unwrap());
Self {
allocator,
offset,
len,
}
}
#[inline]
pub fn start(&self) -> u64 {
self.offset
}
#[inline]
pub fn end(&self) -> u64 {
self.offset + self.len
}
#[inline]
pub fn range(&self) -> Range<u64> {
self.start()..self.end()
}
#[inline]
pub fn len(&self) -> u64 {
self.len
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len == 0
}
#[inline]
pub fn allocator(&self) -> &'a A {
self.allocator
}
#[inline]
pub fn stack(&self) -> &BStack {
self.allocator.stack()
}
#[inline]
pub fn subslice(&self, start: u64, end: u64) -> BStackSlice<'a, A> {
self.subslice_range(start..end)
}
pub fn subslice_range(&self, range: Range<u64>) -> BStackSlice<'a, A> {
assert!(range.start <= range.end, "range start must be <= end");
assert!(range.end <= self.len, "range end must be <= slice length");
BStackSlice {
allocator: self.allocator,
offset: self.offset + range.start,
len: range.end - range.start,
}
}
pub fn read(&self) -> io::Result<Vec<u8>> {
self.stack().get(self.start(), self.end())
}
pub fn read_into(&self, buf: &mut [u8]) -> io::Result<()> {
let n = (buf.len() as u64).min(self.len()) as usize;
self.stack().get_into(self.start(), &mut buf[..n])
}
pub fn read_range(&self, start: u64, end: u64) -> io::Result<Vec<u8>> {
if end > self.len() {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!("range [{start}, {end}) exceeds slice length {}", self.len()),
));
}
self.stack().get(self.start() + start, self.start() + end)
}
pub fn read_range_into(&self, start: u64, buf: &mut [u8]) -> io::Result<()> {
let end_rel = start + buf.len() as u64;
if end_rel > self.len() {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!(
"range [{start}, {end_rel}) exceeds slice length {}",
self.len()
),
));
}
self.stack().get_into(self.start() + start, buf)
}
#[cfg(feature = "set")]
pub fn write(&self, data: impl AsRef<[u8]>) -> io::Result<()> {
let data = data.as_ref();
let n = (data.len() as u64).min(self.len()) as usize;
self.stack().set(self.start(), &data[..n])
}
#[cfg(feature = "set")]
pub fn write_range(&self, start: u64, data: impl AsRef<[u8]>) -> io::Result<()> {
let data = data.as_ref();
let end_rel = start + data.len() as u64;
if end_rel > self.len() {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!(
"range [{start}, {end_rel}) exceeds slice length {}",
self.len()
),
));
}
self.stack().set(self.start() + start, data)
}
#[cfg(feature = "set")]
pub fn zero(&self) -> io::Result<()> {
self.stack().zero(self.start(), self.len())
}
#[cfg(feature = "set")]
pub fn zero_range(&self, start: u64, n: u64) -> io::Result<()> {
let end_rel = start + n;
if end_rel > self.len() {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!(
"range [{start}, {end_rel}) exceeds slice length {}",
self.len()
),
));
}
self.stack().zero(self.start() + start, n)
}
pub fn reader(&self) -> BStackSliceReader<'a, A> {
BStackSliceReader {
slice: *self,
cursor: 0,
}
}
pub fn reader_at(&self, offset: u64) -> BStackSliceReader<'a, A> {
BStackSliceReader {
slice: *self,
cursor: offset,
}
}
#[cfg(feature = "set")]
pub fn writer(&self) -> BStackSliceWriter<'a, A> {
BStackSliceWriter {
slice: *self,
cursor: 0,
}
}
#[cfg(feature = "set")]
pub fn writer_at(&self, offset: u64) -> BStackSliceWriter<'a, A> {
BStackSliceWriter {
slice: *self,
cursor: offset,
}
}
}
impl<'a, A: BStackAllocator> PartialEq for BStackSlice<'a, A> {
fn eq(&self, other: &Self) -> bool {
self.offset == other.offset && self.len == other.len
}
}
impl<'a, A: BStackAllocator> Eq for BStackSlice<'a, A> {}
impl<'a, A: BStackAllocator> Hash for BStackSlice<'a, A> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.offset.hash(state);
self.len.hash(state);
}
}
impl<'a, A: BStackAllocator> PartialOrd for BStackSlice<'a, A> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<'a, A: BStackAllocator> Ord for BStackSlice<'a, A> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.offset
.cmp(&other.offset)
.then(self.len.cmp(&other.len))
}
}
impl<'a, A: BStackAllocator> From<BStackSlice<'a, A>> for [u8; 16] {
fn from(slice: BStackSlice<'a, A>) -> Self {
slice.to_bytes()
}
}
impl<'a, A: BStackAllocator> From<BStackSlice<'a, A>> for BStackSliceReader<'a, A> {
fn from(slice: BStackSlice<'a, A>) -> Self {
slice.reader()
}
}
pub struct BStackSliceReader<'a, A: BStackAllocator> {
slice: BStackSlice<'a, A>,
cursor: u64,
}
impl<'a, A: BStackAllocator> Clone for BStackSliceReader<'a, A> {
fn clone(&self) -> Self {
Self {
slice: self.slice,
cursor: self.cursor,
}
}
}
impl<'a, A: BStackAllocator> fmt::Debug for BStackSliceReader<'a, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("BStackSliceReader")
.field("start", &self.slice.start())
.field("end", &self.slice.end())
.field("len", &self.slice.len())
.field("cursor", &self.cursor)
.finish_non_exhaustive()
}
}
impl<'a, A: BStackAllocator> BStackSliceReader<'a, A> {
#[inline]
pub fn position(&self) -> u64 {
self.cursor
}
#[inline]
pub fn slice(&self) -> BStackSlice<'a, A> {
self.slice
}
}
impl<'a, A: BStackAllocator> io::Read for BStackSliceReader<'a, A> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if buf.is_empty() || self.cursor >= self.slice.len {
return Ok(0);
}
let available = (self.slice.len - self.cursor) as usize;
let n = buf.len().min(available);
let abs_start = self.slice.offset + self.cursor;
self.slice.stack().get_into(abs_start, &mut buf[..n])?;
self.cursor += n as u64;
Ok(n)
}
}
impl<'a, A: BStackAllocator> io::Seek for BStackSliceReader<'a, A> {
fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
let len = self.slice.len as i128;
let new_pos = match pos {
io::SeekFrom::Start(n) => n as i128,
io::SeekFrom::End(n) => len + n as i128,
io::SeekFrom::Current(n) => self.cursor as i128 + n as i128,
};
if new_pos < 0 {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"seek before beginning of slice",
));
}
self.cursor = new_pos as u64;
Ok(self.cursor)
}
}
impl<'a, A: BStackAllocator> PartialEq for BStackSliceReader<'a, A> {
fn eq(&self, other: &Self) -> bool {
self.slice == other.slice && self.cursor == other.cursor
}
}
impl<'a, A: BStackAllocator> Eq for BStackSliceReader<'a, A> {}
impl<'a, A: BStackAllocator> Hash for BStackSliceReader<'a, A> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.slice.hash(state);
self.cursor.hash(state);
}
}
impl<'a, A: BStackAllocator> PartialOrd for BStackSliceReader<'a, A> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<'a, A: BStackAllocator> Ord for BStackSliceReader<'a, A> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
let self_pos = self.slice.start() + self.cursor;
let other_pos = other.slice.start() + other.cursor;
self_pos
.cmp(&other_pos)
.then(self.slice.len().cmp(&other.slice.len()))
}
}
impl<'a, A: BStackAllocator> From<BStackSliceReader<'a, A>> for BStackSlice<'a, A> {
fn from(reader: BStackSliceReader<'a, A>) -> Self {
reader.slice()
}
}
#[cfg(feature = "set")]
pub struct BStackSliceWriter<'a, A: BStackAllocator> {
slice: BStackSlice<'a, A>,
cursor: u64,
}
#[cfg(feature = "set")]
impl<'a, A: BStackAllocator> Clone for BStackSliceWriter<'a, A> {
fn clone(&self) -> Self {
Self {
slice: self.slice,
cursor: self.cursor,
}
}
}
#[cfg(feature = "set")]
impl<'a, A: BStackAllocator> fmt::Debug for BStackSliceWriter<'a, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("BStackSliceWriter")
.field("start", &self.slice.start())
.field("end", &self.slice.end())
.field("len", &self.slice.len())
.field("cursor", &self.cursor)
.finish_non_exhaustive()
}
}
#[cfg(feature = "set")]
impl<'a, A: BStackAllocator> BStackSliceWriter<'a, A> {
#[inline]
pub fn position(&self) -> u64 {
self.cursor
}
#[inline]
pub fn slice(&self) -> BStackSlice<'a, A> {
self.slice
}
}
#[cfg(feature = "set")]
impl<'a, A: BStackAllocator> io::Write for BStackSliceWriter<'a, A> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
if buf.is_empty() || self.cursor >= self.slice.len {
return Ok(0);
}
let available = (self.slice.len - self.cursor) as usize;
let n = buf.len().min(available);
let abs_start = self.slice.offset + self.cursor;
self.slice.stack().set(abs_start, &buf[..n])?;
self.cursor += n as u64;
Ok(n)
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
#[cfg(feature = "set")]
impl<'a, A: BStackAllocator> io::Seek for BStackSliceWriter<'a, A> {
fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
let len = self.slice.len as i128;
let new_pos = match pos {
io::SeekFrom::Start(n) => n as i128,
io::SeekFrom::End(n) => len + n as i128,
io::SeekFrom::Current(n) => self.cursor as i128 + n as i128,
};
if new_pos < 0 {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"seek before beginning of slice",
));
}
self.cursor = new_pos as u64;
Ok(self.cursor)
}
}
#[cfg(feature = "set")]
impl<'a, A: BStackAllocator> PartialEq for BStackSliceWriter<'a, A> {
fn eq(&self, other: &Self) -> bool {
self.slice == other.slice && self.cursor == other.cursor
}
}
#[cfg(feature = "set")]
impl<'a, A: BStackAllocator> Eq for BStackSliceWriter<'a, A> {}
#[cfg(feature = "set")]
impl<'a, A: BStackAllocator> Hash for BStackSliceWriter<'a, A> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.slice.hash(state);
self.cursor.hash(state);
}
}
#[cfg(feature = "set")]
impl<'a, A: BStackAllocator> PartialOrd for BStackSliceWriter<'a, A> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
#[cfg(feature = "set")]
impl<'a, A: BStackAllocator> Ord for BStackSliceWriter<'a, A> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
let self_pos = self.slice.start() + self.cursor;
let other_pos = other.slice.start() + other.cursor;
self_pos
.cmp(&other_pos)
.then(self.slice.len().cmp(&other.slice.len()))
}
}
#[cfg(feature = "set")]
impl<'a, A: BStackAllocator> From<BStackSlice<'a, A>> for BStackSliceWriter<'a, A> {
fn from(slice: BStackSlice<'a, A>) -> Self {
slice.writer()
}
}
#[cfg(feature = "set")]
impl<'a, A: BStackAllocator> From<BStackSliceWriter<'a, A>> for BStackSlice<'a, A> {
fn from(writer: BStackSliceWriter<'a, A>) -> Self {
writer.slice()
}
}
#[cfg(feature = "set")]
impl<'a, A: BStackAllocator> From<BStackSliceReader<'a, A>> for BStackSliceWriter<'a, A> {
fn from(reader: BStackSliceReader<'a, A>) -> Self {
BStackSliceWriter {
slice: reader.slice,
cursor: reader.cursor,
}
}
}
#[cfg(feature = "set")]
impl<'a, A: BStackAllocator> From<BStackSliceWriter<'a, A>> for BStackSliceReader<'a, A> {
fn from(writer: BStackSliceWriter<'a, A>) -> Self {
BStackSliceReader {
slice: writer.slice,
cursor: writer.cursor,
}
}
}
#[cfg(feature = "set")]
impl<'a, A: BStackAllocator> PartialEq<BStackSliceWriter<'a, A>> for BStackSliceReader<'a, A> {
fn eq(&self, other: &BStackSliceWriter<'a, A>) -> bool {
self.slice == other.slice && self.cursor == other.cursor
}
}
#[cfg(feature = "set")]
impl<'a, A: BStackAllocator> PartialEq<BStackSliceReader<'a, A>> for BStackSliceWriter<'a, A> {
fn eq(&self, other: &BStackSliceReader<'a, A>) -> bool {
self.slice == other.slice && self.cursor == other.cursor
}
}
impl<'a, A: BStackAllocator> PartialEq<BStackSlice<'a, A>> for BStackSliceReader<'a, A> {
fn eq(&self, other: &BStackSlice<'a, A>) -> bool {
&self.slice == other
}
}
impl<'a, A: BStackAllocator> PartialEq<BStackSliceReader<'a, A>> for BStackSlice<'a, A> {
fn eq(&self, other: &BStackSliceReader<'a, A>) -> bool {
self == &other.slice
}
}
#[cfg(feature = "set")]
impl<'a, A: BStackAllocator> PartialEq<BStackSlice<'a, A>> for BStackSliceWriter<'a, A> {
fn eq(&self, other: &BStackSlice<'a, A>) -> bool {
&self.slice == other
}
}
#[cfg(feature = "set")]
impl<'a, A: BStackAllocator> PartialEq<BStackSliceWriter<'a, A>> for BStackSlice<'a, A> {
fn eq(&self, other: &BStackSliceWriter<'a, A>) -> bool {
self == &other.slice
}
}
impl<'a, A: BStackAllocator> PartialOrd<BStackSliceReader<'a, A>> for BStackSlice<'a, A> {
fn partial_cmp(&self, other: &BStackSliceReader<'a, A>) -> Option<std::cmp::Ordering> {
Some(self.cmp(&other.slice()))
}
}
impl<'a, A: BStackAllocator> PartialOrd<BStackSlice<'a, A>> for BStackSliceReader<'a, A> {
fn partial_cmp(&self, other: &BStackSlice<'a, A>) -> Option<std::cmp::Ordering> {
Some(self.slice().cmp(other))
}
}
#[cfg(feature = "set")]
impl<'a, A: BStackAllocator> PartialOrd<BStackSlice<'a, A>> for BStackSliceWriter<'a, A> {
fn partial_cmp(&self, other: &BStackSlice<'a, A>) -> Option<std::cmp::Ordering> {
Some(self.slice().cmp(other))
}
}
#[cfg(feature = "set")]
impl<'a, A: BStackAllocator> PartialOrd<BStackSliceWriter<'a, A>> for BStackSliceReader<'a, A> {
fn partial_cmp(&self, other: &BStackSliceWriter<'a, A>) -> Option<std::cmp::Ordering> {
let self_pos = self.slice.start() + self.cursor;
let other_pos = other.slice().start() + other.position();
Some(
self_pos
.cmp(&other_pos)
.then(self.slice.len().cmp(&other.slice().len())),
)
}
}
#[cfg(feature = "set")]
impl<'a, A: BStackAllocator> PartialOrd<BStackSliceReader<'a, A>> for BStackSliceWriter<'a, A> {
fn partial_cmp(&self, other: &BStackSliceReader<'a, A>) -> Option<std::cmp::Ordering> {
let self_pos = self.slice.start() + self.cursor;
let other_pos = other.slice().start() + other.position();
Some(
self_pos
.cmp(&other_pos)
.then(self.slice.len().cmp(&other.slice().len())),
)
}
}
pub trait BStackAllocator: Sized {
type Error: fmt::Debug + fmt::Display;
type Allocated<'a>: Copy + TryInto<BStackSlice<'a, Self>, Error: fmt::Debug + fmt::Display>
where
Self: 'a;
fn stack(&self) -> &BStack;
fn into_stack(self) -> BStack;
fn alloc(&self, len: u64) -> Result<Self::Allocated<'_>, Self::Error>;
fn realloc<'a>(
&'a self,
handle: Self::Allocated<'a>,
new_len: u64,
) -> Result<Self::Allocated<'a>, Self::Error>;
fn dealloc(&self, _handle: Self::Allocated<'_>) -> Result<(), Self::Error> {
Ok(())
}
fn len(&self) -> io::Result<u64> {
self.stack().len()
}
fn is_empty(&self) -> io::Result<bool> {
self.stack().is_empty()
}
}
pub trait BStackBulkAllocator: BStackAllocator {
fn alloc_bulk(
&self,
lengths: impl AsRef<[u64]>,
) -> Result<Vec<Self::Allocated<'_>>, Self::Error>;
fn dealloc_bulk<'a>(
&'a self,
handles: impl AsRef<[Self::Allocated<'a>]>,
) -> Result<(), Self::Error>;
}
pub trait BStackSliceAllocator:
'static
+ BStackAllocator<Error = io::Error>
+ for<'a> BStackAllocator<Allocated<'a> = BStackSlice<'a, Self>>
{
}
impl<A: 'static> BStackSliceAllocator for A
where
A: BStackAllocator<Error = io::Error>,
for<'a> A: BStackAllocator<Allocated<'a> = BStackSlice<'a, A>>,
{
}
#[cfg(feature = "set")]
pub mod first_fit;
#[cfg(feature = "set")]
pub mod ghost_tree;
pub mod linear;
pub mod manual;
#[cfg(feature = "guarded")]
pub mod slices;
#[cfg(feature = "set")]
pub use first_fit::FirstFitBStackAllocator;
#[cfg(feature = "set")]
pub use ghost_tree::GhostTreeBstackAllocator;
pub use linear::LinearBStackAllocator;
pub use manual::ManualAllocator;
#[cfg(all(feature = "guarded", feature = "atomic"))]
pub use slices::{BStackAtomicGuardedSlice, BStackAtomicGuardedSliceSubview};
#[cfg(feature = "guarded")]
pub use slices::{BStackGuardedSlice, BStackGuardedSliceSubview};