134 lines
3.2 KiB
Rust
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.chunks.push(bs.to_owned()),
|
|
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))
|
|
}
|
|
}
|