Skip to content

Commit 04f16db

Browse files
authored
Merge pull request #50 from novacrazy/master
Add `GenericSequence`, `Lengthen`, `Shorten`, `Split` and `Concat` traits.
2 parents d1851f3 + 04f8fe7 commit 04f16db

File tree

3 files changed

+328
-1
lines changed

3 files changed

+328
-1
lines changed

src/lib.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
//! # }
3737
//! ```
3838
39-
//#![deny(missing_docs)]
39+
#![deny(missing_docs)]
4040
#![no_std]
4141

4242
pub extern crate typenum;
@@ -62,6 +62,8 @@ use typenum::uint::{UInt, UTerm, Unsigned};
6262
#[cfg_attr(test, macro_use)]
6363
pub mod arr;
6464
pub mod iter;
65+
pub mod sequence;
66+
6567
pub use iter::GenericArrayIter;
6668

6769
/// Trait making `GenericArray` work, marking types to be used as length of an array
@@ -380,6 +382,9 @@ impl<T, N> GenericArray<T, N>
380382
where
381383
N: ArrayLength<T>,
382384
{
385+
/// Creates a new `GenericArray` instance from an iterator with a known exact size.
386+
///
387+
/// Returns `None` if the size is not equal to the number of elements in the `GenericArray`.
383388
pub fn from_exact_iter<I>(iter: I) -> Option<Self>
384389
where
385390
I: IntoIterator<Item = T>,

src/sequence.rs

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
//! Useful traits for manipulating sequences of data stored in `GenericArray`s
2+
3+
use super::*;
4+
use core::{mem, ptr};
5+
use core::ops::{Add, Sub};
6+
use typenum::operator_aliases::*;
7+
8+
/// Defines some `GenericArray` sequence with an associated length.
9+
///
10+
/// This is useful for passing N-length generic arrays as generics.
11+
pub unsafe trait GenericSequence<T>: Sized {
12+
/// `GenericArray` associated length
13+
type Length: ArrayLength<T>;
14+
}
15+
16+
unsafe impl<T, N: ArrayLength<T>> GenericSequence<T> for GenericArray<T, N> {
17+
type Length = N;
18+
}
19+
20+
/// Defines any `GenericSequence` which can be lengthened or extended by appending
21+
/// or prepending an element to it.
22+
///
23+
/// Any lengthened sequence can be shortened back to the original using `pop_front` or `pop_back`
24+
pub unsafe trait Lengthen<T>: GenericSequence<T> {
25+
/// `GenericSequence` that has one more element than `Self`
26+
type Longer: Shorten<T, Shorter = Self>;
27+
28+
/// Returns a new array with the given element appended to the end of it.
29+
///
30+
/// Example:
31+
///
32+
/// ```ignore
33+
/// let a = arr![i32; 1, 2, 3];
34+
///
35+
/// let b = a.append(4);
36+
///
37+
/// assert_eq!(b, arr![i32; 1, 2, 3, 4]);
38+
/// ```
39+
fn append(self, last: T) -> Self::Longer;
40+
41+
/// Returns a new array with the given element prepended to the front of it.
42+
///
43+
/// Example:
44+
///
45+
/// ```ignore
46+
/// let a = arr![i32; 1, 2, 3];
47+
///
48+
/// let b = a.prepend(4);
49+
///
50+
/// assert_eq!(b, arr![i32; 4, 1, 2, 3]);
51+
/// ```
52+
fn prepend(self, first: T) -> Self::Longer;
53+
}
54+
55+
/// Defines a `GenericSequence` which can be shortened by removing the first or last element from it.
56+
///
57+
/// Additionally, any shortened sequence can be lengthened by
58+
/// appending or prepending an element to it.
59+
pub unsafe trait Shorten<T>: GenericSequence<T> {
60+
/// `GenericSequence` that has one less element than `Self`
61+
type Shorter: Lengthen<T, Longer = Self>;
62+
63+
/// Returns a new array without the last element, and the last element.
64+
///
65+
/// Example:
66+
///
67+
/// ```ignore
68+
/// let a = arr![i32; 1, 2, 3, 4];
69+
///
70+
/// let (init, last) = a.pop_back();
71+
///
72+
/// assert_eq!(init, arr![i32; 1, 2, 3]);
73+
/// assert_eq!(last, 4);
74+
/// ```
75+
fn pop_back(self) -> (Self::Shorter, T);
76+
77+
/// Returns a new array without the first element, and the first element.
78+
/// Example:
79+
///
80+
/// ```ignore
81+
/// let a = arr![i32; 1, 2, 3, 4];
82+
///
83+
/// let (head, tail) = a.pop_front();
84+
///
85+
/// assert_eq!(head, 1);
86+
/// assert_eq!(tail, arr![i32; 2, 3, 4]);
87+
/// ```
88+
fn pop_front(self) -> (T, Self::Shorter);
89+
}
90+
91+
unsafe impl<T, N: ArrayLength<T>> Lengthen<T> for GenericArray<T, N>
92+
where
93+
N: Add<B1>,
94+
Add1<N>: ArrayLength<T>,
95+
Add1<N>: Sub<B1, Output = N>,
96+
Sub1<Add1<N>>: ArrayLength<T>,
97+
{
98+
type Longer = GenericArray<T, Add1<N>>;
99+
100+
fn append(self, last: T) -> Self::Longer {
101+
let mut longer: Self::Longer = unsafe { mem::uninitialized() };
102+
103+
unsafe {
104+
ptr::write(longer.as_mut_ptr() as *mut _, self);
105+
ptr::write(&mut longer[N::to_usize()], last);
106+
}
107+
108+
longer
109+
}
110+
111+
fn prepend(self, first: T) -> Self::Longer {
112+
let mut longer: Self::Longer = unsafe { mem::uninitialized() };
113+
114+
let longer_ptr = longer.as_mut_ptr();
115+
116+
unsafe {
117+
ptr::write(longer_ptr as *mut _, first);
118+
ptr::write(longer_ptr.offset(1) as *mut _, self);
119+
}
120+
121+
longer
122+
}
123+
}
124+
125+
unsafe impl<T, N: ArrayLength<T>> Shorten<T> for GenericArray<T, N>
126+
where
127+
N: Sub<B1>,
128+
Sub1<N>: ArrayLength<T>,
129+
Sub1<N>: Add<B1, Output = N>,
130+
Add1<Sub1<N>>: ArrayLength<T>,
131+
{
132+
type Shorter = GenericArray<T, Sub1<N>>;
133+
134+
fn pop_back(self) -> (Self::Shorter, T) {
135+
let init_ptr = self.as_ptr();
136+
let last_ptr = unsafe { init_ptr.offset(Sub1::<N>::to_usize() as isize) };
137+
138+
let init = unsafe { ptr::read(init_ptr as _) };
139+
let last = unsafe { ptr::read(last_ptr as _) };
140+
141+
mem::forget(self);
142+
143+
(init, last)
144+
}
145+
146+
fn pop_front(self) -> (T, Self::Shorter) {
147+
let head_ptr = self.as_ptr();
148+
let tail_ptr = unsafe { head_ptr.offset(1) };
149+
150+
let head = unsafe { ptr::read(head_ptr as _) };
151+
let tail = unsafe { ptr::read(tail_ptr as _) };
152+
153+
mem::forget(self);
154+
155+
(head, tail)
156+
}
157+
}
158+
159+
/// Defines a `GenericSequence` that can be split into two parts at a given pivot index.
160+
pub unsafe trait Split<T, K>: GenericSequence<T>
161+
where
162+
K: ArrayLength<T>,
163+
{
164+
/// First part of the resulting split array
165+
type First: GenericSequence<T>;
166+
/// Second part of the resulting split array
167+
type Second: GenericSequence<T>;
168+
169+
/// Splits an array at the given index, returning the separate parts of the array.
170+
fn split(self) -> (Self::First, Self::Second);
171+
}
172+
173+
unsafe impl<T, N, K> Split<T, K> for GenericArray<T, N>
174+
where
175+
N: ArrayLength<T>,
176+
K: ArrayLength<T>,
177+
N: Sub<K>,
178+
Diff<N, K>: ArrayLength<T>,
179+
{
180+
type First = GenericArray<T, K>;
181+
type Second = GenericArray<T, Diff<N, K>>;
182+
183+
fn split(self) -> (Self::First, Self::Second) {
184+
let head_ptr = self.as_ptr();
185+
let tail_ptr = unsafe { head_ptr.offset(K::to_usize() as isize) };
186+
187+
let head = unsafe { ptr::read(head_ptr as _) };
188+
let tail = unsafe { ptr::read(tail_ptr as _) };
189+
190+
mem::forget(self);
191+
192+
(head, tail)
193+
}
194+
}
195+
196+
/// Defines `GenericSequence`s which can be joined together, forming a larger array.
197+
pub unsafe trait Concat<T, M>: GenericSequence<T>
198+
where
199+
M: ArrayLength<T>,
200+
{
201+
/// Sequence to be concatenated with `self`
202+
type Rest: GenericSequence<T, Length = M>;
203+
204+
/// Resulting sequence formed by the concatenation.
205+
type Output: GenericSequence<T>;
206+
207+
/// Concatenate, or join, two sequences.
208+
fn concat(self, rest: Self::Rest) -> Self::Output;
209+
}
210+
211+
unsafe impl<T, N, M> Concat<T, M> for GenericArray<T, N>
212+
where
213+
N: ArrayLength<T> + Add<M>,
214+
M: ArrayLength<T>,
215+
Sum<N, M>: ArrayLength<T>,
216+
{
217+
type Rest = GenericArray<T, M>;
218+
type Output = GenericArray<T, Sum<N, M>>;
219+
220+
fn concat(self, rest: Self::Rest) -> Self::Output {
221+
let mut output: Self::Output = unsafe { mem::uninitialized() };
222+
223+
let output_ptr = output.as_mut_ptr();
224+
225+
unsafe {
226+
ptr::write(output_ptr as *mut _, self);
227+
ptr::write(output_ptr.offset(N::to_usize() as isize) as *mut _, rest);
228+
}
229+
230+
output
231+
}
232+
}

tests/mod.rs

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ extern crate generic_array;
55
use core::cell::Cell;
66
use core::ops::Drop;
77
use generic_array::GenericArray;
8+
use generic_array::sequence::*;
89
use generic_array::typenum::{U1, U3, U4, U97};
910

1011
#[test]
@@ -167,3 +168,92 @@ fn test_from_iter() {
167168

168169
assert_eq!(a, arr![i32; 11, 11, 11, 0]);
169170
}
171+
172+
#[test]
173+
fn test_sizes() {
174+
#![allow(dead_code)]
175+
use core::mem::{size_of, size_of_val};
176+
177+
#[derive(Debug)]
178+
#[repr(C)]
179+
#[repr(packed)]
180+
#[derive(Default)]
181+
struct Test {
182+
t: u16,
183+
s: u32,
184+
r: u16,
185+
f: u16,
186+
o: u32,
187+
}
188+
189+
assert_eq!(size_of::<Test>(), 14);
190+
191+
assert_eq!(size_of_val(&arr![u8; 1, 2, 3]), size_of::<u8>() * 3);
192+
assert_eq!(size_of_val(&arr![u32; 1]), size_of::<u32>() * 1);
193+
assert_eq!(size_of_val(&arr![u64; 1, 2, 3, 4]), size_of::<u64>() * 4);
194+
195+
assert_eq!(size_of::<GenericArray<Test, U97>>(), size_of::<Test>() * 97);
196+
}
197+
198+
#[test]
199+
fn test_append() {
200+
let a = arr![i32; 1, 2, 3];
201+
202+
let b = a.append(4);
203+
204+
assert_eq!(b, arr![i32; 1, 2, 3, 4]);
205+
}
206+
207+
#[test]
208+
fn test_prepend() {
209+
let a = arr![i32; 1, 2, 3];
210+
211+
let b = a.prepend(4);
212+
213+
assert_eq!(b, arr![i32; 4, 1, 2, 3]);
214+
}
215+
216+
#[test]
217+
fn test_pop() {
218+
let a = arr![i32; 1, 2, 3, 4];
219+
220+
let (init, last) = a.pop_back();
221+
222+
assert_eq!(init, arr![i32; 1, 2, 3]);
223+
assert_eq!(last, 4);
224+
225+
let (head, tail) = a.pop_front();
226+
227+
assert_eq!(head, 1);
228+
assert_eq!(tail, arr![i32; 2, 3, 4]);
229+
}
230+
231+
#[test]
232+
fn test_split() {
233+
let a = arr![i32; 1, 2, 3, 4];
234+
235+
let (b, c) = a.split();
236+
237+
assert_eq!(b, arr![i32; 1]);
238+
assert_eq!(c, arr![i32; 2, 3, 4]);
239+
240+
let (e, f) = a.split();
241+
242+
assert_eq!(e, arr![i32; 1, 2]);
243+
assert_eq!(f, arr![i32; 3, 4]);
244+
}
245+
246+
#[test]
247+
fn test_concat() {
248+
let a = arr![i32; 1, 2];
249+
let b = arr![i32; 3, 4];
250+
251+
let c = a.concat(b);
252+
253+
assert_eq!(c, arr![i32; 1, 2, 3, 4]);
254+
255+
let (d, e) = c.split();
256+
257+
assert_eq!(d, arr![i32; 1]);
258+
assert_eq!(e, arr![i32; 2, 3, 4]);
259+
}

0 commit comments

Comments
 (0)