Skip to content

Commit

Permalink
Rename and refactor so we can return non-owning types
Browse files Browse the repository at this point in the history
  • Loading branch information
saethlin committed Oct 13, 2020
1 parent a2dac26 commit 3c2a4e6
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 82 deletions.
14 changes: 7 additions & 7 deletions examples/domain_name.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -31,8 +31,8 @@ pub struct DomainNameRef<'a> {
name: &'a [u8],
}

impl ErectFrom<DomainName> 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]]),
Expand All @@ -41,8 +41,8 @@ impl ErectFrom<DomainName> for DomainName {
}
}

impl FlattenInto<DomainName> for DomainNameRef<'_> {
fn flatten_into(&self, mut store: Storage) {
impl IntoFlat<DomainName> 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());
Expand Down
19 changes: 9 additions & 10 deletions examples/gzip.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
use flatvec::{ErectFrom, FlatVec, FlattenInto, Storage};
use libflate::gzip;
use flatvec::{FlatVec, FromFlat, IntoFlat, Storage};

fn main() {
let mut vec = FlatVec::new();
let data_to_insert = &b"ffffffffffffffffffffffffffffffffffffffffffffffffffff"[..];
println!("Original length: {}", data_to_insert.len());
vec.push(data_to_insert);
println!("Internal length: {}", vec.data_len());
let out: Vec<u8> = vec.pop().unwrap();
let out: Vec<u8> = 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<usize> {
self.0.extend(data.into_iter());
self.0.extend(data.iter());
Ok(data.len())
}

Expand All @@ -26,17 +25,17 @@ impl std::io::Write for WriteAdapter<'_> {

struct CompressedBytes(Vec<u8>);

impl FlattenInto<CompressedBytes> for [u8] {
fn flatten_into(&self, store: Storage) {
impl IntoFlat<CompressedBytes> 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();
encoder.finish().unwrap();
}
}

impl ErectFrom<CompressedBytes> for Vec<u8> {
fn erect_from(data: &[u8]) -> Self {
impl FromFlat<'_, CompressedBytes> for Vec<u8> {
fn from_flat(data: &[u8]) -> Self {
use std::io::Read;
let mut out = Vec::new();
libflate::gzip::Decoder::new(data)
Expand Down
113 changes: 48 additions & 65 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ impl<T> Default for FlatVec<T> {
}
}

impl<T> FlatVec<T> {
impl<'a, T: 'a> FlatVec<T> {
#[inline]
pub fn new() -> Self {
Self::default()
Expand All @@ -50,19 +50,6 @@ impl<T> FlatVec<T> {
self.ends.len() == 0
}

#[inline]
pub fn pop<Erected>(&mut self) -> Option<Erected>
where
Erected: ErectFrom<T>,
{
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];
Expand All @@ -74,24 +61,38 @@ impl<T> FlatVec<T> {
}

#[inline]
pub fn push<Source>(&mut self, input: &Source)
pub fn push<Source>(&mut self, input: Source)
where
Source: FlattenInto<T> + ?Sized,
Source: IntoFlat<T>,
{
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<Erected: ErectFrom<T>>(self) -> FlatVecIntoIter<Erected, T> {
FlatVecIntoIter {
inner: self,
cursor: 0,
marker: std::marker::PhantomData::default(),
}
pub fn get<Dest: 'a>(&'a self, index: usize) -> Option<Dest>
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<Dest: 'a>(&'a self) -> impl Iterator<Item = Dest> + '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<u8>);

impl Storage<'_> {
Expand All @@ -110,57 +111,39 @@ impl Storage<'_> {
}
}

pub trait FlattenInto<Flattened> {
fn flatten_into(&self, storage: Storage);
}

pub trait ErectFrom<Flattened> {
fn erect_from(data: &[u8]) -> Self;
pub trait IntoFlat<Flattened> {
fn into_flat(self, storage: &mut Storage);
}

pub struct FlatVecIntoIter<Erected, T> {
inner: FlatVec<T>,
cursor: usize,
marker: std::marker::PhantomData<Erected>,
pub trait FromFlat<'a, Flattened> {
fn from_flat(data: &'a [u8]) -> Self;
}

impl<Erected, T> Iterator for FlatVecIntoIter<Erected, T>
where
Erected: ErectFrom<T>,
{
type Item = Erected;

impl IntoFlat<String> for String {
#[inline]
fn next(&mut self) -> Option<Self::Item> {
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<String> 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<String> for String {
impl IntoFlat<String> 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<String> 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()
}
}

Expand All @@ -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::<String>(), None);
names.push("Jeslek".to_string());
assert_eq!(names.get(0), Some("Cerryl"));
assert_eq!(names.get(1), Some("Jeslek"));
assert_eq!(names.get::<String>(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::<String>().collect::<Vec<_>>();
names.push("Cerryl".to_string());
names.push("Jeslek".to_string());
let as_vec = names.iter::<String>().collect::<Vec<_>>();
assert_eq!(as_vec, vec!["Cerryl".to_string(), "Jeslek".to_string()]);
}
}

0 comments on commit 3c2a4e6

Please sign in to comment.