use std::marker::PhantomData; use std::mem::MaybeUninit; pub const BUFFER_SIZE: usize = 16; // Pullable pub trait Pullable { type Item; fn pull(&mut self, buffer: &mut PushBuffer); fn buffered(self) -> PullBuffer where Self: Sized { PullBuffer::new(self) } fn transcode(self, encoding: E) -> Transcoder where Self: Sized, K: TranscoderKind, E: TranscoderImpl { Transcoder::new(encoding, self) } } impl Pullable for I where I: Iterator { type Item = I::Item; fn pull(&mut self, buffer: &mut PushBuffer) { while buffer.fits(1) { if let Some(x) = self.next() { buffer.push([ x ]); } else { break; } } } } // Pull Buffer pub struct PullBuffer where I: Pullable { inner: I, head: usize, tail: usize, buffer: [MaybeUninit; BUFFER_SIZE], } impl PullBuffer 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) } // TODO replace with `MaybeUninit::slice_assume_init()` once stabilized } 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 Iterator for PullBuffer where I: Pullable { type Item = I::Item; fn next(&mut self) -> Option { 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 Drop for PullBuffer 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; } } // Push Buffer pub struct PushBuffer<'a, T> { count: usize, buffer: &'a mut [MaybeUninit], } impl<'a, T> PushBuffer<'a, T> { pub fn new(buffer: &'a mut [MaybeUninit]) -> 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(&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; } } // Transcoder pub trait TranscoderKind { type Input; type Output; } pub trait TranscoderImpl where K: TranscoderKind, I: Pullable { fn transcode(&self, input: &mut PullBuffer, output: &mut PushBuffer); } pub struct Transcoder where K: TranscoderKind, I: Pullable, E: TranscoderImpl { encoding: E, input: PullBuffer, phantom: PhantomData, } impl Transcoder where K: TranscoderKind, I: Pullable, E: TranscoderImpl { pub fn new(encoding: E, input: I) -> Self { Self { encoding, input: input.buffered(), phantom: PhantomData } } } impl Pullable for Transcoder where K: TranscoderKind, I: Pullable, E: TranscoderImpl { type Item = K::Output; fn pull(&mut self, buffer: &mut PushBuffer) { self.encoding.transcode(&mut self.input, buffer) } } // Modules pub mod str; /* TODO // Dynamic Dispatch /// Any implementation of `Encoding` used for dynamic dispatch. pub type Any = dyn Encoding; /// Encoder using dynamic dispatch. pub type AnyEncoder<'a> = Encoder<'a, Any>; /// Decoder using dynamic dispatch. pub type AnyDecoder<'a> = Decoder<'a, Any>; impl Any { pub fn encoder<'a>(&'a self, text: &'a str) -> AnyEncoder<'a> { Encoder::new(self, text) } pub fn decoder<'a>(&'a self, bytes: &'a [u8]) -> AnyDecoder<'a> { Decoder::new(self, bytes) } } */