1#![doc(issue_tracker_base_url = "https://github.com/gabrielfalcao/unique-pointer/issues/")]
2use core::iter::Iterator;
30use core::marker::PhantomData;
31
32#[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 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}