use std::{mem, num::NonZero};
use o3::buffer::{
self, Residency as _, hold, pool, resident, resident::bound, segments, segments::scatter,
storage,
};
use crate::link::egress::data::{
self, Bound, compose,
compose::{Either, Tagged},
exec, pair,
};
pub unsafe trait Payload<'d> {
type Mode: exec::Mode;
type Cursor<'a>: buffer::raw::Scatter<'a>
where
Self: 'a;
fn len(&self) -> usize;
fn is_empty(&self) -> bool {
self.len() == 0
}
fn start(&self) -> Self::Cursor<'_>;
fn charge(&self) -> hold::Charge;
fn cursor(&self, offset: data::Offset) -> Option<Self::Cursor<'_>>;
unsafe fn resume(
&self,
position: &mut scatter::raw::Position,
offset: data::Offset,
) -> Self::Cursor<'_>;
}
pub unsafe trait StableOwner<'d>: AsRef<[u8]> + buffer::Residency {}
unsafe impl<'d> StableOwner<'d> for resident::Shared<'d> {}
unsafe impl<'d> StableOwner<'d> for storage::Shared {}
unsafe impl<'d, L> StableOwner<'d> for pool::Cursor<L> {}
unsafe impl<'a, L, R> buffer::raw::Scatter<'a> for compose::Either<L, R>
where
L: buffer::raw::Scatter<'a>,
R: buffer::raw::Scatter<'a>,
{
fn remaining(&self) -> usize {
match self {
Self::Left(cursor) => cursor.remaining(),
Self::Right(cursor) => cursor.remaining(),
}
}
unsafe fn advance<const MAX: usize>(
&mut self,
cap: NonZero<usize>,
) -> buffer::raw::Chunk<'a, MAX> {
match self {
Self::Left(cursor) => unsafe { cursor.advance(cap) },
Self::Right(cursor) => unsafe { cursor.advance(cap) },
}
}
}
const _: () = {
assert!(
mem::size_of::<compose::Either<&'static [u8], &'static [u8]>>()
== 3 * mem::size_of::<usize>()
);
};
pub unsafe trait Contiguous<'d>: AsRef<[u8]> + buffer::Residency {}
unsafe impl<'d> Contiguous<'d> for resident::Shared<'d> {}
unsafe impl<'d> Contiguous<'d> for storage::Shared {}
unsafe impl<'d, L> Contiguous<'d> for pool::Cursor<L> {}
unsafe impl<'d, 'a: 'd> Contiguous<'d> for &'a [u8] {}
unsafe impl<'d, T: Contiguous<'d>> Payload<'d> for T {
type Mode = exec::Fallible;
type Cursor<'a>
= &'a [u8]
where
Self: 'a;
fn len(&self) -> usize {
self.as_ref().len()
}
fn charge(&self) -> hold::Charge {
hold::Charge::from_owner(self.as_ref().len(), self.resident())
}
fn start(&self) -> Self::Cursor<'_> {
self.as_ref()
}
fn cursor(&self, offset: data::Offset) -> Option<Self::Cursor<'_>> {
offset.tail(self.as_ref())
}
unsafe fn resume(
&self,
_: &mut scatter::raw::Position,
offset: data::Offset,
) -> Self::Cursor<'_> {
unsafe { self.as_ref().get_unchecked(offset.get()..) }
}
}
unsafe impl<'d, O> Payload<'d> for segments::Chain<O>
where
O: buffer::raw::Segment + data::raw::StableOwner<'d>,
{
type Mode = exec::Fallible;
type Cursor<'a>
= <segments::Chain<O> as buffer::raw::Chunks>::Cursor<'a>
where
Self: 'a;
fn len(&self) -> usize {
segments::Sequence::len(self)
}
fn charge(&self) -> hold::Charge {
hold::Charge::from(self)
}
fn start(&self) -> Self::Cursor<'_> {
buffer::raw::Chunks::start(self)
}
unsafe fn resume(
&self,
position: &mut scatter::raw::Position,
offset: data::Offset,
) -> Self::Cursor<'_> {
unsafe { position.resume(self, offset.get()) }
}
fn cursor(&self, offset: data::Offset) -> Option<Self::Cursor<'_>> {
if offset.is_at_least(self.len()) {
return None;
}
buffer::raw::Chunks::cursor(self, offset.get())
}
}
pub unsafe trait Resident<'d>: Payload<'d> {}
unsafe impl<'d, L> Resident<'d> for pool::Cursor<L> {}
unsafe impl<'a> buffer::raw::Scatter<'a> for pair::Cursor<'a> {
fn remaining(&self) -> usize {
self.prefix.len() + self.body.len()
}
unsafe fn advance<const MAX: usize>(
&mut self,
cap: NonZero<usize>,
) -> buffer::raw::Chunk<'a, MAX> {
if let Some(child) = NonZero::new(self.prefix.len()) {
unsafe { buffer::raw::Scatter::advance(&mut self.prefix, cap.min(child)) }
} else {
unsafe { buffer::raw::Scatter::advance(&mut self.body, cap) }
}
}
}
unsafe impl<'d, T: data::raw::Payload<'d>, G: bound::Bound> data::raw::Payload<'d> for Bound<T, G> {
type Mode = exec::Guaranteed<G>;
type Cursor<'a>
= T::Cursor<'a>
where
Self: 'a;
fn len(&self) -> usize {
self.as_inner().len()
}
fn charge(&self) -> hold::Charge {
self.as_inner().charge()
}
fn start(&self) -> Self::Cursor<'_> {
self.as_inner().start()
}
fn cursor(&self, offset: data::Offset) -> Option<Self::Cursor<'_>> {
self.as_inner().cursor(offset)
}
unsafe fn resume(
&self,
position: &mut scatter::raw::Position,
offset: data::Offset,
) -> Self::Cursor<'_> {
unsafe { self.as_inner().resume(position, offset) }
}
}
unsafe impl<'d, A: data::raw::Payload<'d>, B: data::raw::Payload<'d>> data::raw::Payload<'d>
for Either<A, B>
{
type Mode = exec::Fallible;
type Cursor<'a>
= Either<A::Cursor<'a>, B::Cursor<'a>>
where
Self: 'a;
fn len(&self) -> usize {
match self {
Self::Left(value) => value.len(),
Self::Right(value) => value.len(),
}
}
fn charge(&self) -> hold::Charge {
match self {
Self::Left(value) => value.charge(),
Self::Right(value) => value.charge(),
}
}
fn start(&self) -> Self::Cursor<'_> {
match self {
Self::Left(value) => Either::Left(value.start()),
Self::Right(value) => Either::Right(value.start()),
}
}
fn cursor(&self, offset: data::Offset) -> Option<Self::Cursor<'_>> {
match self {
Self::Left(value) => value.cursor(offset).map(Either::Left),
Self::Right(value) => value.cursor(offset).map(Either::Right),
}
}
unsafe fn resume(
&self,
position: &mut scatter::raw::Position,
offset: data::Offset,
) -> Self::Cursor<'_> {
match self {
Self::Left(value) => Either::Left(unsafe { value.resume(position, offset) }),
Self::Right(value) => Either::Right(unsafe { value.resume(position, offset) }),
}
}
}
unsafe impl<'d, T: data::raw::Payload<'d>, K> data::raw::Payload<'d> for Tagged<T, K> {
type Mode = exec::Fallible;
type Cursor<'a>
= T::Cursor<'a>
where
Self: 'a;
fn len(&self) -> usize {
self.payload.len()
}
fn charge(&self) -> hold::Charge {
self.payload.charge()
}
fn start(&self) -> Self::Cursor<'_> {
self.payload.start()
}
fn cursor(&self, offset: data::Offset) -> Option<Self::Cursor<'_>> {
self.payload.cursor(offset)
}
unsafe fn resume(
&self,
position: &mut scatter::raw::Position,
offset: data::Offset,
) -> Self::Cursor<'_> {
unsafe { self.payload.resume(position, offset) }
}
}
unsafe impl<'d, T: data::raw::Resident<'d>, K> data::raw::Resident<'d> for Tagged<T, K> {}
unsafe impl<'d, C: buffer::raw::Segment> data::raw::Payload<'d> for pair::Source<C> {
type Mode = exec::Fallible;
type Cursor<'a>
= pair::Cursor<'a>
where
Self: 'a;
fn len(&self) -> usize {
self.prefix.len() + self.body.as_ref().len()
}
fn charge(&self) -> hold::Charge {
let body = hold::Charge::from_split(self.body.resident());
let logical = if body.owners == 0 {
0
} else {
self.body.as_ref().len()
};
hold::Charge::from_commit(
self.prefix.len() + logical,
self.prefix.resident() + body.resident_bytes,
1 + body.owners,
)
}
fn start(&self) -> Self::Cursor<'_> {
pair::Cursor {
prefix: self.prefix.as_ref(),
body: self.body.as_ref(),
}
}
fn cursor(&self, offset: data::Offset) -> Option<Self::Cursor<'_>> {
Some(match offset.split_at(self.prefix.len()) {
data::Split::Before(offset) => pair::Cursor {
prefix: offset.tail(self.prefix.as_ref())?,
body: self.body.as_ref(),
},
data::Split::After(offset) => pair::Cursor {
prefix: &[],
body: offset.tail(self.body.as_ref())?,
},
})
}
unsafe fn resume(
&self,
_: &mut scatter::raw::Position,
offset: data::Offset,
) -> Self::Cursor<'_> {
match offset.split_at(self.prefix.len()) {
data::Split::Before(offset) => pair::Cursor {
prefix: unsafe { self.prefix.as_ref().get_unchecked(offset.get()..) },
body: self.body.as_ref(),
},
data::Split::After(offset) => pair::Cursor {
prefix: &[],
body: unsafe { self.body.as_ref().get_unchecked(offset.get()..) },
},
}
}
}