1use crate::Bs;
31use crate::codec::{self, Codec};
32use crate::prelude::ParseBioError;
33use crate::seq::{Seq, SeqArray, SeqSlice};
34use crate::{
35 Complement, ComplementMut, Reverse, ReverseComplement, ReverseComplementMut, ReverseMut,
36};
37use bitvec::field::BitField;
38use bitvec::view::BitView;
39use core::fmt;
40use core::hash::{Hash, Hasher};
41use core::marker::PhantomData;
42use core::ops::Deref;
43use core::ptr;
44use core::str::FromStr;
45
46pub(crate) mod integral;
47
48#[cfg(feature = "serde")]
49use serde_derive::{Deserialize, Serialize};
50
51const fn make_2bit_table() -> [u8; 256] {
52 let mut table = [0u8; 256];
53 let mut i: usize = 0;
54 while i < 256 {
55 #[expect(
56 clippy::cast_possible_truncation,
57 reason = "the loop bounds i below 256"
58 )]
59 let byte = i as u8;
60 let b0: u8 = (byte & 0b11_00_00_00) >> 6;
61 let b1: u8 = (byte & 0b00_11_00_00) >> 2;
62 let b2: u8 = (byte & 0b00_00_11_00) << 2;
63 let b3: u8 = (byte & 0b00_00_00_11) << 6;
64
65 table[i] = b3 | b2 | b1 | b0;
66 i += 1;
67 }
68 table
69}
70
71const REV_2BIT: [u8; 256] = make_2bit_table();
72
73pub(crate) mod sealed {
74 use crate::Bs;
75 use crate::codec::Codec;
76
77 pub trait KmerStorage: Copy + Clone + PartialEq + std::fmt::Debug {
78 const BITS: usize;
79 type BaN: AsRef<Bs> + AsMut<Bs>;
80
81 fn to_bitarray(self) -> Self::BaN;
82 fn from_bitslice(bs: &Bs) -> Self;
83
84 fn shiftr(&mut self, n: u32);
85
86 fn complement(&mut self, mask: usize);
87 fn rev_blocks<A: Codec, const K: usize>(&mut self);
88 }
89}
90
91pub trait KmerStorage: sealed::KmerStorage {}
92
93impl KmerStorage for usize {}
94
95impl KmerStorage for u64 {}
96
97impl KmerStorage for u128 {}
98
99#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
114#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
115#[repr(transparent)]
116pub struct Kmer<C: Codec, const K: usize, S: KmerStorage = usize> {
117 pub(crate) _p: PhantomData<C>,
118 pub(crate) bs: S,
119}
120
121impl<A: Codec, const K: usize, S: KmerStorage> Kmer<A, K, S> {
122 const ASSERT_K: () = assert!(
124 K * A::BITS as usize <= S::BITS,
125 "`KmerStorage` not large enough for `Kmer`",
126 );
127
128 const ASSERT_K_NONZERO: () = assert!(K > 0, "`K` must be greater than 0");
129
130 const fn assert_k() {
131 let () = Self::ASSERT_K;
132 let () = Self::ASSERT_K_NONZERO;
133 }
134
135 const BITS: usize = K * A::BITS as usize;
136
137 #[must_use]
138 pub const fn len(&self) -> usize {
139 K
140 }
141
142 #[must_use]
143 pub const fn is_empty(&self) -> bool {
144 false
147 }
148
149 #[must_use]
150 pub fn rotated_left(&self, n: u32) -> Self {
151 let n: usize = (n as usize % K) * A::BITS as usize;
152 let mut ba = self.bs.to_bitarray();
153 let bs: &mut Bs = ba.as_mut();
154 bs[..Self::BITS].rotate_left(n);
155
156 Kmer {
157 _p: PhantomData,
158 bs: S::from_bitslice(&bs[..Self::BITS]),
159 }
160 }
161
162 #[must_use]
163 pub fn rotated_right(&self, n: u32) -> Self {
164 let n: usize = (n as usize % K) * A::BITS as usize;
165 let mut ba = self.bs.to_bitarray();
166 let bs: &mut Bs = ba.as_mut();
167 bs[..Self::BITS].rotate_right(n);
168
169 Kmer {
170 _p: PhantomData,
171 bs: S::from_bitslice(&bs[..Self::BITS]),
172 }
173 }
174
175 #[must_use]
185 pub fn pushr(self, base: A) -> Self {
186 let mut ba = self.rotated_left(1).bs.to_bitarray();
187 let bs: &mut Bs = ba.as_mut();
188
189 let start = Self::BITS - A::BITS as usize;
190 let end = start + A::BITS as usize;
191
192 bs[start..end].store(base.to_bits());
193
194 Kmer {
195 _p: PhantomData,
196 bs: S::from_bitslice(bs),
197 }
198 }
199
200 #[must_use]
202 pub fn pushl(self, base: A) -> Self {
203 let mut ba = self.rotated_right(1).bs.to_bitarray();
204 let bs: &mut Bs = ba.as_mut();
205
206 bs[..A::BITS as usize].store(base.to_bits());
207
208 Kmer {
209 _p: PhantomData,
210 bs: S::from_bitslice(bs),
211 }
212 }
213
214 #[must_use]
216 pub fn unsafe_from_seqslice(seq: &SeqSlice<A>) -> Self {
217 Self::assert_k();
218 debug_assert!(K == seq.len(), "K != seq.len()");
219 Kmer {
220 _p: PhantomData,
221 bs: S::from_bitslice(&seq.bs),
222 }
223 }
224
225 fn complement(&mut self) {
226 self.bs.complement(K * A::BITS as usize);
227 }
228
229 fn rev_blocks(&mut self) {
230 self.bs.rev_blocks::<A, K>();
231 let shift = u32::try_from(S::BITS - Self::BITS).expect("k-mer storage is at most 128 bits");
232 self.bs.shiftr(shift);
233 }
234}
235
236impl<A: Codec, const K: usize> From<usize> for Kmer<A, K, usize> {
237 fn from(i: usize) -> Kmer<A, K, usize> {
238 Self::assert_k();
239 Kmer {
240 _p: PhantomData,
241 bs: i,
242 }
243 }
244}
245
246impl<A: Codec, const K: usize> From<u64> for Kmer<A, K, u64> {
247 fn from(i: u64) -> Kmer<A, K, u64> {
248 Self::assert_k();
249 Kmer {
250 _p: PhantomData,
251 bs: i,
252 }
253 }
254}
255
256impl<A: Codec, const K: usize> From<usize> for Kmer<A, K, u64> {
257 fn from(i: usize) -> Kmer<A, K, u64> {
258 Self::assert_k();
259 Kmer {
260 _p: PhantomData,
261 bs: i as u64,
262 }
263 }
264}
265
266impl<S: KmerStorage + Into<usize>, A: Codec, const K: usize> From<&Kmer<A, K, S>> for usize {
278 fn from(kmer: &Kmer<A, K, S>) -> usize {
279 kmer.bs.into()
280 }
281}
282
283impl<A: Codec, const K: usize> Deref for Kmer<A, K, usize> {
284 type Target = SeqSlice<A>;
285
286 fn deref(&self) -> &Self::Target {
287 let bs: &Bs = &self.bs.view_bits()[0..(K * A::BITS as usize)];
288 let bs: *const Bs = ptr::from_ref::<Bs>(bs);
289 unsafe { &*(bs as *const SeqSlice<A>) }
290 }
291}
292
293impl<A: Codec, const K: usize> AsRef<SeqSlice<A>> for Kmer<A, K, usize> {
294 fn as_ref(&self) -> &SeqSlice<A> {
295 self
296 }
297}
298
299impl<A: Codec, const K: usize, S: KmerStorage> fmt::Display for Kmer<A, K, S> {
300 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
301 let mut s = String::new();
302 let ba = self.bs.to_bitarray();
303 let bs: &Bs = &ba.as_ref()[0..(K * A::BITS as usize)];
304
305 bs.chunks(A::BITS as usize).for_each(|chunk| {
306 s.push(A::unsafe_from_bits(chunk.load_le::<u8>()).to_char());
307 });
308 write!(f, "{s}")
309 }
310}
311
312#[must_use = "iterators are lazy and do nothing unless consumed"]
314pub struct KmerIter<'a, A: Codec, const K: usize> {
315 pub(crate) slice: &'a SeqSlice<A>,
316 pub(crate) index: usize,
317 pub(crate) len: usize,
318 pub(crate) _p: PhantomData<A>,
319}
320
321impl<A: Codec, const K: usize, S: KmerStorage> Kmer<A, K, S> {
322 fn unsafe_from(seq: &SeqSlice<A>) -> Self {
323 Self::assert_k();
324 debug_assert!(K == seq.len(), "K != seq.len()");
325 Kmer {
326 _p: PhantomData,
327 bs: S::from_bitslice(&seq.bs),
328 }
329 }
330}
331
332impl<A: Codec, const K: usize> Iterator for KmerIter<'_, A, K> {
333 type Item = Kmer<A, K>;
334 fn next(&mut self) -> Option<Kmer<A, K>> {
335 let i = self.index;
336 if self.index + K > self.len {
337 return None;
338 }
339 self.index += 1;
340 Some(Kmer::<A, K>::unsafe_from(&self.slice[i..i + K]))
341 }
342
343 fn size_hint(&self) -> (usize, Option<usize>) {
344 let n = (self.len.saturating_sub(self.index) + 1).saturating_sub(K);
345 (n, Some(n))
346 }
347}
348
349impl<A: Codec, const K: usize> ExactSizeIterator for KmerIter<'_, A, K> {}
350
351impl<A: Codec, const K: usize, S: KmerStorage> Hash for Kmer<A, K, S> {
366 fn hash<H: Hasher>(&self, state: &mut H) {
367 state.write(&(K as u64).to_le_bytes());
369 let ba = self.bs.to_bitarray();
370 let bs: &Bs = ba.as_ref();
371 let n_bits = K * A::BITS as usize;
374 crate::hash::hash_bits(&bs[..n_bits], state);
375 }
376}
377
378impl<A: Codec, const K: usize, S: KmerStorage> TryFrom<&SeqSlice<A>> for Kmer<A, K, S> {
379 type Error = ParseBioError;
380
381 fn try_from(seq: &SeqSlice<A>) -> Result<Self, Self::Error> {
382 if seq.len() == K {
383 Ok(Kmer::<A, K, S>::unsafe_from(&seq[0..K]))
384 } else {
385 Err(ParseBioError::MismatchedLength(K, seq.len()))
386 }
387 }
388}
389
390impl<A: Codec, const K: usize> TryFrom<Seq<A>> for Kmer<A, K> {
391 type Error = ParseBioError;
392
393 fn try_from(seq: Seq<A>) -> Result<Self, Self::Error> {
394 Self::try_from(seq.as_ref())
395 }
396}
397
398impl<A: Codec, const K: usize, S: KmerStorage> PartialEq<SeqArray<A, K, 1>> for Kmer<A, K, S> {
399 fn eq(&self, seq: &SeqArray<A, K, 1>) -> bool {
400 if seq.len() != K {
401 return false;
402 }
403 &Kmer::<A, K, S>::unsafe_from(seq.as_ref()) == self
404 }
405}
406
407impl<A: Codec, const K: usize, S: KmerStorage> PartialEq<&SeqArray<A, K, 1>> for Kmer<A, K, S> {
408 fn eq(&self, seq: &&SeqArray<A, K, 1>) -> bool {
409 if seq.len() != K {
410 return false;
411 }
412 &Kmer::<A, K, S>::unsafe_from(seq.as_ref()) == self
413 }
414}
415
416impl<A: Codec, const K: usize> PartialEq<Seq<A>> for Kmer<A, K> {
417 fn eq(&self, seq: &Seq<A>) -> bool {
418 if seq.len() != K {
419 return false;
420 }
421 &Kmer::<A, K>::unsafe_from(seq.as_ref()) == self
422 }
423}
424
425impl<A: Codec, const K: usize, S: KmerStorage> PartialEq<SeqSlice<A>> for Kmer<A, K, S> {
426 fn eq(&self, seq: &SeqSlice<A>) -> bool {
427 if seq.len() != K {
428 return false;
429 }
430 &Kmer::<A, K, S>::unsafe_from(seq) == self
431 }
432}
433
434impl<A: Codec, const K: usize, S: KmerStorage> PartialEq<&SeqSlice<A>> for Kmer<A, K, S> {
435 fn eq(&self, seq: &&SeqSlice<A>) -> bool {
436 if seq.len() != K {
437 return false;
438 }
439 &Kmer::<A, K, S>::unsafe_from(seq) == self
440 }
441}
442
443impl<A: Codec, const K: usize> PartialEq<&str> for Kmer<A, K> {
444 fn eq(&self, seq: &&str) -> bool {
445 &self.to_string() == seq
446 }
447}
448
449impl<A: Codec, const K: usize, S: KmerStorage> FromStr for Kmer<A, K, S> {
450 type Err = ParseBioError;
451
452 fn from_str(s: &str) -> Result<Self, Self::Err> {
453 if s.len() != K {
454 return Err(ParseBioError::MismatchedLength(K, s.len()));
455 }
456 let seq: Seq<A> = Seq::from_str(s)?;
457 Kmer::<A, K, S>::try_from(seq.as_ref())
458 }
459}
460
461impl<A: Codec, const K: usize> From<Kmer<A, K, usize>> for Seq<A> {
462 fn from(kmer: Kmer<A, K, usize>) -> Self {
463 let mut seq: Seq<A> = Seq::with_capacity(K);
464 seq.extend(kmer.iter());
465 seq
466 }
467}
468
469impl<const K: usize, S: KmerStorage> ComplementMut for Kmer<codec::dna::Dna, K, S> {
470 fn comp(&mut self) {
471 self.complement();
472 }
473}
474
475impl<const K: usize, S: KmerStorage> Complement for Kmer<codec::dna::Dna, K, S> {}
476
477impl<A: Codec, const K: usize, S: KmerStorage> ReverseMut for Kmer<A, K, S> {
478 fn rev(&mut self) {
479 self.rev_blocks();
480 }
481}
482
483impl<A: Codec, const K: usize, S: KmerStorage> Reverse for Kmer<A, K, S> {}
484
485impl<const K: usize> ReverseComplementMut for Kmer<codec::dna::Dna, K, usize> {}
486
487impl<const K: usize> ReverseComplement for Kmer<codec::dna::Dna, K, usize> {}
488
489#[macro_export]
497macro_rules! kmer {
498 ($seq:expr) => {
499 $crate::kmer::Kmer::<$crate::codec::dna::Dna, { $seq.len() }>::unsafe_from_seqslice(dna!($seq))
500 };
501 ($seq:expr, $storage:ty) => {
502 $crate::kmer::Kmer::<$crate::codec::dna::Dna, { $seq.len() }, $storage>::unsafe_from_seqslice(
503 dna!($seq),
504 )
505 };
506}
507
508#[cfg(test)]
509mod tests {
510 use crate::prelude::*;
511 use crate::seq::SeqArray;
512
513 #[cfg(target_pointer_width = "64")]
514 #[test]
515 fn kmer_to_usize() {
516 let s: &'static SeqSlice<Dna> = dna!("AACTT");
517 println!("{s}");
518
519 for (kmer, index) in s.kmers::<2>().zip([0b00_00, 0b01_00, 0b11_01, 0b11_11]) {
520 println!("{kmer}");
521 assert_eq!(index, usize::from(&kmer));
522 }
523 }
524 #[test]
525 fn pushl_test() {
526 let k = kmer!("ACGT");
527 let k1 = k.pushl(Dna::G);
528 let k2 = k1.pushl(Dna::A);
529 let k3 = k2.pushl(Dna::T);
530 let k4 = k3.pushl(Dna::C);
531 let k5 = k4.pushl(Dna::C);
532
533 assert_eq!(k1, kmer!("GACG"));
534 assert_eq!(k2, kmer!("AGAC"));
535 assert_eq!(k3, kmer!("TAGA"));
536 assert_eq!(k4, kmer!("CTAG"));
537 assert_eq!(k5, kmer!("CCTA"));
538 }
539 #[test]
540 fn pushr_test() {
541 let k = kmer!("ACGT");
542 let k1 = k.pushr(Dna::G);
543 let k2 = k1.pushr(Dna::A);
544 let k3 = k2.pushr(Dna::T);
545 let k4 = k3.pushr(Dna::C);
546 let k5 = k4.pushr(Dna::C);
547
548 println!("{k1}");
549 assert_eq!(k1, kmer!("CGTG"));
550 assert_eq!(k2, kmer!("GTGA"));
551 assert_eq!(k3, kmer!("TGAT"));
552 assert_eq!(k4, kmer!("GATC"));
553 assert_eq!(k5, kmer!("ATCC"));
554 }
555
556 #[test]
557 fn amino_kmer_to_usize() {
558 for (kmer, index) in Seq::<Amino>::try_from("SRY")
559 .unwrap()
560 .kmers::<2>()
561 .zip([0b0010_0001_1000, 0b0100_1100_1000])
562 {
563 assert_eq!(index, usize::from(&kmer));
564 }
565 }
566 #[test]
567 fn big_kmer_shiftr() {
568 let mut kmer: Kmer<Dna, 32, u64> = kmer!("AATTTGTGGGTTCGTCTGCGGCTCCGCCCTTA", u64);
569 for base in dna!("TACTATGAGGACGATCAGCACCATAAGAACAAA") {
570 kmer = kmer.pushr(base);
571 }
572 assert_eq!(kmer!("ACTATGAGGACGATCAGCACCATAAGAACAAA", u64), kmer);
573 }
574
575 #[test]
576 fn big_kmer_shiftl() {
577 let mut kmer: Kmer<Dna, 32, u64> = kmer!("AATTTGTGGGTTCGTCTGCGGCTCCGCCCTTA", u64);
578 for base in dna!("GTACTATGAGGACGATCAGCACCATAAGAACAAA") {
579 kmer = kmer.pushl(base);
580 }
581 assert_eq!(kmer!("AAACAAGAATACCACGACTAGCAGGAGTATCA", u64), kmer);
582 }
583
584 #[test]
585 fn amino_kmer_iter() {
586 for (kmer, target) in Seq::<Amino>::try_from("SSLMNHKKL")
587 .unwrap()
588 .kmers::<3>()
589 .zip(["SSL", "SLM", "LMN", "MNH", "NHK", "HKK", "KKL"])
590 {
591 assert_eq!(kmer, target);
592 }
593 }
594
595 #[test]
596 fn test_rotations() {
597 let kmer: Kmer<Dna, 9> = Kmer::try_from(dna!("ACTGCGATG")).unwrap();
598
599 for (rotation, shift) in [
600 "ACTGCGATG",
601 "CTGCGATGA",
602 "TGCGATGAC",
603 "GCGATGACT",
604 "CGATGACTG",
605 "GATGACTGC",
606 "ATGACTGCG",
607 "TGACTGCGA",
608 "GACTGCGAT",
609 "ACTGCGATG",
610 "CTGCGATGA",
611 "TGCGATGAC",
612 ]
613 .into_iter()
614 .zip(0u32..)
615 {
616 assert_eq!(kmer.rotated_left(shift), rotation);
617 }
618
619 for (rotation, shift) in [
620 "ACTGCGATG",
621 "GACTGCGAT",
622 "TGACTGCGA",
623 "ATGACTGCG",
624 "GATGACTGC",
625 "CGATGACTG",
626 "GCGATGACT",
627 "TGCGATGAC",
628 "CTGCGATGA",
629 "ACTGCGATG",
630 "GACTGCGAT",
631 ]
632 .into_iter()
633 .zip(0u32..)
634 {
635 assert_eq!(kmer.rotated_right(shift), rotation);
636 }
637
638 let kmer: Kmer<Dna, 8> = Kmer::try_from(dna!("ACTGCGAT")).unwrap().rotated_left(1);
639
640 assert_ne!(kmer.to_string(), "ACTGCGAT");
641 assert_eq!(kmer.to_string(), "CTGCGATA");
642
643 let kmer: Kmer<Dna, 8> = kmer!("ACTGCGAT").rotated_right(1);
644
645 assert_ne!(kmer.to_string(), "ACTGCGAT");
646 assert_eq!(kmer.to_string(), "TACTGCGA");
647
648 let kmer: Kmer<Dna, 9> = Kmer::from_str("ACTGCGATG").unwrap().rotated_left(0);
649
650 assert_eq!(kmer.to_string(), "ACTGCGATG");
651 assert_ne!(kmer.to_string(), "ACTGCGATGA");
652
653 let kmer: Kmer<Dna, 9> = Kmer::try_from(dna!("ACTGCGATG")).unwrap().rotated_right(0);
654
655 assert_eq!(kmer.to_string(), "ACTGCGATG");
656 assert_ne!(kmer.to_string(), "ACTGCGATGA");
657
658 let kmer: Kmer<Dna, 9> = Kmer::from_str("ACTGCGATG").unwrap().rotated_left(9 * 3307);
659
660 assert_eq!(kmer.to_string(), "ACTGCGATG");
661 assert_ne!(kmer.to_string(), "ACTGCGATGA");
662
663 let kmer: Kmer<Dna, 9> = kmer!("ACTGCGATG").rotated_right(9 * 3307);
664
665 assert_eq!(kmer.to_string(), "ACTGCGATG");
666 assert_ne!(kmer.to_string(), "ACTGCGATGA");
667 }
668
669 #[test]
670 fn eq_functions() {
671 assert_eq!(kmer!("ACGT"), dna!("ACGT"));
672
673 let kmer: Kmer<Iupac, 4> = Kmer::from_str("ACGT").unwrap();
677 assert_eq!(kmer, iupac!("ACGT"));
678 assert_ne!(kmer, iupac!("NCGT"));
679 }
680
681 #[test]
682 fn kmer_iter() {
683 let cs: Vec<Kmer<Dna, 3>> = dna!("ACTGA").kmers().collect();
685 assert_eq!(cs[0], "ACT");
686 assert_eq!(cs[1], "CTG");
687 assert_eq!(cs[2], "TGA");
688 assert_eq!(cs.len(), 3);
689 }
690
691 #[test]
692 fn k_check() {
693 let _kmer = Kmer::<Dna, 32>::from(0);
694 let _kmer = Kmer::<Amino, 10>::from(0);
695 let _kmer = Kmer::<Iupac, 14>::from(0);
696 }
697
698 #[test]
699 fn kmer_revcomp() {
700 assert_eq!(kmer!("ACGT"), kmer!("ACGT").to_revcomp());
701 assert_ne!(kmer!("GTCGTA"), kmer!("TACGAC"));
702
703 let rc = kmer!("GTCGTA").to_revcomp();
704
705 assert_eq!(rc, kmer!("TACGAC"));
706
707 assert_eq!(
708 kmer!("GCTATCGATCTGATCG"),
709 kmer!("CGATCAGATCGATAGC").to_revcomp()
710 );
711 }
712
713 #[test]
714 fn kmer_deref() {
715 let kmer: Kmer<Dna, 3> = kmer!("ACG");
716 let seq: &SeqSlice<Dna> = &kmer;
717
718 assert_eq!(*seq, *kmer);
719 assert_eq!(seq.to_string(), "ACG");
720
721 let kmer: Kmer<Dna, 8> = kmer!("AAAAAAAA");
722 let seq: &SeqSlice<Dna> = &kmer;
723
724 assert_eq!(seq.to_string(), "AAAAAAAA");
725
726 let kmer: Kmer<Dna, 8> = kmer!("TTTTTTTT");
727 let seq: &SeqSlice<Dna> = &kmer;
728
729 assert_eq!(seq.to_string(), "TTTTTTTT");
730
731 let kmer: Kmer<Dna, 16> = kmer!("AGCTAGCTAGCTAGCT");
732 let seq: &SeqSlice<Dna> = &kmer;
733
734 assert_eq!(seq.to_string(), "AGCTAGCTAGCTAGCT");
735 }
736
737 #[test]
738 fn kmer_as_ref() {
739 let kmer: Kmer<Dna, 4> = kmer!("ACGT");
740 let seq: &SeqSlice<Dna> = kmer.as_ref();
741
742 assert_eq!(seq.to_string(), "ACGT");
743
744 let kmer: Kmer<Dna, 16> = kmer!("AGCTAGCTAGCTAGCT");
745 let seq: &SeqSlice<Dna> = kmer.as_ref();
746
747 assert_eq!(seq.to_string(), "AGCTAGCTAGCTAGCT");
748 }
749
750 #[test]
751 fn kmer_rev() {
752 let mut kmer: Kmer<Dna, 4> = kmer!("ACGT");
753
754 kmer.rev();
755
756 assert_eq!(kmer.to_string(), "TGCA");
757
758 kmer.rev();
759
760 assert_eq!(kmer.to_string(), "ACGT");
761
762 kmer.rev();
763
764 assert_eq!(kmer.to_string(), "TGCA");
765 }
766
767 #[test]
768 fn kmer_storage_types() {
769 let s1 = "AACGTAGCCGCGAACTTACGTAGCCGCGAAAA";
770 let s2 = "AACGTAGCCGCGAACTTACGTAGCCGCGAAA";
771 let s3 = "ACGTAGCCGCGAACTTACGTAGCCGCGAAAA";
772
773 let s4 = "AACGTAGCCGCGAACTTACGTAGCCGCGAAAAAACGTAGCCGCGAACTTACGTAGCCGCGAAAA";
774 let s5 = "AACGTAGCCGCGAACTTACGTAGCCGCGAAAAAACGTAGCCGCGAACTTACGTAGCCGCGAAAAA";
775
776 assert_eq!(s1.len(), 32);
777 assert_eq!(s2.len(), 31);
778 assert_eq!(s3.len(), 31);
779 assert_eq!(s4.len(), 64);
780 assert_eq!(s5.len(), 65);
781
782 let kmer1_64 = Kmer::<Dna, 32, u64>::from_str(s1).unwrap();
783 let kmer2_64 = Kmer::<Dna, 31, u64>::from_str(s2).unwrap();
784 let kmer3_64 = Kmer::<Dna, 31, u64>::from_str(s3).unwrap();
785
786 let kmer1 = Kmer::<Dna, 32, u64>::from_str(s1).unwrap();
787 let kmer2 = Kmer::<Dna, 31, u64>::from_str(s2).unwrap();
788 let kmer3 = Kmer::<Dna, 31, u64>::from_str(s3).unwrap();
789
790 let kmer4_128 = Kmer::<Dna, 64, u128>::from_str(s4).unwrap();
791
792 let seq5: Seq<Dna> = s5.try_into().unwrap();
793
794 assert_eq!(kmer4_128, &seq5[..64]);
795 assert_ne!(kmer4_128, &seq5[1..]);
796
797 assert_eq!(kmer1, &seq5[..32]);
798 assert_eq!(kmer1, &seq5[32..64]);
799
800 assert_eq!(kmer1_64, &seq5[..32]);
801 assert_eq!(kmer1_64, &seq5[32..64]);
802
803 assert_ne!(kmer1, &seq5[..31]);
804 assert_ne!(kmer1, &seq5[32..]);
805
806 assert_ne!(kmer1_64, &seq5[1..33]);
807 assert_ne!(kmer1_64, &seq5[33..]);
808
809 assert_eq!(kmer4_128, kmer4_128);
810 assert_eq!(kmer1_64, kmer1_64);
811 assert_eq!(kmer2, kmer2);
812
813 assert_ne!(kmer2, kmer3);
814 assert_ne!(kmer2_64, kmer3_64);
815 }
822
823 #[test]
824 fn try_from_seq() {
825 let seq: Seq<Dna> = Seq::try_from("ACACACACACACGT").unwrap();
826 assert_eq!(
827 Kmer::<Dna, 8>::try_from(&seq[..8]).unwrap().to_string(),
828 "ACACACAC"
829 );
830 assert_eq!(
831 Kmer::<Dna, 8>::try_from(&seq[1..9]).unwrap().to_string(),
832 "CACACACA"
833 );
834
835 let err: Result<Kmer<Dna, 8>, ParseBioError> = Kmer::try_from(&seq[2..9]);
836 assert_eq!(err, Err(ParseBioError::MismatchedLength(8, 7)));
837
838 let err: Result<Kmer<Dna, 8>, ParseBioError> = Kmer::try_from(seq);
839 assert_eq!(err, Err(ParseBioError::MismatchedLength(8, 14)));
840
841 let seq: Seq<Dna> = Seq::try_from("ACACACACACACGT").unwrap();
842
843 assert_eq!(
844 Kmer::<Dna, 14>::try_from(seq).unwrap().to_string(),
845 "ACACACACACACGT"
846 );
847 }
848
849 #[test]
850 fn two_bit_reversal_table() {
851 let generate = std::hint::black_box(super::make_2bit_table as fn() -> [u8; 256]);
852 let table = generate();
853
854 for input in 0u8..=u8::MAX {
855 let mut rem = input;
856 let mut expected = 0u8;
857
858 for _ in 0..4 {
859 expected = (expected << 2) | (rem & 0b11);
860 rem >>= 2;
861 }
862
863 let i = usize::from(input);
864 assert_eq!(table[i], expected, "input={input:#010b}");
865 assert_eq!(super::REV_2BIT[i], expected, "input={input:#010b}");
866 }
867 }
868
869 #[test]
870 fn kmer_is_nonempty() {
871 let k: Kmer<Dna, 1> = "A".parse().unwrap();
872 assert!(!k.is_empty());
873 }
874}