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