preserves/implementations/rust/preserves/src/value/iolist.rs

134 lines
3.2 KiB
Rust

use std::borrow::Cow;
use std::cmp::Ordering;
use std::io;
#[derive(Eq, Debug)]
pub struct IOList {
chunks: Vec<Vec<u8>>,
len: usize,
}
impl IOList {
pub fn new() -> Self {
IOList {
chunks: Vec::with_capacity(5),
len: 0,
}
}
fn rightmost_chunk(&mut self) -> &mut Vec<u8> {
if self.chunks.is_empty() {
self.chunks.push(Vec::with_capacity(64))
}
self.chunks.last_mut().unwrap()
}
pub fn len(&self) -> usize {
self.len
}
pub fn write(&mut self, b: u8) {
self.rightmost_chunk().push(b);
self.len += 1;
}
#[inline(always)]
pub fn write_all(&mut self, cow: Cow<'_, [u8]>) {
self.len += cow.len();
match cow {
Cow::Borrowed(bs) => self.rightmost_chunk().extend_from_slice(bs),
Cow::Owned(bs) => self.chunks.push(bs),
}
}
pub fn append(&mut self, mut iol: IOList) {
self.len += iol.len();
self.chunks.append(&mut iol.chunks);
}
pub fn write_to<W: io::Write>(self, mut w: W) -> io::Result<()> {
for chunk in self.chunks {
w.write_all(&chunk)?;
}
Ok(())
}
pub fn iter<'a>(&'a self) -> IOListIterator<'a> {
IOListIterator { chunks: self.chunks.iter(), chunk: None }
}
}
pub struct IOListIterator<'a> {
chunks: std::slice::Iter<'a, Vec<u8>>,
chunk: Option<std::slice::Iter<'a, u8>>,
}
impl<'a> Iterator for IOListIterator<'a> {
type Item = u8;
fn next(&mut self) -> Option<Self::Item> {
loop {
if self.chunk.is_none() {
self.chunk = self.chunks.next().map(|v| v.iter());
if self.chunk.is_none() {
return None;
}
}
match self.chunk.as_mut().unwrap().next() {
None => {
self.chunk = None;
continue;
}
Some(b) => return Some(*b),
}
}
}
}
impl<'a> IntoIterator for &'a IOList {
type Item = u8;
type IntoIter = IOListIterator<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl std::cmp::PartialEq for IOList {
fn eq(&self, other: &Self) -> bool {
let mut a = self.iter();
let mut b = other.iter();
loop {
let v = a.next();
if v != b.next() {
return false;
}
if v.is_none() {
return true;
}
}
}
}
impl std::cmp::Ord for IOList {
fn cmp(&self, other: &Self) -> Ordering {
let mut a = self.iter();
let mut b = other.iter();
loop {
match (a.next(), b.next()) {
(None, None) => return Ordering::Equal,
(Some(av), Some(bv)) => match av.cmp(&bv) {
Ordering::Equal => continue,
other => return other,
},
(Some(_), None) => return Ordering::Greater,
(None, Some(_)) => return Ordering::Less,
}
}
}
}
impl PartialOrd for IOList {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}