gradient_slice/
lib.rs

1#![doc(issue_tracker_base_url = "https://github.com/gabrielfalcao/unique-pointer/issues/")]
2//! # Gradient Slice
3//!
4//! gradient-slice is a safe crate to iterate over a gradient of
5//! permutations of slices of a Vec
6//!
7//! ## Example
8//!
9//! ```
10//! use gradient_slice::Gradient;
11//! let result = Gradient::new(" abc ".chars().collect::<Vec<char>>())
12//!     .map(Vec::from)
13//!     .map(|vec| {
14//!         vec.iter()
15//!             .map(Clone::clone)
16//!             .map(String::from)
17//!             .collect::<String>()
18//!     })
19//!     .collect::<Vec<String>>();
20//! assert_eq!(
21//!     result,
22//!     vec![
23//!         " ", "a", "b", "c", " ", " a", "ab", "bc", "c ", " ab", "abc", "bc ", " abc",
24//!         "abc ", " abc "
25//!     ]
26//! );
27//! ```
28
29use std::iter::Iterator;
30use std::marker::PhantomData;
31
32/// ```
33/// use gradient_slice::Gradient;
34/// let result = Gradient::new(0x1BADB002u32.to_be_bytes().to_vec())
35///     .map(Vec::from)
36///     .collect::<Vec<Vec<u8>>>();
37/// assert_eq!(
38///     result,
39///     vec![
40///         vec![27], vec![173], vec![176], vec![2],
41///         vec![27, 173], vec![173, 176], vec![176, 2],
42///         vec![27, 173, 176], vec![173, 176, 2],
43///         vec![27, 173, 176, 2]
44///     ]
45/// );
46/// ```
47#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
48pub struct Gradient<'a, G> {
49    input: Vec<G>,
50    start: usize,
51    end: usize,
52    width: usize,
53    wide: bool,
54    _marker: PhantomData<&'a G>,
55}
56impl<'a, G: 'a> Iterator for Gradient<'a, G> {
57    type Item = &'a [G];
58
59    fn next(&mut self) -> Option<&'a [G]> {
60        if self.end == self.input.len() {
61            if self.width == self.len() {
62                return None;
63            }
64        }
65        self.end += 1;
66        if !self.wide {
67            self.wide = true;
68            self.width += 1;
69            self.start = 0;
70            self.end = self.width;
71        }
72
73        self.start = self.end - self.width;
74        if self.end == self.len() {
75            self.wide = false;
76        }
77        Some(self.window())
78    }
79}
80impl<'a, G: 'a> Gradient<'a, G> {
81    fn window(&self) -> &'a [G] {
82        unsafe { std::mem::transmute::<&[G], &'a [G]>(&self.input[self.range()]) }
83    }
84
85    fn start(&self) -> usize {
86        self.start
87    }
88
89    fn end(&self) -> usize {
90        self.end
91    }
92
93    fn range(&self) -> std::ops::Range<usize> {
94        self.start()..self.end()
95    }
96
97    fn len(&self) -> usize {
98        self.input.len()
99    }
100
101    pub fn new(s: Vec<G>) -> Gradient<'a, G> {
102        Gradient {
103            input: s,
104            start: 0,
105            end: 0,
106            width: 1,
107            wide: true,
108            _marker: PhantomData,
109        }
110    }
111}
112
113#[cfg(test)]
114mod tests {
115    use super::*;
116
117    #[test]
118    fn gradient() {
119        let result = Gradient::new(" abc ".chars().collect())
120            .map(Vec::from)
121            .map(|vec| {
122                vec.iter()
123                    .map(Clone::clone)
124                    .map(String::from)
125                    .collect::<String>()
126            })
127            .collect::<Vec<String>>();
128        assert_eq!(
129            result,
130            vec![
131                " ", "a", "b", "c", " ", " a", "ab", "bc", "c ", " ab", "abc", "bc ", " abc",
132                "abc ", " abc "
133            ]
134        );
135    }
136}