From 7350c003480546bade522c49acc28303cb1809b4 Mon Sep 17 00:00:00 2001 From: novacrazy Date: Sun, 4 Mar 2018 22:37:29 -0600 Subject: [PATCH 1/8] Add vscode directory to gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index ac98a7d842..5293c63cdd 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ *.rlib *.dll +.vscode + # Executables *.exe From cd578bc297d8585631797d4fb9dac150b6b7e03b Mon Sep 17 00:00:00 2001 From: novacrazy Date: Sun, 4 Mar 2018 22:37:45 -0600 Subject: [PATCH 2/8] Implement new functional system --- src/functional.rs | 69 ++++++++++++++ src/impls.rs | 7 +- src/iter.rs | 29 ++++-- src/lib.rs | 232 +++++++++++++++++++++++++--------------------- src/sequence.rs | 51 ++++++++-- tests/mod.rs | 18 +++- tests/std.rs | 23 +++++ 7 files changed, 302 insertions(+), 127 deletions(-) create mode 100644 src/functional.rs create mode 100644 tests/std.rs diff --git a/src/functional.rs b/src/functional.rs new file mode 100644 index 0000000000..38f727d11f --- /dev/null +++ b/src/functional.rs @@ -0,0 +1,69 @@ +//! Functional programming with generic sequences + +use core::iter::FromIterator; + +use super::ArrayLength; +use sequence::*; + +/// Defines the relationship between one generic sequence and another, +/// for operations such as `map` and `zip`. +pub unsafe trait MappedGenericSequence: GenericSequence +where + Self::Length: ArrayLength, +{ + /// Mapped sequence type + type Mapped: GenericSequence; +} + +unsafe impl<'a, T, U, S: MappedGenericSequence> MappedGenericSequence for &'a S +where + &'a S: GenericSequence, + S: GenericSequence>::Length>, + >::Length: ArrayLength, +{ + type Mapped = >::Mapped; +} + +/// Accessor type for a mapped generic sequence +pub type MappedSequence = <>::Mapped as GenericSequence>::Sequence; + +/// Defines functional programming methods for generic sequences +pub unsafe trait FunctionalSequence: GenericSequence { + /// Maps a `GenericSequence` to another `GenericSequence`. + /// + /// If the mapping function panics, any already initialized elements in the new sequence + /// will be dropped, AND any unused elements in the source sequence will also be dropped. + fn map(self, f: F) -> MappedSequence + where + Self: MappedGenericSequence, + Self::Length: ArrayLength, + F: Fn(SequenceItem) -> U, + { + FromIterator::from_iter(self.into_iter().map(f)) + } + + /// Combines two `GenericSequence` instances and iterates through both of them, + /// initializing a new `GenericSequence` with the result of the zipped mapping function. + /// + /// If the mapping function panics, any already initialized elements in the new sequence + /// will be dropped, AND any unused elements in the source sequences will also be dropped. + fn zip(self, rhs: Rhs, f: F) -> MappedSequence + where + Self: MappedGenericSequence, + Self::Length: ArrayLength + ArrayLength, + Rhs: GenericSequence, + F: Fn(SequenceItem, SequenceItem) -> U, + { + FromIterator::from_iter(self.into_iter().zip(rhs.into_iter()).map(|(l, r)| f(l, r) )) + } +} + +unsafe impl<'a, T, S: GenericSequence> FunctionalSequence for &'a S +where + &'a S: GenericSequence, +{} + +unsafe impl<'a, T, S: GenericSequence> FunctionalSequence for &'a mut S +where + &'a mut S: GenericSequence, +{} \ No newline at end of file diff --git a/src/impls.rs b/src/impls.rs index 8aa0b4675b..c439f591ee 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -1,9 +1,12 @@ -use super::{ArrayLength, GenericArray}; use core::borrow::{Borrow, BorrowMut}; use core::cmp::Ordering; use core::fmt::{self, Debug}; use core::hash::{Hash, Hasher}; +use super::{ArrayLength, GenericArray}; +use sequence::*; +use functional::*; + impl Default for GenericArray where N: ArrayLength, @@ -19,7 +22,7 @@ where N: ArrayLength, { fn clone(&self) -> GenericArray { - self.map_ref(|x| x.clone()) + self.map(|x| x.clone()) } } diff --git a/src/iter.rs b/src/iter.rs index b9282761a4..9ea49796b1 100644 --- a/src/iter.rs +++ b/src/iter.rs @@ -14,6 +14,9 @@ pub struct GenericArrayIter> { index_back: usize, } +unsafe impl> Send for GenericArrayIter {} +unsafe impl> Sync for GenericArrayIter {} + impl IntoIterator for GenericArray where N: ArrayLength, @@ -34,6 +37,7 @@ impl Drop for GenericArrayIter where N: ArrayLength, { + #[inline] fn drop(&mut self) { // Drop values that are still alive. for p in &mut self.array[self.index..self.index_back] { @@ -50,23 +54,28 @@ where { type Item = T; + #[inline] fn next(&mut self) -> Option { - if self.len() > 0 { - unsafe { - let p = self.array.get_unchecked(self.index); - self.index += 1; - Some(ptr::read(p)) - } + if self.index < self.index_back { + let p = unsafe { + Some(ptr::read(self.array.get_unchecked(self.index))) + }; + + self.index += 1; + + p } else { None } } + #[inline] fn size_hint(&self) -> (usize, Option) { let len = self.len(); (len, Some(len)) } + #[inline] fn count(self) -> usize { self.len() } @@ -95,11 +104,11 @@ where N: ArrayLength, { fn next_back(&mut self) -> Option { - if self.len() > 0 { + if self.index < self.index_back { self.index_back -= 1; + unsafe { - let p = self.array.get_unchecked(self.index_back); - Some(ptr::read(p)) + Some(ptr::read(self.array.get_unchecked(self.index_back))) } } else { None @@ -114,4 +123,4 @@ where fn len(&self) -> usize { self.index_back - self.index } -} +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index f340885c99..d3df3869d9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,6 +53,7 @@ use core::{mem, ptr, slice}; use core::marker::PhantomData; use core::mem::ManuallyDrop; use core::ops::{Deref, DerefMut}; +use core::iter::FromIterator; use typenum::bit::{B0, B1}; use typenum::uint::{UInt, UTerm, Unsigned}; @@ -60,6 +61,10 @@ use typenum::uint::{UInt, UTerm, Unsigned}; pub mod arr; pub mod iter; pub mod sequence; +pub mod functional; + +use sequence::*; +use functional::*; pub use iter::GenericArrayIter; @@ -134,6 +139,9 @@ pub struct GenericArray> { data: U::ArrayType, } +unsafe impl> Send for GenericArray {} +unsafe impl> Sync for GenericArray {} + impl Deref for GenericArray where N: ArrayLength, @@ -210,121 +218,144 @@ impl> Drop for ArrayConsumer { } } -impl GenericArray +impl<'a, T: 'a, N> IntoIterator for &'a GenericArray +where + N: ArrayLength +{ + type IntoIter = slice::Iter<'a, T>; + type Item = &'a T; + + fn into_iter(self: &'a GenericArray) -> Self::IntoIter { + self.as_slice().iter() + } +} + +impl<'a, T: 'a, N> IntoIterator for &'a mut GenericArray +where + N: ArrayLength +{ + type IntoIter = slice::IterMut<'a, T>; + type Item = &'a mut T; + + fn into_iter(self: &'a mut GenericArray) -> Self::IntoIter { + self.as_mut_slice().iter_mut() + } +} + +impl FromIterator for GenericArray where N: ArrayLength, { - /// Initializes a new `GenericArray` instance using the given function. - /// - /// If the generator function panics while initializing the array, - /// any already initialized elements will be dropped. - pub fn generate(f: F) -> GenericArray + fn from_iter(iter: I) -> GenericArray where - F: Fn(usize) -> T, + I: IntoIterator, { let mut destination = ArrayBuilder::new(); - for (i, dst) in destination.array.iter_mut().enumerate() { + for (src, dst) in iter.into_iter().zip(destination.array.iter_mut()) { unsafe { - ptr::write(dst, f(i)); + ptr::write(dst, src); } destination.position += 1; } + if destination.position < N::to_usize() { + from_iter_length_fail(destination.position, N::to_usize()); + } + destination.into_inner() } +} - /// Map a function over a slice to a `GenericArray`. - /// - /// The length of the slice *must* be equal to the length of the array. - #[inline] - pub fn map_slice T>(s: &[S], f: F) -> GenericArray { - assert_eq!(s.len(), N::to_usize()); +#[inline(never)] +#[cold] +fn from_iter_length_fail(length: usize, expected: usize) -> ! { + panic!("GenericArray::from_iter received {} elements but expected {}", length, expected); +} - Self::generate(|i| f(unsafe { s.get_unchecked(i) })) - } +unsafe impl GenericSequence for GenericArray +where + N: ArrayLength, +{ + type Length = N; + type Sequence = Self; - /// Maps a `GenericArray` to another `GenericArray`. - /// - /// If the mapping function panics, any already initialized elements in the new array - /// will be dropped, AND any unused elements in the source array will also be dropped. - pub fn map(self, f: F) -> GenericArray + fn generate(f: F) -> GenericArray where - F: Fn(T) -> U, - N: ArrayLength, + F: Fn(usize) -> T, { - let mut source = ArrayConsumer::new(self); let mut destination = ArrayBuilder::new(); - for (dst, src) in destination.array.iter_mut().zip(source.array.iter()) { + for (i, dst) in destination.array.iter_mut().enumerate() { unsafe { - ptr::write(dst, f(ptr::read(src))); + ptr::write(dst, f(i)); } - source.position += 1; destination.position += 1; } destination.into_inner() } +} - /// Maps a `GenericArray` to another `GenericArray` by reference. - /// - /// If the mapping function panics, any already initialized elements will be dropped. - #[inline] - pub fn map_ref(&self, f: F) -> GenericArray - where - F: Fn(&T) -> U, - N: ArrayLength, - { - GenericArray::generate(|i| f(unsafe { self.get_unchecked(i) })) - } +unsafe impl MappedGenericSequence for GenericArray +where + N: ArrayLength + ArrayLength, + GenericArray: GenericSequence, +{ + type Mapped = GenericArray; +} - /// Combines two `GenericArray` instances and iterates through both of them, - /// initializing a new `GenericArray` with the result of the zipped mapping function. - /// - /// If the mapping function panics, any already initialized elements in the new array - /// will be dropped, AND any unused elements in the source arrays will also be dropped. - pub fn zip(self, rhs: GenericArray, f: F) -> GenericArray +unsafe impl FunctionalSequence for GenericArray +where + N: ArrayLength, + Self: GenericSequence +{ + fn map(self, f: F) -> MappedSequence where - F: Fn(T, B) -> U, - N: ArrayLength + ArrayLength, + Self::Length: ArrayLength, + Self: MappedGenericSequence, + F: Fn(T) -> U, { - let mut left = ArrayConsumer::new(self); - let mut right = ArrayConsumer::new(rhs); + let mut source = ArrayConsumer::new(self); - let mut destination = ArrayBuilder::new(); + let ArrayConsumer { ref array, ref mut position } = source; - for (dst, (lhs, rhs)) in destination - .array - .iter_mut() - .zip(left.array.iter().zip(right.array.iter())) - { - unsafe { - ptr::write(dst, f(ptr::read(lhs), ptr::read(rhs))); - } + FromIterator::from_iter(array.iter().map(|src| { + let value = unsafe { ptr::read(src) }; - destination.position += 1; - left.position += 1; - right.position += 1; - } + *position += 1; - destination.into_inner() + f(value) + })) } - /// Combines two `GenericArray` instances and iterates through both of them by reference, - /// initializing a new `GenericArray` with the result of the zipped mapping function. - /// - /// If the mapping function panics, any already initialized elements will be dropped. - pub fn zip_ref(&self, rhs: &GenericArray, f: F) -> GenericArray + fn zip(self, rhs: Rhs, f: F) -> MappedSequence where - F: Fn(&T, &B) -> U, - N: ArrayLength + ArrayLength, + Self: MappedGenericSequence, + Self::Length: ArrayLength + ArrayLength, + Rhs: GenericSequence, + F: Fn(T, SequenceItem) -> U, { - GenericArray::generate(|i| unsafe { f(self.get_unchecked(i), rhs.get_unchecked(i)) }) + let mut left = ArrayConsumer::new(self); + + let ArrayConsumer { ref array, ref mut position } = left; + + FromIterator::from_iter(array.iter().zip(rhs.into_iter()).map(|(l, right_value)| { + let left_value = unsafe { ptr::read(l) }; + + *position += 1; + + f(left_value, right_value) + })) } +} +impl GenericArray +where + N: ArrayLength, +{ /// Extracts a slice containing the entire array. #[inline] pub fn as_slice(&self) -> &[T] { @@ -342,16 +373,36 @@ where /// Length of the slice must be equal to the length of the array. #[inline] pub fn from_slice(slice: &[T]) -> &GenericArray { + slice.into() + } + + /// Converts mutable slice to a mutable generic array reference + /// + /// Length of the slice must be equal to the length of the array. + #[inline] + pub fn from_mut_slice(slice: &mut [T]) -> &mut GenericArray { + slice.into() + } +} + +impl<'a, T, N: ArrayLength> From<&'a [T]> for &'a GenericArray { + /// Converts slice to a generic array reference with inferred length; + /// + /// Length of the slice must be equal to the length of the array. + #[inline] + fn from(slice: &[T]) -> &GenericArray { assert_eq!(slice.len(), N::to_usize()); unsafe { &*(slice.as_ptr() as *const GenericArray) } } +} +impl<'a, T, N: ArrayLength> From<&'a mut [T]> for &'a mut GenericArray { /// Converts mutable slice to a mutable generic array reference /// /// Length of the slice must be equal to the length of the array. #[inline] - pub fn from_mut_slice(slice: &mut [T]) -> &mut GenericArray { + fn from(slice: &mut [T]) -> &mut GenericArray { assert_eq!(slice.len(), N::to_usize()); unsafe { &mut *(slice.as_mut_ptr() as *mut GenericArray) } @@ -397,44 +448,13 @@ where destination.position += 1; } - let array = unsafe { ptr::read(&destination.array) }; - - mem::forget(destination); - - Some(ManuallyDrop::into_inner(array)) + Some(destination.into_inner()) } else { None } } } -impl ::core::iter::FromIterator for GenericArray -where - N: ArrayLength, - T: Default, -{ - fn from_iter(iter: I) -> GenericArray - where - I: IntoIterator, - { - let mut destination = ArrayBuilder::new(); - - let defaults = ::core::iter::repeat(()).map(|_| T::default()); - - for (dst, src) in destination - .array - .iter_mut() - .zip(iter.into_iter().chain(defaults)) - { - unsafe { - ptr::write(dst, src); - } - } - - destination.into_inner() - } -} - /// A reimplementation of the `transmute` function, avoiding problems /// when the compiler can't prove equal sizes. #[inline] @@ -464,10 +484,12 @@ mod test { #[test] fn test_assembly() { + use functional::*; + let a = black_box(arr![i32; 1, 3, 5, 7]); let b = black_box(arr![i32; 2, 4, 6, 8]); - let c = a.zip_ref(&b, |l, r| l + r); + let c = a.zip(&b, |l: i32, r: &i32| l + r); assert_eq!(c, arr![i32; 3, 7, 11, 15]); } diff --git a/src/sequence.rs b/src/sequence.rs index 5624bea44e..b13798cbf5 100644 --- a/src/sequence.rs +++ b/src/sequence.rs @@ -5,23 +5,62 @@ use core::{mem, ptr}; use core::ops::{Add, Sub}; use typenum::operator_aliases::*; -/// Defines some `GenericArray` sequence with an associated length. +/// Defines some sequence with an associated length and iteration capabilities. /// /// This is useful for passing N-length generic arrays as generics. -pub unsafe trait GenericSequence: Sized { +pub unsafe trait GenericSequence: Sized + IntoIterator { /// `GenericArray` associated length type Length: ArrayLength; + + /// Concrete sequence type used in conjuction with reference implementations of `GenericSequence` + type Sequence: GenericSequence + FromIterator; + + /// Initializes a new sequence instance using the given function. + /// + /// If the generator function panics while initializing the sequence, + /// any already initialized elements will be dropped. + fn generate(f: F) -> Self::Sequence + where F: Fn(usize) -> T; +} + +/// Accessor type for iteration items from `GenericSequence` +pub type SequenceItem = ::Item; + +unsafe impl<'a, T: 'a, S: GenericSequence> GenericSequence for &'a S +where + &'a S: IntoIterator +{ + type Length = S::Length; + type Sequence = S::Sequence; + + #[inline] + fn generate(f: F) -> Self::Sequence + where F: Fn(usize) -> T + { + S::generate(f) + } } -unsafe impl> GenericSequence for GenericArray { - type Length = N; +unsafe impl<'a, T: 'a, S: GenericSequence> GenericSequence for &'a mut S +where + &'a mut S: IntoIterator +{ + type Length = S::Length; + type Sequence = S::Sequence; + + #[inline] + fn generate(f: F) -> Self::Sequence + where F: Fn(usize) -> T + { + S::generate(f) + } } /// Defines any `GenericSequence` which can be lengthened or extended by appending /// or prepending an element to it. /// /// Any lengthened sequence can be shortened back to the original using `pop_front` or `pop_back` -pub unsafe trait Lengthen: GenericSequence { +pub unsafe trait Lengthen: Sized + GenericSequence { /// `GenericSequence` that has one more element than `Self` type Longer: Shorten; @@ -56,7 +95,7 @@ pub unsafe trait Lengthen: GenericSequence { /// /// Additionally, any shortened sequence can be lengthened by /// appending or prepending an element to it. -pub unsafe trait Shorten: GenericSequence { +pub unsafe trait Shorten: Sized + GenericSequence { /// `GenericSequence` that has one less element than `Self` type Shorter: Lengthen; diff --git a/tests/mod.rs b/tests/mod.rs index 10cb4f5b6f..016071a531 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -6,6 +6,7 @@ use core::cell::Cell; use core::ops::Drop; use generic_array::GenericArray; use generic_array::sequence::*; +use generic_array::functional::*; use generic_array::typenum::{U1, U3, U4, U97}; #[test] @@ -155,13 +156,14 @@ fn test_zip() { let a: GenericArray<_, U4> = GenericArray::generate(|i| i + 1); let b: GenericArray<_, U4> = GenericArray::generate(|i| i as i32 * 4); - let c = a.zip(b, |r, l| r as i32 + l); + let c = (&a).zip(&b, |r, l| *r as i32 + l); assert_eq!(c, arr![i32; 1, 6, 11, 16]); } #[test] -fn test_from_iter() { +#[should_panic] +fn test_from_iter_short() { use core::iter::repeat; let a: GenericArray<_, U4> = repeat(11).take(3).collect(); @@ -169,15 +171,23 @@ fn test_from_iter() { assert_eq!(a, arr![i32; 11, 11, 11, 0]); } +#[test] +fn test_from_iter() { + use core::iter::{repeat, once}; + + let a: GenericArray<_, U4> = repeat(11).take(3).chain(once(0)).collect(); + + assert_eq!(a, arr![i32; 11, 11, 11, 0]); +} + #[test] fn test_sizes() { #![allow(dead_code)] use core::mem::{size_of, size_of_val}; - #[derive(Debug)] + #[derive(Debug, Copy, Clone)] #[repr(C)] #[repr(packed)] - #[derive(Default)] struct Test { t: u16, s: u32, diff --git a/tests/std.rs b/tests/std.rs new file mode 100644 index 0000000000..705e3e1791 --- /dev/null +++ b/tests/std.rs @@ -0,0 +1,23 @@ +#![recursion_limit="128"] + +//#[macro_use] +extern crate generic_array; + +use std::fmt::Debug; +use std::ops::Add; + +//use generic_array::GenericArray; +use generic_array::sequence::*; +use generic_array::functional::*; + +pub fn test_generic(s: S) + where + S: FunctionalSequence, + SequenceItem: Add, + S: MappedGenericSequence, + MappedSequence: Debug +{ + let a = s.map(|x| x + 1); + + println!("{:?}", a); +} \ No newline at end of file From 805d8c812203e4eb20b5a38e9253e0204f89ab73 Mon Sep 17 00:00:00 2001 From: novacrazy Date: Sun, 4 Mar 2018 22:58:01 -0600 Subject: [PATCH 3/8] Tweak tests for references --- tests/mod.rs | 3 ++- tests/std.rs | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/mod.rs b/tests/mod.rs index 016071a531..b539a18287 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -156,7 +156,8 @@ fn test_zip() { let a: GenericArray<_, U4> = GenericArray::generate(|i| i + 1); let b: GenericArray<_, U4> = GenericArray::generate(|i| i as i32 * 4); - let c = (&a).zip(&b, |r, l| *r as i32 + l); + // Uses reference and non-reference arguments + let c = (&a).zip(b, |r, l| *r as i32 + l); assert_eq!(c, arr![i32; 1, 6, 11, 16]); } diff --git a/tests/std.rs b/tests/std.rs index 705e3e1791..e6e5502a30 100644 --- a/tests/std.rs +++ b/tests/std.rs @@ -12,10 +12,10 @@ use generic_array::functional::*; pub fn test_generic(s: S) where - S: FunctionalSequence, - SequenceItem: Add, - S: MappedGenericSequence, - MappedSequence: Debug + S: FunctionalSequence, // `.map` + SequenceItem: Add, // `+` + S: MappedGenericSequence, // `i32` -> `i32` + MappedSequence: Debug // println! { let a = s.map(|x| x + 1); From c16b587cd67208494acd0e44d2e0aa496ca717f3 Mon Sep 17 00:00:00 2001 From: novacrazy Date: Mon, 5 Mar 2018 14:49:02 -0600 Subject: [PATCH 4/8] Make function arguments FnMut Closes #59 --- src/functional.rs | 6 +++--- src/lib.rs | 12 ++++++------ src/sequence.rs | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/functional.rs b/src/functional.rs index 38f727d11f..a805f68265 100644 --- a/src/functional.rs +++ b/src/functional.rs @@ -37,7 +37,7 @@ pub unsafe trait FunctionalSequence: GenericSequence { where Self: MappedGenericSequence, Self::Length: ArrayLength, - F: Fn(SequenceItem) -> U, + F: FnMut(SequenceItem) -> U, { FromIterator::from_iter(self.into_iter().map(f)) } @@ -47,12 +47,12 @@ pub unsafe trait FunctionalSequence: GenericSequence { /// /// If the mapping function panics, any already initialized elements in the new sequence /// will be dropped, AND any unused elements in the source sequences will also be dropped. - fn zip(self, rhs: Rhs, f: F) -> MappedSequence + fn zip(self, rhs: Rhs, mut f: F) -> MappedSequence where Self: MappedGenericSequence, Self::Length: ArrayLength + ArrayLength, Rhs: GenericSequence, - F: Fn(SequenceItem, SequenceItem) -> U, + F: FnMut(SequenceItem, SequenceItem) -> U, { FromIterator::from_iter(self.into_iter().zip(rhs.into_iter()).map(|(l, r)| f(l, r) )) } diff --git a/src/lib.rs b/src/lib.rs index d3df3869d9..841cf87436 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -281,9 +281,9 @@ where type Length = N; type Sequence = Self; - fn generate(f: F) -> GenericArray + fn generate(mut f: F) -> GenericArray where - F: Fn(usize) -> T, + F: FnMut(usize) -> T, { let mut destination = ArrayBuilder::new(); @@ -312,11 +312,11 @@ where N: ArrayLength, Self: GenericSequence { - fn map(self, f: F) -> MappedSequence + fn map(self, mut f: F) -> MappedSequence where Self::Length: ArrayLength, Self: MappedGenericSequence, - F: Fn(T) -> U, + F: FnMut(T) -> U, { let mut source = ArrayConsumer::new(self); @@ -331,12 +331,12 @@ where })) } - fn zip(self, rhs: Rhs, f: F) -> MappedSequence + fn zip(self, rhs: Rhs, mut f: F) -> MappedSequence where Self: MappedGenericSequence, Self::Length: ArrayLength + ArrayLength, Rhs: GenericSequence, - F: Fn(T, SequenceItem) -> U, + F: FnMut(T, SequenceItem) -> U, { let mut left = ArrayConsumer::new(self); diff --git a/src/sequence.rs b/src/sequence.rs index b13798cbf5..d6723833df 100644 --- a/src/sequence.rs +++ b/src/sequence.rs @@ -20,7 +20,7 @@ pub unsafe trait GenericSequence: Sized + IntoIterator { /// If the generator function panics while initializing the sequence, /// any already initialized elements will be dropped. fn generate(f: F) -> Self::Sequence - where F: Fn(usize) -> T; + where F: FnMut(usize) -> T; } /// Accessor type for iteration items from `GenericSequence` @@ -35,7 +35,7 @@ where #[inline] fn generate(f: F) -> Self::Sequence - where F: Fn(usize) -> T + where F: FnMut(usize) -> T { S::generate(f) } @@ -50,7 +50,7 @@ where #[inline] fn generate(f: F) -> Self::Sequence - where F: Fn(usize) -> T + where F: FnMut(usize) -> T { S::generate(f) } From ce7a1ee0210ac9ec7692b5e607cc42f2cff8ec43 Mon Sep 17 00:00:00 2001 From: novacrazy Date: Wed, 7 Mar 2018 00:57:04 -0600 Subject: [PATCH 5/8] Specialize GenericSequence and zip --- src/functional.rs | 3 ++- src/lib.rs | 49 ++++++++++++++++++++++++++++++++--------------- src/sequence.rs | 24 +++++++++++++++++++++++ 3 files changed, 60 insertions(+), 16 deletions(-) diff --git a/src/functional.rs b/src/functional.rs index a805f68265..5788a7e036 100644 --- a/src/functional.rs +++ b/src/functional.rs @@ -50,8 +50,9 @@ pub unsafe trait FunctionalSequence: GenericSequence { fn zip(self, rhs: Rhs, mut f: F) -> MappedSequence where Self: MappedGenericSequence, + Rhs: MappedGenericSequence>, Self::Length: ArrayLength + ArrayLength, - Rhs: GenericSequence, + Rhs: GenericSequence, F: FnMut(SequenceItem, SequenceItem) -> U, { FromIterator::from_iter(self.into_iter().zip(rhs.into_iter()).map(|(l, r)| f(l, r) )) diff --git a/src/lib.rs b/src/lib.rs index 841cf87436..a4d1de5895 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -277,6 +277,7 @@ fn from_iter_length_fail(length: usize, expected: usize) -> ! { unsafe impl GenericSequence for GenericArray where N: ArrayLength, + Self: IntoIterator, { type Length = N; type Sequence = Self; @@ -297,6 +298,32 @@ where destination.into_inner() } + + fn inverted_zip(self, lhs: GenericArray, mut f: F) -> MappedSequence, B, U> + where + GenericArray: + GenericSequence + + MappedGenericSequence, + Self: MappedGenericSequence, + Self::Length: ArrayLength + ArrayLength, + F: FnMut(B, Self::Item) -> U + { + let mut left = ArrayConsumer::new(lhs); + let mut right = ArrayConsumer::new(self); + + let ArrayConsumer { array: ref left_array, position: ref mut left_position } = left; + let ArrayConsumer { array: ref right_array, position: ref mut right_position } = right; + + FromIterator::from_iter(left_array.iter().zip(right_array.iter()).map(|(l, r)| { + let left_value = unsafe { ptr::read(l) }; + let right_value = unsafe { ptr::read(r) }; + + *left_position += 1; + *right_position += 1; + + f(left_value, right_value) + })) + } } unsafe impl MappedGenericSequence for GenericArray @@ -310,7 +337,7 @@ where unsafe impl FunctionalSequence for GenericArray where N: ArrayLength, - Self: GenericSequence + Self: GenericSequence { fn map(self, mut f: F) -> MappedSequence where @@ -331,24 +358,16 @@ where })) } - fn zip(self, rhs: Rhs, mut f: F) -> MappedSequence + #[inline] + fn zip(self, rhs: Rhs, f: F) -> MappedSequence where Self: MappedGenericSequence, + Rhs: MappedGenericSequence>, Self::Length: ArrayLength + ArrayLength, - Rhs: GenericSequence, + Rhs: GenericSequence, F: FnMut(T, SequenceItem) -> U, { - let mut left = ArrayConsumer::new(self); - - let ArrayConsumer { ref array, ref mut position } = left; - - FromIterator::from_iter(array.iter().zip(rhs.into_iter()).map(|(l, right_value)| { - let left_value = unsafe { ptr::read(l) }; - - *position += 1; - - f(left_value, right_value) - })) + rhs.inverted_zip(self, f) } } @@ -489,7 +508,7 @@ mod test { let a = black_box(arr![i32; 1, 3, 5, 7]); let b = black_box(arr![i32; 2, 4, 6, 8]); - let c = a.zip(&b, |l: i32, r: &i32| l + r); + let c = a.zip(b, |l, r| l + r); assert_eq!(c, arr![i32; 3, 7, 11, 15]); } diff --git a/src/sequence.rs b/src/sequence.rs index d6723833df..729ef42e8c 100644 --- a/src/sequence.rs +++ b/src/sequence.rs @@ -21,6 +21,30 @@ pub unsafe trait GenericSequence: Sized + IntoIterator { /// any already initialized elements will be dropped. fn generate(f: F) -> Self::Sequence where F: FnMut(usize) -> T; + + #[doc(hidden)] + fn inverted_zip(self, lhs: GenericArray, mut f: F) -> MappedSequence, B, U> + where + GenericArray: + GenericSequence + + MappedGenericSequence, + Self: MappedGenericSequence, + Self::Length: ArrayLength + ArrayLength, + F: FnMut(B, Self::Item) -> U + { + + let mut left = ArrayConsumer::new(lhs); + + let ArrayConsumer { array: ref left_array, position: ref mut left_position } = left; + + FromIterator::from_iter(left_array.iter().zip(self.into_iter()).map(|(l, right_value)| { + let left_value = unsafe { ptr::read(l) }; + + *left_position += 1; + + f(left_value, right_value) + })) + } } /// Accessor type for iteration items from `GenericSequence` From 2b7502a069b76e4964ffae2fb0fd8793c40cdbcf Mon Sep 17 00:00:00 2001 From: novacrazy Date: Wed, 7 Mar 2018 02:24:47 -0600 Subject: [PATCH 6/8] Specialize GenericSequence and zip more Added missing MappedGenericSequence implementation for &mut S --- src/functional.rs | 14 ++++++++++++-- src/lib.rs | 24 ++++++++++++++++++++++-- src/sequence.rs | 11 +++++++++++ 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/functional.rs b/src/functional.rs index 5788a7e036..8a5bdf84d9 100644 --- a/src/functional.rs +++ b/src/functional.rs @@ -24,6 +24,15 @@ where type Mapped = >::Mapped; } +unsafe impl<'a, T, U, S: MappedGenericSequence> MappedGenericSequence for &'a mut S +where + &'a mut S: GenericSequence, + S: GenericSequence>::Length>, + >::Length: ArrayLength, +{ + type Mapped = >::Mapped; +} + /// Accessor type for a mapped generic sequence pub type MappedSequence = <>::Mapped as GenericSequence>::Sequence; @@ -47,7 +56,8 @@ pub unsafe trait FunctionalSequence: GenericSequence { /// /// If the mapping function panics, any already initialized elements in the new sequence /// will be dropped, AND any unused elements in the source sequences will also be dropped. - fn zip(self, rhs: Rhs, mut f: F) -> MappedSequence + #[inline] + fn zip(self, rhs: Rhs, f: F) -> MappedSequence where Self: MappedGenericSequence, Rhs: MappedGenericSequence>, @@ -55,7 +65,7 @@ pub unsafe trait FunctionalSequence: GenericSequence { Rhs: GenericSequence, F: FnMut(SequenceItem, SequenceItem) -> U, { - FromIterator::from_iter(self.into_iter().zip(rhs.into_iter()).map(|(l, r)| f(l, r) )) + rhs.inverted_zip2(self, f) } } diff --git a/src/lib.rs b/src/lib.rs index a4d1de5895..22e4e44af3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -324,6 +324,26 @@ where f(left_value, right_value) })) } + + fn inverted_zip2(self, lhs: Lhs, mut f: F) -> MappedSequence + where + Lhs: GenericSequence + MappedGenericSequence, + Self: MappedGenericSequence, + Self::Length: ArrayLength + ArrayLength, + F: FnMut(SequenceItem, SequenceItem) -> U + { + let mut right = ArrayConsumer::new(self); + + let ArrayConsumer { array: ref right_array, position: ref mut right_position } = right; + + FromIterator::from_iter(lhs.into_iter().zip(right_array.iter()).map(|(left_value, r)| { + let right_value = unsafe { ptr::read(r) }; + + *right_position += 1; + + f(left_value, right_value) + })) + } } unsafe impl MappedGenericSequence for GenericArray @@ -506,9 +526,9 @@ mod test { use functional::*; let a = black_box(arr![i32; 1, 3, 5, 7]); - let b = black_box(arr![i32; 2, 4, 6, 8]); + let mut b = black_box(arr![i32; 2, 4, 6, 8]); - let c = a.zip(b, |l, r| l + r); + let c = (a).zip(&mut b, |l, r| l + *r); assert_eq!(c, arr![i32; 3, 7, 11, 15]); } diff --git a/src/sequence.rs b/src/sequence.rs index 729ef42e8c..8984fa9e54 100644 --- a/src/sequence.rs +++ b/src/sequence.rs @@ -45,6 +45,17 @@ pub unsafe trait GenericSequence: Sized + IntoIterator { f(left_value, right_value) })) } + + #[doc(hidden)] + fn inverted_zip2(self, lhs: Lhs, mut f: F) -> MappedSequence + where + Lhs: GenericSequence + MappedGenericSequence, + Self: MappedGenericSequence, + Self::Length: ArrayLength + ArrayLength, + F: FnMut(SequenceItem, SequenceItem) -> U + { + FromIterator::from_iter(lhs.into_iter().zip(self.into_iter()).map(|(l, r)| f(l, r) )) + } } /// Accessor type for iteration items from `GenericSequence` From 7f5efcffe22641002763b7c3e99f38711093ddd7 Mon Sep 17 00:00:00 2001 From: novacrazy Date: Wed, 7 Mar 2018 05:42:57 -0600 Subject: [PATCH 7/8] Add `fold` method to `FunctionalSequence` --- src/functional.rs | 30 ++++++++++++++++++++---------- src/lib.rs | 25 +++++++++++++++++++++++-- tests/mod.rs | 25 ++++++++++++++++++++++++- tests/std.rs | 11 +++++------ 4 files changed, 72 insertions(+), 19 deletions(-) diff --git a/src/functional.rs b/src/functional.rs index 8a5bdf84d9..8ecd135e77 100644 --- a/src/functional.rs +++ b/src/functional.rs @@ -43,10 +43,10 @@ pub unsafe trait FunctionalSequence: GenericSequence { /// If the mapping function panics, any already initialized elements in the new sequence /// will be dropped, AND any unused elements in the source sequence will also be dropped. fn map(self, f: F) -> MappedSequence - where - Self: MappedGenericSequence, - Self::Length: ArrayLength, - F: FnMut(SequenceItem) -> U, + where + Self: MappedGenericSequence, + Self::Length: ArrayLength, + F: FnMut(SequenceItem) -> U, { FromIterator::from_iter(self.into_iter().map(f)) } @@ -58,15 +58,25 @@ pub unsafe trait FunctionalSequence: GenericSequence { /// will be dropped, AND any unused elements in the source sequences will also be dropped. #[inline] fn zip(self, rhs: Rhs, f: F) -> MappedSequence - where - Self: MappedGenericSequence, - Rhs: MappedGenericSequence>, - Self::Length: ArrayLength + ArrayLength, - Rhs: GenericSequence, - F: FnMut(SequenceItem, SequenceItem) -> U, + where + Self: MappedGenericSequence, + Rhs: MappedGenericSequence>, + Self::Length: ArrayLength + ArrayLength, + Rhs: GenericSequence, + F: FnMut(SequenceItem, SequenceItem) -> U, { rhs.inverted_zip2(self, f) } + + /// Folds (or reduces) a sequence of data into a single value. + /// + /// If the fold function panics, any unused elements will be dropped. + fn fold(self, init: U, f: F) -> U + where + F: FnMut(U, SequenceItem) -> U, + { + self.into_iter().fold(init, f) + } } unsafe impl<'a, T, S: GenericSequence> FunctionalSequence for &'a S diff --git a/src/lib.rs b/src/lib.rs index 22e4e44af3..c171c09494 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -389,6 +389,23 @@ where { rhs.inverted_zip(self, f) } + + fn fold(self, init: U, mut f: F) -> U + where + F: FnMut(U, T) -> U + { + let mut source = ArrayConsumer::new(self); + + let ArrayConsumer { ref array, ref mut position } = source; + + array.iter().fold(init, |acc, src| { + let value = unsafe { ptr::read(src) }; + + *position += 1; + + f(acc, value) + }) + } } impl GenericArray @@ -526,10 +543,14 @@ mod test { use functional::*; let a = black_box(arr![i32; 1, 3, 5, 7]); - let mut b = black_box(arr![i32; 2, 4, 6, 8]); + let b = black_box(arr![i32; 2, 4, 6, 8]); + + let c = (&a).zip(b, |l, r| l + r); - let c = (a).zip(&mut b, |l, r| l + *r); + let d = a.fold(0, |a, x| a + x); assert_eq!(c, arr![i32; 3, 7, 11, 15]); + + assert_eq!(d, 16); } } diff --git a/tests/mod.rs b/tests/mod.rs index b539a18287..f0f6a8d479 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -3,7 +3,7 @@ #[macro_use] extern crate generic_array; use core::cell::Cell; -use core::ops::Drop; +use core::ops::{Add, Drop}; use generic_array::GenericArray; use generic_array::sequence::*; use generic_array::functional::*; @@ -267,4 +267,27 @@ fn test_concat() { assert_eq!(d, arr![i32; 1]); assert_eq!(e, arr![i32; 2, 3, 4]); +} + +#[test] +fn test_fold() { + let a = arr![i32; 1, 2, 3, 4]; + + assert_eq!(10, a.fold(0, |a, x| a + x)); +} + +fn sum_generic(s: S) -> i32 +where + S: FunctionalSequence, + SequenceItem: Add, // `+` + i32: Add, Output=i32>, // reflexive +{ + s.fold(0, |a, x| a + x) +} + +#[test] +fn test_sum() { + let a = sum_generic(arr![i32; 1, 2, 3, 4]); + + assert_eq!(a, 10); } \ No newline at end of file diff --git a/tests/std.rs b/tests/std.rs index e6e5502a30..d758ca6ca9 100644 --- a/tests/std.rs +++ b/tests/std.rs @@ -1,6 +1,5 @@ #![recursion_limit="128"] -//#[macro_use] extern crate generic_array; use std::fmt::Debug; @@ -11,11 +10,11 @@ use generic_array::sequence::*; use generic_array::functional::*; pub fn test_generic(s: S) - where - S: FunctionalSequence, // `.map` - SequenceItem: Add, // `+` - S: MappedGenericSequence, // `i32` -> `i32` - MappedSequence: Debug // println! +where + S: FunctionalSequence, // `.map` + SequenceItem: Add, // `+` + S: MappedGenericSequence, // `i32` -> `i32` + MappedSequence: Debug // println! { let a = s.map(|x| x + 1); From 81f3e103dc449c1b868eac4ce7b200e29ac4c072 Mon Sep 17 00:00:00 2001 From: novacrazy Date: Wed, 7 Mar 2018 15:45:42 -0600 Subject: [PATCH 8/8] Remove `SequenceItem`, as it is unnecessary --- src/functional.rs | 6 +++--- src/lib.rs | 4 ++-- src/sequence.rs | 5 +---- tests/mod.rs | 4 ++-- tests/std.rs | 2 +- 5 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/functional.rs b/src/functional.rs index 8ecd135e77..461210b108 100644 --- a/src/functional.rs +++ b/src/functional.rs @@ -46,7 +46,7 @@ pub unsafe trait FunctionalSequence: GenericSequence { where Self: MappedGenericSequence, Self::Length: ArrayLength, - F: FnMut(SequenceItem) -> U, + F: FnMut(Self::Item) -> U, { FromIterator::from_iter(self.into_iter().map(f)) } @@ -63,7 +63,7 @@ pub unsafe trait FunctionalSequence: GenericSequence { Rhs: MappedGenericSequence>, Self::Length: ArrayLength + ArrayLength, Rhs: GenericSequence, - F: FnMut(SequenceItem, SequenceItem) -> U, + F: FnMut(Self::Item, Rhs::Item) -> U, { rhs.inverted_zip2(self, f) } @@ -73,7 +73,7 @@ pub unsafe trait FunctionalSequence: GenericSequence { /// If the fold function panics, any unused elements will be dropped. fn fold(self, init: U, f: F) -> U where - F: FnMut(U, SequenceItem) -> U, + F: FnMut(U, Self::Item) -> U, { self.into_iter().fold(init, f) } diff --git a/src/lib.rs b/src/lib.rs index c171c09494..cdefff4faf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -330,7 +330,7 @@ where Lhs: GenericSequence + MappedGenericSequence, Self: MappedGenericSequence, Self::Length: ArrayLength + ArrayLength, - F: FnMut(SequenceItem, SequenceItem) -> U + F: FnMut(Lhs::Item, Self::Item) -> U { let mut right = ArrayConsumer::new(self); @@ -385,7 +385,7 @@ where Rhs: MappedGenericSequence>, Self::Length: ArrayLength + ArrayLength, Rhs: GenericSequence, - F: FnMut(T, SequenceItem) -> U, + F: FnMut(T, Rhs::Item) -> U, { rhs.inverted_zip(self, f) } diff --git a/src/sequence.rs b/src/sequence.rs index 8984fa9e54..a1775ce31f 100644 --- a/src/sequence.rs +++ b/src/sequence.rs @@ -52,15 +52,12 @@ pub unsafe trait GenericSequence: Sized + IntoIterator { Lhs: GenericSequence + MappedGenericSequence, Self: MappedGenericSequence, Self::Length: ArrayLength + ArrayLength, - F: FnMut(SequenceItem, SequenceItem) -> U + F: FnMut(Lhs::Item, Self::Item) -> U { FromIterator::from_iter(lhs.into_iter().zip(self.into_iter()).map(|(l, r)| f(l, r) )) } } -/// Accessor type for iteration items from `GenericSequence` -pub type SequenceItem = ::Item; - unsafe impl<'a, T: 'a, S: GenericSequence> GenericSequence for &'a S where &'a S: IntoIterator diff --git a/tests/mod.rs b/tests/mod.rs index f0f6a8d479..b637fcaf99 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -279,8 +279,8 @@ fn test_fold() { fn sum_generic(s: S) -> i32 where S: FunctionalSequence, - SequenceItem: Add, // `+` - i32: Add, Output=i32>, // reflexive + S::Item: Add, // `+` + i32: Add, // reflexive { s.fold(0, |a, x| a + x) } diff --git a/tests/std.rs b/tests/std.rs index d758ca6ca9..68d6837e2d 100644 --- a/tests/std.rs +++ b/tests/std.rs @@ -12,7 +12,7 @@ use generic_array::functional::*; pub fn test_generic(s: S) where S: FunctionalSequence, // `.map` - SequenceItem: Add, // `+` + S::Item: Add, // `+` S: MappedGenericSequence, // `i32` -> `i32` MappedSequence: Debug // println! {