Skip to content

Commit ffc65b1

Browse files
committed
Improve examples in tests, add back SequenceItem, and fix GenericArrayIter Send/Sync.
1 parent c292d61 commit ffc65b1

File tree

5 files changed

+117
-23
lines changed

5 files changed

+117
-23
lines changed

src/functional.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
//! Functional programming with generic sequences
2+
//!
3+
//! Please see `tests/generics.rs` for examples of how to best use these in your generic functions.
24
35
use super::ArrayLength;
46
use core::iter::FromIterator;

src/iter.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,17 @@ pub struct GenericArrayIter<T, N: ArrayLength<T>> {
1414
index_back: usize,
1515
}
1616

17-
unsafe impl<T: Send, N: ArrayLength<T>> Send for GenericArrayIter<T, N> {}
18-
unsafe impl<T: Sync, N: ArrayLength<T>> Sync for GenericArrayIter<T, N> {}
17+
#[cfg(test)]
18+
mod test {
19+
use super::*;
20+
21+
fn send<I: Send>(_iter: I) {}
22+
23+
#[test]
24+
fn test_send_iter() {
25+
send(GenericArray::from([1, 2, 3, 4]).into_iter());
26+
}
27+
}
1928

2029
impl<T, N> IntoIterator for GenericArray<T, N>
2130
where

src/sequence.rs

+6
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ pub unsafe trait GenericSequence<T>: Sized + IntoIterator {
6969
}
7070
}
7171

72+
/// Accessor for `GenericSequence` item type, which is really `IntoIterator::Item`
73+
///
74+
/// For deeply nested generic mapped sequence types, like shown in `tests/generics.rs`,
75+
/// this can be useful for keeping things organized.
76+
pub type SequenceItem<T> = <T as IntoIterator>::Item;
77+
7278
unsafe impl<'a, T: 'a, S: GenericSequence<T>> GenericSequence<T> for &'a S
7379
where
7480
&'a S: IntoIterator,

tests/generics.rs

+98
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
#![recursion_limit = "128"]
2+
3+
#[macro_use]
4+
extern crate generic_array;
5+
6+
use generic_array::typenum::consts::U4;
7+
8+
use std::fmt::Debug;
9+
use std::ops::Add;
10+
11+
use generic_array::{GenericArray, ArrayLength};
12+
use generic_array::sequence::*;
13+
use generic_array::functional::*;
14+
15+
/// Example function using generics to pass N-length sequences and map them
16+
pub fn generic_map<S>(s: S)
17+
where
18+
S: FunctionalSequence<i32>, // `.map`
19+
S::Item: Add<i32, Output = i32>, // `x + 1`
20+
S: MappedGenericSequence<i32, i32>, // `i32` -> `i32`
21+
MappedSequence<S, i32, i32>: Debug, // println!
22+
{
23+
let a = s.map(|x| x + 1);
24+
25+
println!("{:?}", a);
26+
}
27+
28+
/// Complex example function using generics to pass N-length sequences, zip them, and then map that result.
29+
///
30+
/// If used with `GenericArray` specifically this isn't necessary
31+
pub fn generic_sequence_zip_sum<A, B>(a: A, b: B) -> i32
32+
where
33+
A: FunctionalSequence<i32>, // `.zip`
34+
B: FunctionalSequence<i32, Length = A::Length>, // `.zip`
35+
A: MappedGenericSequence<i32, i32>, // `i32` -> `i32`
36+
B: MappedGenericSequence<i32, i32, Mapped = MappedSequence<A, i32, i32>>, // `i32` -> `i32`, prove A and B can map to the same output
37+
A::Item: Add<B::Item, Output = i32>, // `l + r`
38+
MappedSequence<A, i32, i32>: MappedGenericSequence<i32, i32> + FunctionalSequence<i32>, // `.map`
39+
SequenceItem<MappedSequence<A, i32, i32>>: Add<i32, Output=i32>, // `x + 1`
40+
MappedSequence<MappedSequence<A, i32, i32>, i32, i32>: Debug, // `println!`
41+
MappedSequence<MappedSequence<A, i32, i32>, i32, i32>: FunctionalSequence<i32>, // `.fold`
42+
SequenceItem<MappedSequence<MappedSequence<A, i32, i32>, i32, i32>>: Add<i32, Output=i32> // `x + a`, note the order
43+
{
44+
let c = a.zip(b, |l, r| l + r).map(|x| x + 1);
45+
46+
println!("{:?}", c);
47+
48+
c.fold(0, |a, x| x + a)
49+
}
50+
51+
/// Super-simple fixed-length i32 `GenericArray`s
52+
pub fn generic_array_plain_zip_sum(a: GenericArray<i32, U4>, b: GenericArray<i32, U4>) -> i32 {
53+
a.zip(b, |l, r| l + r).map(|x| x + 1).fold(0, |a, x| x + a)
54+
}
55+
56+
pub fn generic_array_variable_length_zip_sum<N>(a: GenericArray<i32, N>, b: GenericArray<i32, N>) -> i32
57+
where
58+
N: ArrayLength<i32>,
59+
{
60+
a.zip(b, |l, r| l + r).map(|x| x + 1).fold(0, |a, x| x + a)
61+
}
62+
63+
pub fn generic_array_same_type_variable_length_zip_sum<T, N>(a: GenericArray<T, N>, b: GenericArray<T, N>) -> i32
64+
where
65+
N: ArrayLength<T> + ArrayLength<<T as Add<T>>::Output>,
66+
T: Add<T, Output=i32>,
67+
{
68+
a.zip(b, |l, r| l + r).map(|x| x + 1).fold(0, |a, x| x + a)
69+
}
70+
71+
/// Complex example using fully generic `GenericArray`s with the same length.
72+
///
73+
/// It's mostly just the repeated `Add` traits, which would be present in other systems anyway.
74+
pub fn generic_array_zip_sum<A, B, N: ArrayLength<A> + ArrayLength<B>>(a: GenericArray<A, N>, b: GenericArray<B, N>) -> i32
75+
where
76+
A: Add<B>,
77+
N: ArrayLength<<A as Add<B>>::Output> +
78+
ArrayLength<<<A as Add<B>>::Output as Add<i32>>::Output>,
79+
<A as Add<B>>::Output: Add<i32>,
80+
<<A as Add<B>>::Output as Add<i32>>::Output: Add<i32, Output=i32>,
81+
{
82+
a.zip(b, |l, r| l + r).map(|x| x + 1).fold(0, |a, x| x + a)
83+
}
84+
85+
#[test]
86+
fn test_generics() {
87+
generic_map(arr![i32; 1, 2, 3, 4]);
88+
89+
assert_eq!(generic_sequence_zip_sum(arr![i32; 1, 2, 3, 4], arr![i32; 2, 3, 4, 5]), 28);
90+
91+
assert_eq!(generic_array_plain_zip_sum(arr![i32; 1, 2, 3, 4], arr![i32; 2, 3, 4, 5]), 28);
92+
93+
assert_eq!(generic_array_variable_length_zip_sum(arr![i32; 1, 2, 3, 4], arr![i32; 2, 3, 4, 5]), 28);
94+
95+
assert_eq!(generic_array_same_type_variable_length_zip_sum(arr![i32; 1, 2, 3, 4], arr![i32; 2, 3, 4, 5]), 28);
96+
97+
assert_eq!(generic_array_zip_sum(arr![i32; 1, 2, 3, 4], arr![i32; 2, 3, 4, 5]), 28);
98+
}

tests/std.rs

-21
This file was deleted.

0 commit comments

Comments
 (0)