diff --git a/implementations/rust/preserves/src/value/iolist.rs b/implementations/rust/preserves/src/value/iolist.rs index ca31bad..6a7e5da 100644 --- a/implementations/rust/preserves/src/value/iolist.rs +++ b/implementations/rust/preserves/src/value/iolist.rs @@ -1,37 +1,29 @@ use std::borrow::Cow; -use std::cell::RefCell; +use std::cmp::Ordering; use std::io; #[derive(Eq, Debug)] pub struct IOList { - chunks: RefCell>>, + chunks: Vec>, len: usize, } impl IOList { pub fn new() -> Self { IOList { - chunks: RefCell::new(Vec::new()), + chunks: vec![], len: 0, } } fn rightmost_chunk(&mut self) -> &mut Vec { - let cs = self.chunks.get_mut(); - if cs.is_empty() { - cs.push(Vec::new()); + if self.chunks.is_empty() { + self.chunks.push(vec![]); } - cs.last_mut().unwrap() + self.chunks.last_mut().unwrap() } - fn consolidate(&self) { - if self.chunks.borrow().len() != 1 { - let bs = self.chunks.replace(Vec::new()).concat(); - self.chunks.borrow_mut().push(bs); - } - } - - pub fn len(&mut self) -> usize { + pub fn len(&self) -> usize { self.len } @@ -44,41 +36,97 @@ impl IOList { pub fn write_all(&mut self, cow: Cow<'_, [u8]>) { self.len += cow.len(); match cow { - Cow::Borrowed(bs) => self.chunks.get_mut().push(bs.to_owned()), - Cow::Owned(bs) => self.chunks.get_mut().push(bs), + 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.get_mut().append(&mut iol.chunks.take()); + self.chunks.append(&mut iol.chunks); } pub fn write_to(self, mut w: W) -> io::Result<()> { - for chunk in self.chunks.take() { + 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 { - self.consolidate(); - other.consolidate(); - self.chunks.borrow().last().unwrap() == other.chunks.borrow().last().unwrap() + 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) -> std::cmp::Ordering { - self.consolidate(); - other.consolidate(); - self.chunks.borrow().last().unwrap().cmp(other.chunks.borrow().last().unwrap()) + 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 std::cmp::PartialOrd for IOList { +impl PartialOrd for IOList { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } diff --git a/implementations/rust/preserves/src/value/packed/writer.rs b/implementations/rust/preserves/src/value/packed/writer.rs index 8933cf5..e71c8e2 100644 --- a/implementations/rust/preserves/src/value/packed/writer.rs +++ b/implementations/rust/preserves/src/value/packed/writer.rs @@ -89,7 +89,7 @@ impl PackedWriter { pub fn finish_item(&mut self) -> io::Result<()> { if self.buffer.len() > 0 { - let mut buffer = std::mem::replace(&mut self.buffer, IOList::new()); + let buffer = std::mem::replace(&mut self.buffer, IOList::new()); match self.items.last_mut() { Some(iols) => iols.push(buffer), None => { @@ -127,7 +127,7 @@ impl PackedWriter { items.sort(); } self.write_tag(tag); - for mut i in items { + for i in items { varint(&mut self.buffer, i.len()); self.buffer.append(i); } @@ -409,7 +409,7 @@ impl Writer for PackedWriter } chunks.sort(); self.write_tag(Tag::Dictionary); - for (mut ki, mut vi) in chunks { + for (ki, vi) in chunks { varint(&mut self.buffer, ki.len()); self.buffer.append(ki); varint(&mut self.buffer, vi.len());