use std::borrow::Cow; use std::cmp::Ordering; use std::io; #[derive(Eq, Debug)] pub struct IOList { chunks: Vec>, len: usize, } impl IOList { pub fn new() -> Self { IOList { chunks: vec![], len: 0, } } fn rightmost_chunk(&mut self) -> &mut Vec { if self.chunks.is_empty() { self.chunks.push(vec![]); } 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(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>, chunk: Option>, } impl<'a> Iterator for IOListIterator<'a> { type Item = u8; fn next(&mut self) -> Option { 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 { Some(self.cmp(other)) } }