Skip to content

Commit

Permalink
Implement iterators for variable size array types
Browse files Browse the repository at this point in the history
  • Loading branch information
mbrobbel committed Jun 29, 2021
1 parent ba1138a commit 4f6e177
Show file tree
Hide file tree
Showing 8 changed files with 232 additions and 51 deletions.
11 changes: 1 addition & 10 deletions src/array/boolean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,6 @@ impl FromIterator<Option<bool>> for BooleanArray<true> {
}
}

impl<'a> FromIterator<&'a Option<bool>> for BooleanArray<true> {
fn from_iter<I>(iter: I) -> Self
where
I: IntoIterator<Item = &'a Option<bool>>,
{
Self(iter.into_iter().copied().collect())
}
}

impl<'a> IntoIterator for &'a BooleanArray<false> {
type Item = bool;
type IntoIter = <&'a Bitmap as IntoIterator>::IntoIter;
Expand Down Expand Up @@ -106,7 +97,7 @@ mod tests {
assert_eq!(vec, boolean_array.into_iter().collect::<Vec<bool>>());

let vec = vec![Some(false), Some(true), None, Some(true), None];
let boolean_array = vec.iter().collect::<BooleanArray<true>>();
let boolean_array = vec.iter().copied().collect::<BooleanArray<true>>();
assert_eq!(
vec,
boolean_array.into_iter().collect::<Vec<Option<bool>>>()
Expand Down
12 changes: 0 additions & 12 deletions src/array/fixed_size_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,18 +102,6 @@ where
}
}

impl<'a, T, const N: usize, const M: bool> IntoIterator for &'a FixedSizeListArray<T, N, M>
where
T: Array,
{
type Item = T; //[T; N];
type IntoIter = std::vec::IntoIter<T>;

fn into_iter(self) -> Self::IntoIter {
todo!()
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
9 changes: 3 additions & 6 deletions src/array/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,14 @@ mod r#struct;
pub use r#struct::*;

/// Types for which sequences of values can be stored in arrays.
pub trait ArrayType // where
// for<'a> &'a Self::Array: IntoIterator,
{
pub trait ArrayType {
/// Array type used for this type.
type Array: Array;
}

/// A sequence of values with known length all having the same type.
pub trait Array // where
// for<'a> &'a Self: IntoIterator,
{
// todo(mb): https://github.com/rust-lang/rust/issues/20671
pub trait Array {
/// [Validity](crate::Validity) of the array.
// todo(mb): GATs
type Validity: ArrayData;
Expand Down
108 changes: 108 additions & 0 deletions src/array/variable_size_binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,84 @@ where
}
}

/// Iterator over elements of an array with variable-sized binary data.
pub struct VariableSizeBinaryArrayIter<'a, T, const N: bool>
where
T: OffsetValue,
&'a Offset<T, N>: IntoIterator,
{
data: &'a [u8],
offset: <&'a Offset<T, N> as IntoIterator>::IntoIter,
}

impl<'a, T> Iterator for VariableSizeBinaryArrayIter<'a, T, false>
where
T: OffsetValue,
&'a Offset<T, false>: IntoIterator<Item = (usize, usize)>,
{
type Item = &'a [u8];

fn next(&mut self) -> Option<Self::Item> {
self.offset
.next()
.map(|(start, end)| &self.data[start..end])
}

fn size_hint(&self) -> (usize, Option<usize>) {
self.offset.size_hint()
}
}

impl<'a, T> IntoIterator for &'a VariableSizeBinaryArray<T, false>
where
T: OffsetValue,
&'a Offset<T, false>: IntoIterator<Item = (usize, usize)>,
{
type Item = &'a [u8];
type IntoIter = VariableSizeBinaryArrayIter<'a, T, false>;

fn into_iter(self) -> Self::IntoIter {
VariableSizeBinaryArrayIter {
data: &self.data,
offset: self.offset.into_iter(),
}
}
}

impl<'a, T> Iterator for VariableSizeBinaryArrayIter<'a, T, true>
where
T: OffsetValue,
&'a Offset<T, true>: IntoIterator<Item = Option<(usize, usize)>>,
{
type Item = Option<&'a [u8]>;

fn next(&mut self) -> Option<Self::Item> {
self.offset
.next()
.map(|opt| opt.map(|(start, end)| &self.data[start..end]))
}

fn size_hint(&self) -> (usize, Option<usize>) {
self.offset.size_hint()
}
}

impl<'a, T> IntoIterator for &'a VariableSizeBinaryArray<T, true>
where
T: OffsetValue,
&'a Offset<T, true>: IntoIterator<Item = Option<(usize, usize)>>,
{
type Item = Option<&'a [u8]>;
type IntoIter = VariableSizeBinaryArrayIter<'a, T, true>;

fn into_iter(self) -> Self::IntoIter {
VariableSizeBinaryArrayIter {
data: &self.data,
offset: self.offset.into_iter(),
}
}
}

/// Array with variable sized binary data. Uses [i32] offsets.
pub type BinaryArray<const N: bool> = VariableSizeBinaryArray<i32, N>;

Expand Down Expand Up @@ -139,4 +217,34 @@ mod tests {
let array = vec.into_iter().collect::<LargeBinaryArray<true>>();
assert_eq!(array.len(), 6);
}

#[test]
fn into_iter() {
let x = vec![1u8, 2, 3, 4, 5];
let y = vec![1u8, 2, 3, 4];
let z = vec![1u8, 2, 3];
let vec = vec![&x[..], &y, &z];

let array = vec.iter().collect::<BinaryArray<false>>();
let mut iter = array.into_iter();
assert_eq!(iter.size_hint(), (3, Some(3)));
assert_eq!(iter.next(), Some(&x[..]));
assert_eq!(iter.next(), Some(&y[..]));
assert_eq!(iter.next(), Some(&z[..]));
assert_eq!(iter.next(), None);

let x = vec![1u8, 2, 3, 4, 5];
let y = vec![1u8, 2, 3, 4];
let vec = vec![Some(&x[..]), Some(&y), None, None, Some(&x), Some(&[])];
let array = vec.into_iter().collect::<LargeBinaryArray<true>>();
let mut iter = array.into_iter();
assert_eq!(iter.size_hint(), (6, Some(6)));
assert_eq!(iter.next(), Some(Some(&x[..])));
assert_eq!(iter.next(), Some(Some(&y[..])));
assert_eq!(iter.next(), Some(None));
assert_eq!(iter.next(), Some(None));
assert_eq!(iter.next(), Some(Some(&x[..])));
assert_eq!(iter.next(), Some(Some(&[] as &[u8])));
assert_eq!(iter.next(), None);
}
}
111 changes: 110 additions & 1 deletion src/array/variable_size_list.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{Array, ArrayType, NestedArray, Offset, OffsetValue, Uint8Array};
use std::iter::FromIterator;
use std::iter::{FromIterator, Skip, Take};

/// Array with variable-sized lists of other array types.
///
Expand Down Expand Up @@ -143,6 +143,85 @@ where
}
}

pub struct VariableSizeListArrayIter<'a, T, U, const N: bool>
where
U: OffsetValue,
&'a Offset<U, N>: IntoIterator,
{
data: &'a T,
offset: <&'a Offset<U, N> as IntoIterator>::IntoIter,
}

impl<'a, T, U> Iterator for VariableSizeListArrayIter<'a, T, U, false>
where
&'a T: IntoIterator,
U: OffsetValue,
{
type Item = Take<Skip<<&'a T as IntoIterator>::IntoIter>>;

fn next(&mut self) -> Option<Self::Item> {
self.offset
.next()
.map(|(start, end)| self.data.into_iter().skip(start).take(end - start))
}

fn size_hint(&self) -> (usize, Option<usize>) {
self.offset.size_hint()
}
}

impl<'a, T, U> IntoIterator for &'a VariableSizeListArray<T, U, false>
where
T: Array,
&'a T: IntoIterator,
U: OffsetValue,
{
type Item = Take<Skip<<&'a T as IntoIterator>::IntoIter>>;
type IntoIter = VariableSizeListArrayIter<'a, T, U, false>;

fn into_iter(self) -> Self::IntoIter {
VariableSizeListArrayIter {
data: &self.data,
offset: self.offset.into_iter(),
}
}
}

impl<'a, T, U> Iterator for VariableSizeListArrayIter<'a, T, U, true>
where
&'a T: IntoIterator,
U: OffsetValue,
{
type Item = Option<Take<Skip<<&'a T as IntoIterator>::IntoIter>>>;

fn next(&mut self) -> Option<Self::Item> {
self.offset
.next()
.map(|opt| opt.map(|(start, end)| self.data.into_iter().skip(start).take(end - start)))
}

fn size_hint(&self) -> (usize, Option<usize>) {
self.offset.size_hint()
}
}

impl<'a, T, U> IntoIterator for &'a VariableSizeListArray<T, U, true>
where
T: Array,
&'a T: IntoIterator,
U: OffsetValue,
{
type Item = Option<Take<Skip<<&'a T as IntoIterator>::IntoIter>>>;
type IntoIter = VariableSizeListArrayIter<'a, T, U, true>;

fn into_iter(self) -> Self::IntoIter {
VariableSizeListArrayIter {
data: &self.data,
offset: self.offset.into_iter(),
}
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -202,4 +281,34 @@ mod tests {
assert_eq!(list.child().len(), 6);
assert_eq!(list.child().data().len(), 24);
}

#[test]
fn into_iter() {
let x = vec![1u32, 2, 3, 4];
let y = vec![1u32, 2, 3, 4, 5];
let vec = vec![x.clone(), y.clone()];
let list: ListArray<Uint32Array<false>, false> = vec.into_iter().collect();
let mut iter = list.into_iter();
assert_eq!(iter.size_hint(), (2, Some(2)));
assert_eq!(iter.next().unwrap().collect::<Vec<_>>(), x);
assert_eq!(iter.next().unwrap().collect::<Vec<_>>(), y);
assert!(iter.next().is_none());

let vec = vec![vec![x.clone(), y.clone()]];
let list: ListArray<ListArray<Uint32Array<false>, false>, false> =
vec.clone().into_iter().collect();
assert_eq!(
list.into_iter().flatten().flatten().collect::<Vec<_>>(),
vec[0].iter().flatten().copied().collect::<Vec<_>>()
);

let vec = vec![Some(x.clone()), None, Some(y.clone())];
let list: ListArray<Uint32Array<false>, true> = vec.into_iter().collect();
let mut iter = list.into_iter();
assert_eq!(iter.size_hint(), (3, Some(3)));
assert_eq!(iter.next().unwrap().unwrap().collect::<Vec<_>>(), x);
assert!(iter.next().unwrap().is_none());
assert_eq!(iter.next().unwrap().unwrap().collect::<Vec<_>>(), y);
assert!(iter.next().is_none());
}
}
19 changes: 1 addition & 18 deletions src/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,23 +54,6 @@ impl<T, const A: usize> Buffer<T, A>
where
T: Primitive,
{
/// Extracts a slice containing the entire buffer.
///
/// Equivalent to `&buffer[..]`.
///
/// # Examples
///
/// ```
/// use narrow::Buffer;
///
/// let buffer: Buffer<_, 3> = [1u8, 2, 3, 4].iter().copied().collect();
///
/// assert_eq!(buffer.as_slice(), &buffer[..]);
/// ```
pub fn as_slice(&self) -> &[T] {
&self
}

/// Returns an new Buffer.
/// todo(mb): document safety issues
pub(crate) unsafe fn new_unchecked(ptr: *mut T, len: usize) -> Self {
Expand Down Expand Up @@ -196,7 +179,7 @@ where
T: Primitive,
{
fn clone(&self) -> Self {
Self::from_slice(self.as_slice())
Self::from_slice(self)
}
}

Expand Down
8 changes: 6 additions & 2 deletions src/offset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ where
}
}

/// Iterator over offsets values.
/// Iterator over offsets values of variable sized arrays.
pub struct OffsetIter<T, const N: bool> {
pos: Option<usize>,
iter: T,
Expand Down Expand Up @@ -203,6 +203,10 @@ where
}),
)
}

fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}

impl<'a, T> IntoIterator for &'a Offset<T, false>
Expand Down Expand Up @@ -266,7 +270,7 @@ mod tests {
assert_eq!(&offset[..], &[0, 1, 3, 6, 10]);

let offset: Offset<i32, true> = [Some(3), None, Some(4), Some(0)].iter().copied().collect();
assert_eq!(offset.data().as_slice(), &[0, 3, 3, 7, 7]);
assert_eq!(&offset.data()[..], &[0, 3, 3, 7, 7]);
}

#[test]
Expand Down
5 changes: 3 additions & 2 deletions src/validity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ where
_ => unsafe { unreachable_unchecked() },
}
}

fn is_null(&self, index: usize) -> bool {
match (N, &self.0) {
(false, _) => false,
Expand Down Expand Up @@ -174,13 +175,13 @@ mod tests {
#[test]
fn data() {
let valid: Validity<Buffer<_, ALIGNMENT>, false> = vec![1u8, 2, 3, 4].into_iter().collect();
assert_eq!(valid.data().as_slice(), &[1, 2, 3, 4]);
assert_eq!(&valid.data()[..], &[1, 2, 3, 4]);

let nullable: Validity<Buffer<_, ALIGNMENT>, true> =
vec![Some(1u8), None, Some(3), Some(4)]
.into_iter()
.collect();
assert_eq!(nullable.data().as_slice(), &[1, u8::default(), 3, 4]);
assert_eq!(&nullable.data()[..], &[1, u8::default(), 3, 4]);
}

#[test]
Expand Down

0 comments on commit 4f6e177

Please sign in to comment.