1use crate::codec::Codec;
7use crate::kmer::KmerIter;
8use crate::seq::{Seq, SeqSlice};
9use core::iter::Chain;
10use core::marker::PhantomData;
11
12#[must_use = "iterators are lazy and do nothing unless consumed"]
14pub struct SeqChunks<'a, A: Codec> {
15 slice: &'a SeqSlice<A>,
16 width: usize,
17 skip: usize,
18 index: usize,
19}
20
21#[must_use = "iterators are lazy and do nothing unless consumed"]
23pub struct SeqIter<'a, A: Codec> {
24 slice: &'a SeqSlice<A>,
25 index: usize,
26}
27
28impl<'a, A: Codec> SeqSlice<A> {
29 pub fn chain(
30 self: &'a SeqSlice<A>,
31 second: &'a SeqSlice<A>,
32 ) -> Chain<SeqIter<'a, A>, SeqIter<'a, A>> {
33 self.into_iter().chain(second)
34 }
35
36 pub fn iter(&'a self) -> SeqIter<'a, A> {
37 <&Self as IntoIterator>::into_iter(self)
38 }
39
40 pub fn kmers<const K: usize>(&self) -> KmerIter<'_, A, K> {
42 KmerIter::<A, K> {
43 slice: self,
44 index: 0,
45 len: self.len(),
46 _p: PhantomData,
47 }
48 }
49
50 pub fn rev_iter(&self) -> RevIter<'_, A> {
52 RevIter {
53 slice: self,
54 index: self.len(),
55 }
56 }
57
58 pub fn windows(&self, width: usize) -> SeqChunks<'_, A> {
72 assert!(width != 0, "window must be non-zero");
73 SeqChunks {
74 slice: self,
75 width,
76 skip: 1,
77 index: 0,
78 }
79 }
80
81 pub fn chunks(&self, width: usize) -> SeqChunks<'_, A> {
98 assert!(width != 0, "chunk must be non-zero");
99 SeqChunks {
100 slice: self,
101 width,
102 skip: width,
103 index: 0,
104 }
105 }
106}
107
108#[must_use = "iterators are lazy and do nothing unless consumed"]
110pub struct RevIter<'a, A: Codec> {
111 pub(crate) slice: &'a SeqSlice<A>,
112 pub(crate) index: usize,
113}
114
115impl<A: Codec> Iterator for RevIter<'_, A> {
116 type Item = A;
117 fn next(&mut self) -> Option<A> {
118 let i = self.index;
119
120 if self.index == 0 {
121 return None;
122 }
123 self.index -= 1;
124 Some(A::unsafe_from_bits(self.slice[i - 1].into()))
125 }
126
127 fn size_hint(&self) -> (usize, Option<usize>) {
128 (self.index, Some(self.index))
129 }
130}
131
132impl<A: Codec> ExactSizeIterator for RevIter<'_, A> {}
133
134impl<'a, A: Codec> Iterator for SeqChunks<'a, A> {
135 type Item = &'a SeqSlice<A>;
136
137 fn next(&mut self) -> Option<Self::Item> {
138 let i = self.index;
139 if i + self.width > self.slice.len() {
140 return None;
141 }
142 self.index += self.skip;
143 Some(&self.slice[i..i + self.width])
144 }
145
146 fn size_hint(&self) -> (usize, Option<usize>) {
147 let n = self
148 .slice
149 .len()
150 .saturating_sub(self.index)
151 .saturating_sub(self.width - 1)
152 .div_ceil(self.skip);
153 (n, Some(n))
154 }
155}
156
157impl<A: Codec> ExactSizeIterator for SeqChunks<'_, A> {}
158
159impl<'a, A: Codec> IntoIterator for &'a Seq<A> {
160 type Item = A;
161 type IntoIter = SeqIter<'a, A>;
162
163 fn into_iter(self) -> Self::IntoIter {
164 self.as_ref().into_iter()
165 }
166}
167
168impl<'a, A: Codec> IntoIterator for &'a SeqSlice<A> {
169 type Item = A;
170 type IntoIter = SeqIter<'a, A>;
171
172 fn into_iter(self) -> Self::IntoIter {
173 SeqIter {
174 slice: self,
175 index: 0,
176 }
177 }
178}
179
180impl<'a, A: Codec> FromIterator<&'a SeqSlice<A>> for Vec<Seq<A>> {
181 fn from_iter<T: IntoIterator<Item = &'a SeqSlice<A>>>(iter: T) -> Self {
182 iter.into_iter().map(ToOwned::to_owned).collect()
183 }
184}
185
186impl<A: Codec> Iterator for SeqIter<'_, A> {
187 type Item = A;
188 fn next(&mut self) -> Option<A> {
189 let i = self.index;
190 if self.index >= self.slice.len() {
191 return None;
192 }
193 self.index += 1;
194 Some(A::unsafe_from_bits(self.slice[i].into()))
195 }
196
197 fn size_hint(&self) -> (usize, Option<usize>) {
198 let n = self.slice.len() - self.index;
199 (n, Some(n))
200 }
201}
202
203impl<A: Codec> ExactSizeIterator for SeqIter<'_, A> {}
204
205#[cfg(test)]
206mod tests {
207 use crate::codec::dna::Dna::*;
208 use crate::prelude::*;
209
210 #[test]
211 fn seq_iter() {
212 let seq: Seq<Dna> = dna!("ACTGATCGATAC").into();
213 let elements: Vec<Dna> = seq.into_iter().collect();
214 assert_eq!(elements, vec![A, C, T, G, A, T, C, G, A, T, A, C]);
215 assert_ne!(elements, vec![A, C, T, G, A, T, C, G, A, T, A, C, A]);
216 assert_ne!(elements, vec![C, A, T, A, G, C, T, A, G, T, C, A]);
217 }
218
219 #[test]
220 fn rev_iter() {
221 let seq: Seq<Dna> = dna!("ACTGATCGATAC").into();
222 let rev_elements: Vec<Dna> = seq.rev_iter().collect();
223 assert_ne!(rev_elements, vec![A, C, T, G, A, T, C, G, A, T, A, C]);
224 assert_eq!(rev_elements, vec![C, A, T, A, G, C, T, A, G, T, C, A]);
225 }
226
227 #[test]
228 fn iterators() {
229 let seq: Seq<Dna> = dna!("ACTGATCGATAC").into();
230 let slice = &seq[2..9];
231 let elements: Vec<Dna> = slice.into_iter().collect();
232 assert_eq!(elements, vec![T, G, A, T, C, G, A]);
233 }
234
235 #[test]
236 fn chunks() {
237 let seq: Seq<Dna> = dna!("ACTGATCGATAC").into();
238 let cs: Vec<Seq<Dna>> = seq.chunks(5).collect();
239 assert_eq!(cs[0], dna!("ACTGA"));
240 assert_eq!(cs[1], dna!("TCGAT"));
241 assert_eq!(cs.len(), 2);
242 }
243
244 #[test]
245 fn test_chain() {
246 let seq1 = Seq::<Dna>::try_from("ATG").unwrap();
247 let seq2 = Seq::<Dna>::try_from("TAC").unwrap();
248
249 let chained = seq1.chain(&seq2);
250
251 let expected_seq = Seq::<Dna>::try_from("ATGTAC").unwrap();
252 for (a, b) in chained.zip(&expected_seq) {
253 assert_eq!(a, b);
254 }
255
256 let chained = seq1.chain(&seq2);
257 for (a, b) in chained.map(|b| b.to_comp()).zip(&expected_seq) {
258 assert_ne!(a, b);
259 }
260 }
261
262 #[test]
263 fn windows() {
264 let seq: Seq<Dna> = dna!("ACTGATACG").into();
265 let windows: Vec<String> = seq.windows(5).map(String::from).collect();
266 assert_eq!(windows, vec!["ACTGA", "CTGAT", "TGATA", "GATAC", "ATACG"]);
267 }
268
269 #[test]
270 #[should_panic(expected = "chunk must be non-zero")]
271 fn zero_width_chunk_panics() {
272 let _ = dna!("ACGTACGTGA").chunks(0);
273 }
274
275 #[test]
276 #[should_panic(expected = "window must be non-zero")]
277 fn zero_width_window_panics() {
278 let _ = dna!("ACGTACGTGA").windows(0);
279 }
280}