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 core::iter::Iterator;
30use core::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    max_width: Option<usize>,
55
56    _marker: PhantomData<&'a G>,
57}
58impl<'a, G: 'a> Iterator for Gradient<'a, G> {
59    type Item = &'a [G];
60
61    fn next(&mut self) -> Option<&'a [G]> {
62        if self.finished() {
63            return None;
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        if let Some(max_width) = self.max_width {
78            if self.width > max_width {
79                return None;
80            }
81        }
82        Some(self.window())
83    }
84}
85impl<'a, G: Clone + 'a> Gradient<'a, G> {
86    pub fn input(&self) -> Vec<G> {
87        self.input.clone()
88    }
89
90    /// ```
91    /// use gradient_slice::Gradient;
92    /// let result = Gradient::new(0x1BADB002u32.to_be_bytes().to_vec())
93    ///     .with_max_width(2)
94    ///     .map(Vec::from)
95    ///     .collect::<Vec<Vec<u8>>>();
96    /// assert_eq!(
97    ///     result,
98    ///     vec![
99    ///         vec![27], vec![173], vec![176], vec![2],
100    ///         vec![27, 173], vec![173, 176], vec![176, 2],
101    ///     ]
102    /// );
103    /// ```
104    pub fn with_max_width(self, width: usize) -> Gradient<'a, G> {
105        let mut gradient = self.clone();
106        gradient.max_width = Some(width);
107        gradient
108    }
109}
110impl<'a, G: 'a> Gradient<'a, G> {
111    pub fn window(&self) -> &'a [G] {
112        unsafe { core::mem::transmute::<&[G], &'a [G]>(&self.input[self.range()]) }
113    }
114
115    pub fn finished(&self) -> bool {
116        if self.len() == 0 {
117            return true;
118        }
119        if self.end == self.len() {
120            if self.width == self.len() {
121                return true;
122            }
123        }
124        false
125    }
126
127    pub fn width(&self) -> usize {
128        self.width
129    }
130
131    pub fn start(&self) -> usize {
132        self.start
133    }
134
135    pub fn end(&self) -> usize {
136        self.end
137    }
138
139    pub fn range(&self) -> core::ops::Range<usize> {
140        self.start()..self.end()
141    }
142
143    pub fn len(&self) -> usize {
144        self.input.len()
145    }
146
147    pub fn new(s: Vec<G>) -> Gradient<'a, G> {
148        Gradient {
149            input: s,
150            start: 0,
151            end: 0,
152            width: 1,
153            wide: true,
154            max_width: None,
155            _marker: PhantomData,
156        }
157    }
158}
159
160#[cfg(test)]
161mod tests {
162    use super::*;
163
164    #[test]
165    fn gradient() {
166        let result = Gradient::new(" abc ".chars().collect())
167            .map(Vec::from)
168            .map(|vec| {
169                vec.iter()
170                    .map(Clone::clone)
171                    .map(String::from)
172                    .collect::<String>()
173            })
174            .collect::<Vec<String>>();
175        assert_eq!(
176            result,
177            vec![
178                " ", "a", "b", "c", " ", " a", "ab", "bc", "c ", " ab", "abc", "bc ", " abc",
179                "abc ", " abc "
180            ]
181        );
182    }
183    #[test]
184    fn empty() {
185        assert_eq!(
186            Gradient::new(Vec::<char>::new()).collect::<Vec<_>>().len(),
187            0
188        );
189    }
190
191    #[test]
192    fn max_width() {
193        let result = Gradient::new(" abc ".chars().collect())
194            .with_max_width(2)
195            .map(Vec::from)
196            .map(|vec| {
197                vec.iter()
198                    .map(Clone::clone)
199                    .map(String::from)
200                    .collect::<String>()
201            })
202            .collect::<Vec<String>>();
203        assert_eq!(
204            result,
205            vec![" ", "a", "b", "c", " ", " a", "ab", "bc", "c "]
206        );
207    }
208}