diff --git a/examples/domain_name.rs b/examples/domain_name.rs index 6dcbc82..0e8b52b 100644 --- a/examples/domain_name.rs +++ b/examples/domain_name.rs @@ -1,14 +1,14 @@ -use flatvec::{ErectFrom, FlatVec, FlattenInto, Storage}; +use flatvec::{FlatVec, FromFlat, IntoFlat, Storage}; fn main() { let mut names = FlatVec::new(); - names.push(&DomainNameRef { + names.push(DomainNameRef { ttl: 60, time_seen: 31415, name: &b"google.com"[..], }); assert_eq!( - names.pop(), + names.get(0), Some(DomainName { ttl: 60, time_seen: 31415, @@ -31,8 +31,8 @@ pub struct DomainNameRef<'a> { name: &'a [u8], } -impl ErectFrom for DomainName { - fn erect_from(data: &[u8]) -> Self { +impl FromFlat<'_, DomainName> for DomainName { + fn from_flat(data: &[u8]) -> Self { Self { time_seen: u32::from_ne_bytes([data[0], data[1], data[2], data[3]]), ttl: u32::from_ne_bytes([data[4], data[5], data[6], data[7]]), @@ -41,8 +41,8 @@ impl ErectFrom for DomainName { } } -impl FlattenInto for DomainNameRef<'_> { - fn flatten_into(&self, mut store: Storage) { +impl IntoFlat for DomainNameRef<'_> { + fn into_flat(self, store: &mut Storage) { store.reserve(self.name.len() + 8); store.extend(&self.time_seen.to_ne_bytes()); store.extend(&self.ttl.to_ne_bytes()); diff --git a/examples/gzip.rs b/examples/gzip.rs index 80ef344..64040e4 100644 --- a/examples/gzip.rs +++ b/examples/gzip.rs @@ -1,5 +1,4 @@ -use flatvec::{ErectFrom, FlatVec, FlattenInto, Storage}; -use libflate::gzip; +use flatvec::{FlatVec, FromFlat, IntoFlat, Storage}; fn main() { let mut vec = FlatVec::new(); @@ -7,15 +6,15 @@ fn main() { println!("Original length: {}", data_to_insert.len()); vec.push(data_to_insert); println!("Internal length: {}", vec.data_len()); - let out: Vec = vec.pop().unwrap(); + let out: Vec = vec.get(0).unwrap(); assert_eq!(&out, &data_to_insert); } -struct WriteAdapter<'a>(Storage<'a>); +struct WriteAdapter<'a, 'b>(&'a mut Storage<'b>); -impl std::io::Write for WriteAdapter<'_> { +impl std::io::Write for WriteAdapter<'_, '_> { fn write(&mut self, data: &[u8]) -> std::io::Result { - self.0.extend(data.into_iter()); + self.0.extend(data.iter()); Ok(data.len()) } @@ -26,8 +25,8 @@ impl std::io::Write for WriteAdapter<'_> { struct CompressedBytes(Vec); -impl FlattenInto for [u8] { - fn flatten_into(&self, store: Storage) { +impl IntoFlat for &[u8] { + fn into_flat(self, store: &mut Storage) { use std::io::Write; let mut encoder = libflate::gzip::Encoder::new(WriteAdapter(store)).unwrap(); encoder.write_all(&self).unwrap(); @@ -35,8 +34,8 @@ impl FlattenInto for [u8] { } } -impl ErectFrom for Vec { - fn erect_from(data: &[u8]) -> Self { +impl FromFlat<'_, CompressedBytes> for Vec { + fn from_flat(data: &[u8]) -> Self { use std::io::Read; let mut out = Vec::new(); libflate::gzip::Decoder::new(data) diff --git a/src/lib.rs b/src/lib.rs index 5f4c5be..6f75931 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,7 +29,7 @@ impl Default for FlatVec { } } -impl FlatVec { +impl<'a, T: 'a> FlatVec { #[inline] pub fn new() -> Self { Self::default() @@ -50,19 +50,6 @@ impl FlatVec { self.ends.len() == 0 } - #[inline] - pub fn pop(&mut self) -> Option - where - Erected: ErectFrom, - { - let end = *self.ends.last()?; - let start = *self.ends.iter().rev().nth(1).unwrap_or(&0); - let output = Erected::erect_from(&self.data[start..end]); - self.data.truncate(start); - self.ends.pop(); - Some(output) - } - #[inline] pub fn remove(&mut self, index: usize) { let end = self.ends[index]; @@ -74,24 +61,38 @@ impl FlatVec { } #[inline] - pub fn push(&mut self, input: &Source) + pub fn push(&mut self, input: Source) where - Source: FlattenInto + ?Sized, + Source: IntoFlat, { - input.flatten_into(Storage(&mut self.data)); + input.into_flat(&mut Storage(&mut self.data)); self.ends.push(self.data.len()); } #[inline] - pub fn into_iter>(self) -> FlatVecIntoIter { - FlatVecIntoIter { - inner: self, - cursor: 0, - marker: std::marker::PhantomData::default(), - } + pub fn get(&'a self, index: usize) -> Option + where + Dest: FromFlat<'a, T>, + { + let end = *self.ends.get(index)?; + let start = if index == 0 { 0 } else { self.ends[index - 1] }; + Some(Dest::from_flat(&self.data[start..end])) + } + + #[inline] + pub fn iter(&'a self) -> impl Iterator + 'a + where + Dest: FromFlat<'a, T>, + { + std::iter::once(&0usize) + .chain(self.ends.iter()) + .zip(self.ends.iter()) + .map(move |(&start, &end)| Dest::from_flat(&self.data[start..end])) } } +/// A wrapper over the innards of a `FlatVec` which exposes mutating operations which cannot +/// corrupt other elements during a push pub struct Storage<'a>(&'a mut Vec); impl Storage<'_> { @@ -110,57 +111,39 @@ impl Storage<'_> { } } -pub trait FlattenInto { - fn flatten_into(&self, storage: Storage); -} - -pub trait ErectFrom { - fn erect_from(data: &[u8]) -> Self; +pub trait IntoFlat { + fn into_flat(self, storage: &mut Storage); } -pub struct FlatVecIntoIter { - inner: FlatVec, - cursor: usize, - marker: std::marker::PhantomData, +pub trait FromFlat<'a, Flattened> { + fn from_flat(data: &'a [u8]) -> Self; } -impl Iterator for FlatVecIntoIter -where - Erected: ErectFrom, -{ - type Item = Erected; - +impl IntoFlat for String { #[inline] - fn next(&mut self) -> Option { - let end = *self.inner.ends.get(self.cursor)?; - let start = if self.cursor == 0 { - 0 - } else { - self.inner.ends[self.cursor - 1] - }; - self.cursor += 1; - Some(Erected::erect_from(&self.inner.data[start..end])) + fn into_flat(self, store: &mut Storage) { + store.extend(self.bytes()); } } -impl FlattenInto for String { +impl FromFlat<'_, String> for String { #[inline] - fn flatten_into(&self, mut store: Storage<'_>) { - store.extend(self.bytes()); + fn from_flat(data: &[u8]) -> Self { + String::from_utf8(data.to_vec()).unwrap() } } -impl ErectFrom for String { +impl IntoFlat for &str { #[inline] - fn erect_from(data: &[u8]) -> Self { - String::from_utf8(data.to_vec()).unwrap() + fn into_flat(self, store: &mut Storage) { + store.extend(self.bytes()); } } -impl FlattenInto for str { +impl<'a> FromFlat<'a, String> for &'a str { #[inline] - fn flatten_into(&self, mut store: Storage<'_>) { - store.extend(self.bytes()); + fn from_flat(data: &'a [u8]) -> &'a str { + std::str::from_utf8(&data).unwrap() } } @@ -169,21 +152,21 @@ mod tests { use super::*; #[test] - fn push_pop() { + fn push_get() { let mut names = FlatVec::new(); names.push("Cerryl"); - names.push(&"Jeslek".to_string()); - assert_eq!(names.pop(), Some("Jeslek".to_string())); - assert_eq!(names.pop(), Some("Cerryl".to_string())); - assert_eq!(names.pop::(), None); + names.push("Jeslek".to_string()); + assert_eq!(names.get(0), Some("Cerryl")); + assert_eq!(names.get(1), Some("Jeslek")); + assert_eq!(names.get::(2), None); } #[test] fn iter() { let mut names = FlatVec::new(); - names.push(&"Cerryl".to_string()); - names.push(&"Jeslek".to_string()); - let as_vec = names.into_iter::().collect::>(); + names.push("Cerryl".to_string()); + names.push("Jeslek".to_string()); + let as_vec = names.iter::().collect::>(); assert_eq!(as_vec, vec!["Cerryl".to_string(), "Jeslek".to_string()]); } }