use std::{marker, num::NonZero};
pub use reader::Reader;
use crate::buffer;
pub mod raw;
mod reader;
pub trait Source: buffer::raw::Chunks {
fn chunks(&self) -> Self::Cursor<'_> {
buffer::raw::Chunks::start(self)
}
fn suffix<const N: usize>(&self) -> Option<[u8; N]> {
let mut cursor = self.chunks();
let skipped = buffer::raw::Scatter::remaining(&cursor).checked_sub(N)?;
Take::new(&mut cursor, skipped).finish();
let mut output = [0; N];
let source = Take::new(&mut cursor, usize::MAX);
unsafe {
buffer::raw::copy_slices(source.map(|chunk| chunk.bytes()), output.as_mut_ptr());
}
Some(output)
}
}
impl<T: buffer::raw::Chunks + ?Sized> Source for T {}
#[must_use = "a bounded scatter view does nothing until it is iterated"]
pub struct Take<'cursor, 'data, C> {
cursor: &'cursor mut C,
remaining: usize,
data: marker::PhantomData<&'data [u8]>,
}
impl<'cursor, 'data, C> Take<'cursor, 'data, C> {
pub fn new(cursor: &'cursor mut C, limit: usize) -> Self
where
C: buffer::raw::Scatter<'data>,
{
let len = limit.min(cursor.remaining());
Self {
cursor,
remaining: len,
data: marker::PhantomData,
}
}
pub const fn len(&self) -> usize {
self.remaining
}
pub const fn is_empty(&self) -> bool {
self.remaining == 0
}
}
impl<'data, C: buffer::raw::Scatter<'data>> Take<'_, 'data, C> {
pub fn next_chunk<const MAX: usize>(&mut self) -> Option<buffer::raw::Chunk<'data, MAX>> {
const { assert!(MAX > 0) };
let cap = NonZero::new(self.remaining.min(MAX))?;
Some(self.advance(cap))
}
fn advance<const MAX: usize>(&mut self, cap: NonZero<usize>) -> buffer::raw::Chunk<'data, MAX> {
let left = unsafe { NonZero::new_unchecked(self.cursor.remaining()) };
let chunk = unsafe { self.cursor.advance(cap, left) };
self.remaining -= chunk.len().get();
chunk
}
pub(in crate::buffer) fn finish(mut self) {
while !self.is_empty() {
let _ = self.next();
}
}
}
impl<'data, C: buffer::raw::Scatter<'data>> Iterator for Take<'_, 'data, C> {
type Item = buffer::raw::Chunk<'data>;
fn next(&mut self) -> Option<Self::Item> {
let cap = NonZero::new(self.remaining)?;
Some(self.advance(cap))
}
fn size_hint(&self) -> (usize, Option<usize>) {
if self.is_empty() {
(0, Some(0))
} else {
(1, None)
}
}
}