use std::marker::PhantomData;
use std::mem::MaybeUninit;
pub const BUFFER_SIZE: usize = 16;
pub trait Pullable {
type Item;
fn pull(&mut self, buffer: &mut PushBuffer<Self::Item>);
fn buffered(self) -> PullBuffer<Self> where Self: Sized {
PullBuffer::new(self)
}
fn transcode<K, E>(self, encoding: E) -> Transcoder<K, E, Self>
where Self: Sized,
K: TranscoderKind<Input = Self::Item>,
E: TranscoderImpl<K, Self> {
Transcoder::new(encoding, self)
}
}
impl<I> Pullable for I where I: Iterator {
type Item = I::Item;
fn pull(&mut self, buffer: &mut PushBuffer<Self::Item>) {
while buffer.fits(1) {
if let Some(x) = self.next() {
buffer.push([ x ]);
} else {
break;
}
}
}
}
pub struct PullBuffer<I> where I: Pullable {
inner: I,
head: usize,
tail: usize,
buffer: [MaybeUninit<I::Item>; BUFFER_SIZE],
}
impl<I> PullBuffer<I> where I: Pullable {
pub fn new(inner: I) -> Self {
Self { inner, head: 0, tail: 0, buffer: std::array::from_fn(|_| MaybeUninit::uninit()) }
}
pub fn view(&mut self, amount: usize) -> &[I::Item] {
assert!(amount <= BUFFER_SIZE);
if self.head + amount > self.tail {
if self.head == self.tail {
self.head = 0;
self.tail = 0;
} else {
self.buffer.rotate_left(self.head);
self.tail -= self.head;
self.head = 0;
}
let mut buffer = PushBuffer::new(&mut self.buffer[self.tail..]);
self.inner.pull(&mut buffer);
self.tail += buffer.len();
}
let view = &self.buffer[self.head..self.tail.min(self.head + amount)];
unsafe { std::mem::transmute(view) } }
pub fn advance(&mut self, amount: usize) {
assert!(self.head + amount <= self.tail);
for i in 0..amount {
unsafe {
std::mem::replace(&mut self.buffer[self.head + i], MaybeUninit::uninit()).assume_init_drop();
}
}
self.head += amount;
}
}
impl<I> Iterator for PullBuffer<I> where I: Pullable {
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
if self.head >= self.tail {
let mut buffer = PushBuffer::new(&mut self.buffer);
self.inner.pull(&mut buffer);
self.head = 0;
self.tail = buffer.len();
}
if self.head < self.tail {
let item = std::mem::replace(&mut self.buffer[self.head], MaybeUninit::uninit());
self.head += 1;
Some(unsafe { item.assume_init() })
} else {
None
}
}
}
impl<I> Drop for PullBuffer<I> where I: Pullable {
fn drop(&mut self) {
for i in self.head..self.tail {
unsafe {
std::mem::replace(&mut self.buffer[i], MaybeUninit::uninit()).assume_init_drop();
}
}
self.head = 0;
self.tail = 0;
}
}
pub struct PushBuffer<'a, T> {
count: usize,
buffer: &'a mut [MaybeUninit<T>],
}
impl<'a, T> PushBuffer<'a, T> {
pub fn new(buffer: &'a mut [MaybeUninit<T>]) -> Self {
Self { count: 0, buffer }
}
pub fn len(&self) -> usize { self.count }
pub fn is_empty(&self) -> bool { self.count == 0 }
pub fn capacity(&self) -> usize { self.buffer.len() }
pub fn fits(&self, count: usize) -> bool { self.count + count <= self.buffer.len() }
pub fn push<const N: usize>(&mut self, items: [T; N]) {
assert!(self.fits(N));
for (i, x) in items.into_iter().enumerate() {
self.buffer[self.count + i].write(x);
}
self.count += N;
}
}
pub trait TranscoderKind {
type Input;
type Output;
}
pub trait TranscoderImpl<K, I> where K: TranscoderKind, I: Pullable<Item = K::Input> {
fn transcode(&self, input: &mut PullBuffer<I>, output: &mut PushBuffer<K::Output>);
}
pub struct Transcoder<K, E, I> where K: TranscoderKind, I: Pullable<Item = K::Input>, E: TranscoderImpl<K, I> {
encoding: E,
input: PullBuffer<I>,
phantom: PhantomData<K>,
}
impl<K, E, I> Transcoder<K, E, I> where K: TranscoderKind, I: Pullable<Item = K::Input>, E: TranscoderImpl<K, I> {
pub fn new(encoding: E, input: I) -> Self {
Self { encoding, input: input.buffered(), phantom: PhantomData }
}
}
impl<K, E, I> Pullable for Transcoder<K, E, I> where K: TranscoderKind, I: Pullable<Item = K::Input>, E: TranscoderImpl<K, I> {
type Item = K::Output;
fn pull(&mut self, buffer: &mut PushBuffer<Self::Item>) {
self.encoding.transcode(&mut self.input, buffer)
}
}
pub mod str;