mchr 0.1.6

Lenient implementations of encodings. Zero allocations, zero dependencies!
Documentation

use std::marker::PhantomData;

const BUFFER_SIZE: usize = 16;

// Pullable

pub trait Pullable {
	type Item;
	fn pull(&mut self, buffer: &mut [Self::Item]) -> usize;
	
	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)
	}
	
	fn iter(self) -> PullableIterator<Self> where Self: Sized, Self::Item: Default {
		PullableIterator::new(self)
	}
}

impl<I> Pullable for I where I: Iterator {
	type Item = I::Item;
	fn pull(&mut self, buffer: &mut [Self::Item]) -> usize {
		let mut count = 0;
		while count < buffer.len() {
			if let Some(x) = self.next() {
				buffer[count] = x;
				count += 1;
			} else {
				break;
			}
		}
		count
	}
}

// Pullable Iterator

pub struct PullableIterator<I> where I: Pullable {
	inner: I,
	buffer: [I::Item; BUFFER_SIZE],
	index: usize,
	count: usize,
}

impl<I> PullableIterator<I> where I: Pullable, I::Item: Default { // TODO relax this
	pub fn new(inner: I) -> Self {
		Self { inner, buffer: std::array::from_fn(|_| I::Item::default()), index: 0, count: 0 }
	}
}

impl<I> Iterator for PullableIterator<I> where I: Pullable, I::Item: Default { // TODO relax this
	type Item = I::Item;
	fn next(&mut self) -> Option<Self::Item> {
		if self.index >= self.count {
			self.index = 0;
			self.count = self.inner.pull(&mut self.buffer);
		}
		if self.index < self.count {
			let item = std::mem::take(&mut self.buffer[self.index]);
			self.index += 1;
			Some(item)
		} else {
			None
		}
	}
}

// Pull Buffer

#[derive(Clone)]
pub struct PullBuffer<I> where I: Pullable {
	inner: I,
	head: usize,
	tail: usize,
	buffer: [I::Item; BUFFER_SIZE],
}

impl<I> PullBuffer<I> where I: Pullable {
	pub fn new(inner: I) -> Self where I::Item: Default { // TODO relax this
		Self { inner, head: 0, tail: 0, buffer: std::array::from_fn(|_| I::Item::default()) }
	}
	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;
			}
			self.tail += self.inner.pull(&mut self.buffer[self.tail..]);
		}
		&self.buffer[self.head..self.tail.min(self.head + amount)]
	}
	pub fn advance(&mut self, amount: usize) {
		self.head += amount;
		assert!(self.head <= self.tail);
	}
}

// Push Buffer

pub struct PushBuffer<'a, T> {
	count: usize,
	buffer: &'a mut [T],
}

impl<'a, T> PushBuffer<'a, T> {
	pub fn new(buffer: &'a mut [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] = x;
		}
		self.count += N;
	}
}

// Transcoder

pub trait TranscoderKind {
	type Input: Default; // TODO relax this
	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: PullBuffer::new(input), 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 [Self::Item]) -> usize {
		let mut buf = PushBuffer::new(buffer);
		self.encoding.transcode(&mut self.input, &mut buf);
		buf.len()
	}
}

// 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) }
}
*/