1pub mod index;
10pub mod iterators;
11
12mod array;
13mod slice;
14
15pub use array::SeqArray;
16pub use slice::SeqSlice;
17
18use crate::codec::{Codec, text};
19use crate::error::ParseBioError;
20use crate::{
21 Complement, ComplementMut, Maskable, MaskableMut, Reverse, ReverseComplement,
22 ReverseComplementMut, ReverseMut,
23};
24
25use crate::{Bs, Bv, Order};
26
27use bitvec::field::BitField;
28use bitvec::view::BitView;
29
30#[cfg(feature = "serde")]
31use serde::{Deserialize, Serialize};
32
33use core::borrow::Borrow;
34use core::hash::{Hash, Hasher};
35use core::marker::PhantomData;
36use core::ops::{Bound, Deref, RangeBounds};
37use core::str::FromStr;
38use core::{fmt, ptr, str};
39
40#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
44#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
45#[repr(transparent)]
46pub struct Seq<A: Codec> {
47 pub(crate) _p: PhantomData<A>,
48 pub(crate) bv: Bv,
49}
50
51impl<A: Codec> From<Seq<A>> for usize {
52 fn from(seq: Seq<A>) -> usize {
53 debug_assert!(seq.bv.len() <= usize::BITS as usize);
54 if seq.bv.is_empty() {
55 0
56 } else {
57 seq.bv.load_le::<usize>() }
59 }
60}
61
62impl<A: Codec> Hash for Seq<A> {
63 fn hash<H: Hasher>(&self, state: &mut H) {
64 self.as_ref().hash(state);
65 }
67}
68
69impl<A: Codec> Default for Seq<A> {
70 fn default() -> Self {
71 Self::new()
72 }
73}
74
75impl<A: Codec> Seq<A> {
76 #[must_use]
77 pub fn new() -> Self {
78 Seq {
79 _p: PhantomData,
80 bv: Bv::new(),
81 }
82 }
83
84 fn bit_range<R: RangeBounds<usize>>(&self, range: R) -> (usize, usize) {
85 let s = match range.start_bound() {
86 Bound::Included(&n) => n,
87 Bound::Excluded(&n) => n.checked_add(1).expect("bound overflow"),
88 Bound::Unbounded => 0,
89 };
90
91 let e = match range.end_bound() {
92 Bound::Included(&n) => n.checked_add(1).expect("bound overflow"),
93 Bound::Excluded(&n) => n,
94 Bound::Unbounded => self.len(),
95 };
96
97 assert!(s <= e, "Start of range must be less than or equal to end");
98 assert!(e <= self.len(), "Range out of bounds");
99
100 (s * A::BITS as usize, e * A::BITS as usize)
101 }
102
103 pub fn trim_u8(v: &[u8]) -> Result<Self, ParseBioError> {
116 let start = v
117 .iter()
118 .position(|&byte| A::try_from_ascii(byte).is_some())
119 .unwrap_or(v.len());
120
121 let end = v[start..]
122 .iter()
123 .rposition(|&byte| A::try_from_ascii(byte).is_some())
124 .map_or(start, |pos| start + pos + 1);
125
126 v[start..end]
127 .iter()
128 .map(|&byte| A::try_from_ascii(byte).ok_or(ParseBioError::UnrecognisedBase(byte)))
129 .collect()
130 }
131
132 #[must_use]
133 pub fn with_capacity(len: usize) -> Self {
134 Seq {
135 _p: PhantomData,
136 bv: Bv::with_capacity(len * A::BITS as usize),
137 }
138 }
139
140 #[must_use]
141 pub fn bit_and(self, rhs: Seq<A>) -> Seq<A> {
142 Seq::<A> {
143 _p: PhantomData,
144 bv: Bv::from_bitslice(&(self.bv & rhs.bv)),
145 }
146 }
147
148 #[must_use]
149 pub fn bit_or(self, rhs: Seq<A>) -> Seq<A> {
150 Seq::<A> {
151 _p: PhantomData,
152 bv: Bv::from_bitslice(&(self.bv | rhs.bv)),
153 }
154 }
155
156 pub fn push(&mut self, item: A) {
157 let byte: u8 = item.to_bits();
158 self.bv
159 .extend_from_bitslice(&byte.view_bits::<Order>()[..A::BITS as usize]);
160 }
161
162 pub fn clear(&mut self) {
163 self.bv.clear();
164 }
165
166 pub fn truncate(&mut self, len: usize) {
174 self.bv.truncate(len * A::BITS as usize);
175 }
176
177 pub fn prepend(&mut self, other: &SeqSlice<A>) {
185 let mut bv = Bv::with_capacity(self.bv.len() + other.bs.len());
186 bv.extend_from_bitslice(&other.bs);
187 bv.extend_from_bitslice(&self.bv);
188 self.bv = bv;
189 }
190
191 pub fn append(&mut self, other: &SeqSlice<A>) {
199 self.bv.extend_from_bitslice(&other.bs);
200 }
201
202 pub fn splice<R: RangeBounds<usize>>(&mut self, range: R, other: &SeqSlice<A>) {
210 let (s, e) = self.bit_range(range);
211
212 let mut bv = Bv::with_capacity(self.bv.len() - (e - s) + other.bs.len());
213
214 bv.extend_from_bitslice(&self.bs[..s]);
215 bv.extend_from_bitslice(&other.bs);
216 bv.extend_from_bitslice(&self.bs[e..]);
217
218 self.bv = bv;
219 }
220
221 pub fn insert(&mut self, index: usize, other: &SeqSlice<A>) {
232 assert!(index <= self.len(), "Index out of bounds");
233
234 let i = index * A::BITS as usize;
235 let mut bv = Bv::with_capacity(self.bv.len() + other.bs.len());
236
237 bv.extend_from_bitslice(&self.bs[..i]);
238 bv.extend_from_bitslice(&other.bs);
239 bv.extend_from_bitslice(&self.bs[i..]);
240
241 self.bv = bv;
242 }
243
244 pub fn remove<R: RangeBounds<usize>>(&mut self, range: R) {
252 let (s, e) = self.bit_range(range);
253 self.bv.drain(s..e);
254 }
255
256 pub fn extend_from_iter<I: IntoIterator<Item = A>>(&mut self, iter: I) {
257 iter.into_iter().for_each(|base| self.push(base));
258 }
259
260 #[must_use]
268 pub fn from_raw(len: usize, bits: &[usize]) -> Option<Self> {
269 let mut bv: Bv = Bv::from_slice(bits);
270 let bit_len = len.checked_mul(A::BITS as usize)?;
271
272 if bit_len > bv.len() {
273 return None;
274 }
275 bv.truncate(bit_len);
276 Some(Seq {
277 _p: PhantomData,
278 bv,
279 })
280 }
281
282 #[must_use]
291 pub fn into_raw(&self) -> &[usize] {
292 self.bv.as_raw_slice()
293 }
294}
295
296impl<A: Codec> ReverseMut for Seq<A> {
297 fn rev(&mut self) {
298 self.bv.reverse();
299 for chunk in self.bv.rchunks_exact_mut(A::BITS as usize) {
300 chunk.reverse();
301 }
302 }
303}
304
305impl<A: Codec + ComplementMut> ComplementMut for Seq<A> {
306 fn comp(&mut self) {
307 unsafe {
308 for base in self.bv.chunks_exact_mut(A::BITS as usize).remove_alias() {
309 let mut bc = A::unsafe_from_bits(base.load_le::<u8>());
310 bc.comp();
311 base.store(bc.to_bits() as usize);
312 }
313 }
314 }
315}
316
317impl<A: Codec + MaskableMut> MaskableMut for Seq<A> {
318 fn mask(&mut self) {
319 unsafe {
320 for base in self.bv.chunks_exact_mut(A::BITS as usize).remove_alias() {
321 let mut bc = A::unsafe_from_bits(base.load_le::<u8>());
322 bc.mask();
323 base.store(bc.to_bits() as usize);
324 }
325 }
326 }
327 fn unmask(&mut self) {
328 unsafe {
329 for base in self.bv.chunks_exact_mut(A::BITS as usize).remove_alias() {
330 let mut bc = A::unsafe_from_bits(base.load_le::<u8>());
331 bc.unmask();
332 base.store(bc.to_bits() as usize);
333 }
334 }
335 }
336}
337
338impl<A: Codec + MaskableMut> Maskable for Seq<A> {}
339
340impl<A: Codec + ComplementMut> ReverseComplementMut for Seq<A> where
341 Seq<A>: ComplementMut + ReverseMut
342{
343}
344
345impl<A: Codec> Reverse for Seq<A> {}
346
347impl<A: Codec + ComplementMut> Complement for Seq<A> {}
348
349impl<A: Codec + ComplementMut> ReverseComplement for Seq<A> where Seq<A>: ComplementMut + ReverseMut {}
350
351impl<A: Codec> PartialEq<SeqSlice<A>> for Seq<A> {
352 fn eq(&self, other: &SeqSlice<A>) -> bool {
353 self.as_ref() == other
354 }
355}
356
357impl<A: Codec> PartialEq<&SeqSlice<A>> for Seq<A> {
358 fn eq(&self, other: &&SeqSlice<A>) -> bool {
359 self.as_ref() == *other
360 }
361}
362
363impl<A: Codec> PartialEq<Seq<A>> for &Seq<A> {
364 fn eq(&self, other: &Seq<A>) -> bool {
365 **self == *other
366 }
367}
368
369impl<A: Codec> PartialEq<&Seq<A>> for Seq<A> {
370 fn eq(&self, other: &&Seq<A>) -> bool {
371 *self == **other
372 }
373}
374
375impl<A: Codec> Borrow<SeqSlice<A>> for Seq<A> {
399 fn borrow(&self) -> &SeqSlice<A> {
400 self.as_ref()
401 }
402}
403
404impl<A: Codec> Borrow<SeqSlice<A>> for &Seq<A> {
405 fn borrow(&self) -> &SeqSlice<A> {
406 self.as_ref()
407 }
408}
409
410impl<A: Codec> Deref for Seq<A> {
424 type Target = SeqSlice<A>;
425
426 fn deref(&self) -> &Self::Target {
427 let bs: *const Bs = ptr::from_ref::<Bs>(&self.bv);
428 unsafe { &*(bs as *const SeqSlice<A>) }
429 }
430}
431
432impl<A: Codec> AsRef<SeqSlice<A>> for Seq<A> {
446 fn as_ref(&self) -> &SeqSlice<A> {
447 self
448 }
449}
450
451impl<A: Codec> Clone for Seq<A> {
464 fn clone(&self) -> Self {
465 Self {
466 _p: PhantomData,
467 bv: self.bv.clone(),
468 }
469 }
470}
471
472impl<A: Codec> FromIterator<A> for Seq<A> {
473 fn from_iter<I: IntoIterator<Item = A>>(iter: I) -> Self {
474 let i = iter.into_iter();
475 let mut seq = Seq::with_capacity(i.size_hint().0);
476 seq.extend(i);
477 seq
478 }
479}
480
481impl<A: Codec> From<&Vec<A>> for Seq<A> {
482 fn from(vec: &Vec<A>) -> Self {
483 vec.iter().copied().collect()
486 }
487}
488
489impl<A: Codec + Into<B>, B: Codec> From<&SeqSlice<A>> for Seq<B> {
490 fn from(slice: &SeqSlice<A>) -> Self {
491 slice.iter().map(Into::into).collect()
492 }
493}
494
495impl<A: Codec + Into<B>, B: Codec, const N: usize, const W: usize> From<&SeqArray<A, N, W>>
496 for Seq<B>
497{
498 fn from(slice: &SeqArray<A, N, W>) -> Self {
499 slice.iter().map(Into::into).collect()
500 }
501}
502
503impl<A: Codec + Into<B>, B: Codec, const N: usize, const W: usize> From<SeqArray<A, N, W>>
504 for Seq<B>
505{
506 fn from(slice: SeqArray<A, N, W>) -> Self {
507 slice.iter().map(Into::into).collect()
508 }
509}
510
511impl<A: Codec> TryFrom<&str> for Seq<A> {
512 type Error = ParseBioError;
513
514 fn try_from(s: &str) -> Result<Self, Self::Error> {
515 Seq::<A>::try_from(s.as_bytes())
516 }
517}
518
519impl<A: Codec> TryFrom<String> for Seq<A> {
520 type Error = ParseBioError;
521
522 fn try_from(s: String) -> Result<Self, Self::Error> {
523 Seq::<A>::try_from(s.as_str())
524 }
525}
526
527impl<A: Codec> TryFrom<&String> for Seq<A> {
528 type Error = ParseBioError;
529
530 fn try_from(s: &String) -> Result<Self, Self::Error> {
531 Seq::<A>::try_from(s.as_str())
532 }
533}
534
535impl<A: Codec> FromStr for Seq<A> {
536 type Err = ParseBioError;
537
538 fn from_str(s: &str) -> Result<Self, Self::Err> {
539 Seq::<A>::try_from(s)
540 }
541}
542
543impl<A: Codec> TryFrom<&[u8]> for Seq<A> {
544 type Error = ParseBioError;
545
546 fn try_from(v: &[u8]) -> Result<Self, Self::Error> {
547 v.iter()
548 .copied()
549 .map(|byte| A::try_from_ascii(byte).ok_or(ParseBioError::UnrecognisedBase(byte)))
550 .collect()
551 }
552}
553
554impl<A: Codec> TryFrom<Vec<u8>> for Seq<A> {
555 type Error = ParseBioError;
556
557 fn try_from(v: Vec<u8>) -> Result<Self, Self::Error> {
558 v.into_iter()
562 .map(|byte| A::try_from_ascii(byte).ok_or(ParseBioError::UnrecognisedBase(byte)))
563 .collect()
564 }
565}
566
567impl<A: Codec> From<Seq<A>> for String {
568 fn from(seq: Seq<A>) -> Self {
569 String::from(seq.as_ref())
570 }
571}
572
573impl<A: Codec> From<&Seq<A>> for String {
574 fn from(seq: &Seq<A>) -> Self {
575 String::from(seq.as_ref())
576 }
577}
578
579impl<A: Codec> fmt::Display for Seq<A> {
580 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
581 fmt::Display::fmt(self.as_ref(), f)
582 }
583}
584
585impl<A: Codec> Extend<A> for Seq<A> {
586 fn extend<T: IntoIterator<Item = A>>(&mut self, iter: T) {
587 self.extend_from_iter(iter);
588 }
589}
590
591impl From<Vec<usize>> for Seq<text::Dna> {
592 fn from(vec: Vec<usize>) -> Self {
593 Seq {
594 _p: PhantomData,
595 bv: Bv::from_vec(vec),
596 }
597 }
598}
599
600impl<A: Codec> From<&Bs> for Seq<A> {
602 fn from(bs: &Bs) -> Self {
603 Seq {
604 _p: PhantomData,
605 bv: bs.into(),
606 }
607 }
608}
609
610impl<A: Codec> From<Bv> for Seq<A> {
612 fn from(bv: Bv) -> Self {
613 Seq {
614 _p: PhantomData,
615 bv,
616 }
617 }
618}
619
620#[cfg(test)]
621mod tests {
622 use crate::codec::text;
623 use crate::prelude::*;
624 use crate::{Bv, Order};
625 use bitvec::prelude::*;
626 use core::borrow::Borrow;
627 use core::hash::{Hash, Hasher};
628 use core::marker::PhantomData;
629 use std::collections::hash_map::DefaultHasher;
630
631 #[test]
632 fn test_revcomp() {
633 let s1: Seq<Dna> = dna!("ATGTGTGCGACTGA").into();
634 let mut s2: Seq<Dna> = dna!("TCAGTCGCACACAT").into();
635 let s3: &SeqSlice<Dna> = &s1;
636
637 assert_eq!(s3.to_revcomp(), s2.to_revcomp().to_revcomp());
638 assert_eq!(s3.to_revcomp(), &s2);
639
640 s2.revcomp();
641
642 assert_eq!(s3.to_revcomp(), s2.to_revcomp());
643 assert_ne!(s3, s2.to_revcomp());
644 }
645
646 #[test]
647 fn test_revcomp_mismatched_sizes() {
648 let s1 = dna!("AAAA");
649 let mut s2: Seq<Dna> = dna!("TTTTT").into();
650 s2.revcomp();
651 assert_ne!(s1, s2);
652 }
653
654 #[test]
655 fn test_revcomp_idempotence() {
656 let mut s = dna!("AAACGCTACGTACGCGCCTTCGGGGCATCAGCACCAC").to_owned();
657 let sc = dna!("AAACGCTACGTACGCGCCTTCGGGGCATCAGCACCAC");
658 s.revcomp();
659 assert_eq!(s.to_revcomp(), sc);
660 s.comp();
661 s.rev();
662 s.rev();
663 s.comp();
664 assert_eq!(s.to_revcomp(), sc);
665 }
666 #[test]
667 fn slice_index_comparisions() {
668 let s1 = dna!("ATGTGTGCGACTGATGATCAAACGTAGCTACG");
669 let s2 = dna!("ACGTGTGTGCTAGCTAATCGATCAAAAAG");
670
671 assert_eq!(&s1[0], &s2[0]);
672 assert_ne!(&s1[1], &s2[1]);
673 assert_eq!(&s1[2..4], &s2[2..4]);
674 assert_eq!(&s1[15..21], &s2[19..25]);
675 assert_ne!(&s1[2..20], &s2[2..20]);
676 }
677
678 #[test]
679 #[expect(clippy::redundant_slicing, reason = "exercise full-range indexing")]
680 fn slice_index_owned() {
681 let seq = dna!("GCTCGATCACT");
682
683 assert_eq!(&seq[..], dna!("GCTCGATCACT"));
684 assert_eq!(&seq[..=4], dna!("GCTCG"));
685 assert_eq!(&seq[1..=4], dna!("CTCG"));
686 assert_eq!(&seq[1..4], dna!("CTC"));
687 assert_eq!(&seq[..4], dna!("GCTC"));
688 assert_eq!(&seq[1..], dna!("CTCGATCACT"));
689 }
690
691 #[test]
692 #[expect(clippy::redundant_slicing, reason = "exercise full-range indexing")]
693 fn slice_indexing() {
694 let seq = dna!("TGCATCGAT");
695
696 assert_ne!(&seq[..], &dna!("AGCATCGAA")[..]);
697 assert_ne!(&seq[3..=6], &dna!("ATC")[..]);
698 assert_ne!(&seq[..=6], &dna!("TGCATC")[..]);
699 assert_ne!(&seq[4..5], &dna!("TC")[..]);
700 assert_ne!(&seq[..6], &dna!("TGCAT")[..]);
701 assert_ne!(&seq[5..], &dna!("TCGAT")[..]);
702
703 assert_eq!(&seq[..], &dna!("TGCATCGAT")[..]);
704 assert_eq!(&seq[3..=6], &dna!("ATCG")[..]);
705 assert_eq!(&seq[..=6], &dna!("TGCATCG")[..]);
706 assert_eq!(&seq[4..5], &dna!("T")[..]);
707 assert_eq!(&seq[..6], &dna!("TGCATC")[..]);
708 assert_eq!(&seq[5..], &dna!("CGAT")[..]);
709 }
710
711 #[test]
712 #[expect(clippy::redundant_slicing, reason = "exercise full-range indexing")]
713 fn slice_index_ranges() {
714 let s1: &'static SeqSlice<Dna> = dna!("ACGACTGATCGA");
715 let s2: &'static SeqSlice<Dna> = dna!("TCGAACGACTGA");
716
717 assert_eq!(&s1[..8], &s2[4..]);
718 assert_eq!(&s1[8..], &s2[..4]);
719 assert_ne!(&s1[8..], &s2[8..]);
720 assert_ne!(&s1[..], &s2[..4]);
721
722 assert_eq!(&s1[..=7], &s2[4..]);
723 assert_eq!(&s1[8..], &s2[..=3]);
724 assert_ne!(&s1[8..11], &s2[8..=11]);
725 assert_ne!(&s1[..], &s2[..=4]);
726 }
727
728 #[test]
729 fn slice_nth() {
730 let s = dna!("ATGTGTGCGACTGATGATCAAACGTAGCTACG");
731
732 assert_eq!(s.nth(0), Dna::A);
733 assert_ne!(s.nth(0), Dna::G);
734
735 assert_eq!(s.nth(1), Dna::T);
736 assert_ne!(s.nth(1), Dna::C);
737
738 assert_eq!(s.nth(s.len() - 1), Dna::G);
739 assert_ne!(s.nth(s.len() - 1), Dna::C);
740 }
741
742 #[test]
743 #[expect(clippy::redundant_slicing, reason = "exercise full-range indexing")]
744 fn slice_rangeto_and_full() {
745 let s1 = dna!("ATCGACTAGCATGCTACG");
746 let s2 = dna!("ATCGACTAG");
747
748 assert_eq!(&s1[..s2.len()], &s2[..]);
749 assert_ne!(&s2[..s2.len()], &s1[..]);
750 }
751
752 #[test]
753 fn from_slice() {
754 let s1 = dna!("ATGTGTGCGACTGATGATCAAACGTAGCTACG");
755 let s: &SeqSlice<Dna> = &s1[15..21];
756 assert_eq!(format!("{s}"), "GATCAA");
757 }
758
759 #[test]
760 fn string_to_seq() {
761 let seq_str = "ACTGACTG";
762 let seq: Result<Seq<Dna>, _> = seq_str.try_into();
763 assert!(seq.is_ok());
764 assert_eq!(seq.unwrap().to_string(), seq_str);
765 }
766
767 #[test]
768 fn invalid_string_to_seq() {
769 let invalid_seq_str = "ACUGACTG";
770 let seq: Result<Seq<Dna>, _> = invalid_seq_str.try_into();
771 assert!(seq.is_err());
772 }
773
774 #[test]
775 fn seq_to_string() {
776 let seq_str = "ACTGACTG";
777 let seq: Seq<Dna> = seq_str.try_into().unwrap();
778 let result_str: String = seq.into();
779 assert_eq!(result_str, seq_str);
780 }
781
782 #[test]
783 fn seqslice_to_string() {
784 let seq_str = "ACTGACTG";
785 let seq: Seq<Dna> = seq_str.try_into().unwrap();
786 let slice = &seq[1..5];
787 let result_str: String = slice.into();
788 assert_eq!(result_str, "CTGA");
789 }
790
791 #[test]
792 #[should_panic(expected = "range 2..18 out of bounds: 16")]
793 fn invalid_seqslice_to_string() {
794 let seq_str = "ACTGACTG";
795 let seq: Seq<Dna> = seq_str.try_into().unwrap();
796 let _ = &seq[1..9];
797 }
798
799 #[test]
800 fn test_push() {
801 let mut seq = Seq::<Dna>::new();
802 seq.push(Dna::A);
803 seq.push(Dna::C);
804 seq.push(Dna::G);
805 seq.push(Dna::T);
806
807 assert_eq!(seq.len(), 4);
808 assert_eq!(String::from(seq), "ACGT");
809 }
810
811 #[test]
812 fn test_extend_amino() {
813 let mut seq = Seq::<Amino>::new();
814 seq.push(Amino::S);
815 seq.push(Amino::L);
816
817 seq.extend(vec![Amino::Y, Amino::M]);
818
819 assert_eq!(seq.len(), 4);
820 assert_eq!(String::from(seq), "SLYM");
821 }
822 #[test]
823 fn test_extend() {
824 let mut seq = Seq::<Dna>::new();
825 seq.push(Dna::A);
826 seq.push(Dna::C);
827
828 seq.extend(vec![Dna::G, Dna::T]);
829
830 assert_eq!(seq.len(), 4);
831 assert_eq!(String::from(seq), "ACGT");
832 }
833
834 #[test]
835 fn test_eqs() {
836 let seq: Seq<Dna> = "ACTAGCATCGA".try_into().unwrap();
837 let seq2: Seq<Dna> = "ACTAGCATCGA".try_into().unwrap();
838 let slice: &SeqSlice<Dna> = &seq;
839 let slice2: &SeqSlice<Dna> = &seq2[..];
840 assert_eq!(seq, slice);
841 assert_eq!(seq2, slice);
842 assert_eq!(seq2, slice2);
843 assert_eq!(slice, slice2);
844 assert_eq!(seq, seq2);
845 }
846
847 #[test]
848 fn test_str_eqs() {
849 let string: String = "ACTAGCATCGA".into();
850 let slice: &str = "GCTGCATCGATC";
851
852 let seq1: Seq<Dna> = Seq::<Dna>::try_from(slice).unwrap();
853 let seq2: Seq<Dna> = Seq::<Dna>::try_from(string.clone()).unwrap();
854
855 assert_eq!(seq2.to_string(), string);
856 assert_eq!(seq1.to_string(), slice);
857
858 assert_ne!(seq2.to_string(), slice);
859 assert_ne!(seq1.to_string(), string);
860 }
861
862 #[test]
863 fn test_from_iter() {
864 let iter = vec![Dna::A, Dna::C, Dna::G, Dna::T].into_iter();
865 let seq: Seq<Dna> = Seq::from_iter(iter);
866
867 assert_eq!(seq.len(), 4);
868 assert_eq!(String::from(seq), "ACGT");
869 }
870
871 #[test]
872 fn test_bit_order() {
873 let raw: usize = 0b10_11_01_11_10_01_00_01;
874 let mut bv: Bv = BitVec::default();
875 bv.extend(&raw.view_bits::<Order>()[..(Dna::BITS as usize * 8)]);
876 let s = Seq::<Dna> {
877 bv,
878 _p: PhantomData,
879 };
880 assert_eq!(dna!("CACGTCTG").to_string(), "CACGTCTG");
881 assert_eq!(String::from(s), "CACGTCTG");
882 }
884
885 #[test]
886 fn test_borrow() {
887 let seq: Seq<Dna> = dna!("ACGACCCCCATAGATGGGCTG").into();
888 let slice: &SeqSlice<Dna> = seq.borrow();
889 assert_eq!(slice, &seq[..]);
890 assert_ne!(slice, &seq[1..]);
891 }
892
893 #[test]
894 #[expect(
895 clippy::explicit_auto_deref,
896 reason = "exercise the Deref implementation"
897 )]
898 fn test_deref() {
899 let seq: Seq<Dna> = dna!("AGAATGATCG").into();
900 let slice: &SeqSlice<Dna> = &*seq;
901
902 assert_eq!(slice, &seq[..]);
903 assert_ne!(slice, &seq[1..]);
904 }
905
906 #[test]
907 fn test_asref() {
908 let seq: Seq<Dna> = dna!("AGAATGATCAAAATATATATAAAG").into();
909 let slice: &SeqSlice<Dna> = seq.as_ref();
910 assert_ne!(slice, &seq[2..5]);
911 assert_eq!(slice, &seq[..]);
912 }
913
914 #[test]
915 fn test_to_owned() {
916 let seq: Seq<Dna> = dna!("AGAATGAATCG").into();
917 let slice: &SeqSlice<Dna> = &seq;
918 let owned: Seq<Dna> = slice[2..5].to_owned();
919 assert_eq!(&owned, &seq[2..5]);
920 assert_eq!(owned, seq[2..5].to_owned());
921 assert_ne!(&owned, &seq[..]);
922 }
923
924 #[test]
925 fn test_clone() {
926 let seq: Seq<Dna> = dna!("AGAATGATGGGGGGGGGGGCG").into();
927 let cloned = seq.clone();
928 assert_eq!(seq, cloned);
929 }
930 #[test]
931 fn test_trim() {
932 let seq = b"AGAATGATGGGGGGGGGGGCG";
933 let s: Seq<Dna> = Seq::trim_u8(seq).unwrap();
934 assert_eq!(s, dna!("AGAATGATGGGGGGGGGGGCG"));
935
936 let seq = b"NNNNAGAATGATGGGGGGGGGGGCGNNNNNNNNNNN";
937 let s: Seq<Dna> = Seq::trim_u8(seq).unwrap();
938 assert_eq!(s, dna!("AGAATGATGGGGGGGGGGGCG"));
939
940 let seq = b"NNNNAGAATGATGGGGNGGGGGGGCGNNNNNNNNNNN";
941 let s: Result<Seq<Dna>, ParseBioError> = Seq::trim_u8(seq);
942 assert_eq!(s, Err(ParseBioError::UnrecognisedBase(b'N')));
943
944 let seq = b"AGAATGATGGGGGGGGGGGCG";
945 let s: Seq<Dna> = Seq::trim_u8(seq).unwrap();
946 assert_eq!(s, dna!("AGAATGATGGGGGGGGGGGCG"));
947
948 let seq = b"NNNNAGAATGATGGGGGGGGGGGCGNNNNNNNNNNN";
949 let s: Seq<Dna> = Seq::trim_u8(seq).unwrap();
950 assert_eq!(s, dna!("AGAATGATGGGGGGGGGGGCG"));
951
952 let seq = b"NNNNAGAATGATGGGGNGGGGGGGCGNNNNNNNNNNN";
953 let s: Result<Seq<Dna>, ParseBioError> = Seq::trim_u8(seq);
954 assert_eq!(s, Err(ParseBioError::UnrecognisedBase(b'N')));
955
956 let seq = b"";
957 let s: Result<Seq<Dna>, ParseBioError> = Seq::trim_u8(seq);
958 assert!(s.is_ok());
959 assert_eq!(s.unwrap(), dna!(""));
960
961 let seq = b"XXXX";
962 let s: Result<Seq<Dna>, ParseBioError> = Seq::trim_u8(seq);
963 assert!(s.is_ok());
964 assert_eq!(s.unwrap(), dna!(""));
965
966 let seq = b"XXACGT";
967 let s: Seq<Dna> = Seq::trim_u8(seq).unwrap();
968 assert_eq!(s, dna!("ACGT"));
969
970 let seq = b"ACGTXX";
971 let s: Seq<Dna> = Seq::trim_u8(seq).unwrap();
972 assert_eq!(s, dna!("ACGT"));
973
974 let seq = b"ACGTACGTACGTACGTACGTACGT";
975 let s: Seq<Dna> = Seq::trim_u8(seq).unwrap();
976 assert_eq!(s, dna!("ACGTACGTACGTACGTACGTACGT"));
977
978 let seq = b"XXACGTXXACGTXX";
979 let s: Result<Seq<Dna>, ParseBioError> = Seq::trim_u8(seq);
980 assert_eq!(s, Err(ParseBioError::UnrecognisedBase(b'X')));
981
982 let seq = b"A";
983 let s: Seq<Dna> = Seq::trim_u8(seq).unwrap();
984 assert_eq!(s, dna!("A"));
985
986 let seq = b"X";
987 let s: Result<Seq<Dna>, ParseBioError> = Seq::trim_u8(seq);
988 assert!(s.is_ok());
989 assert_eq!(s.unwrap(), dna!(""));
990
991 }
1005
1006 #[test]
1007 fn test_seq_eq_and_hash() {
1008 let seq1: Seq<Dna> = "ACGT".try_into().unwrap();
1009 let seq2: Seq<Dna> = "ACGT".try_into().unwrap();
1010
1011 assert_eq!(seq1, seq2);
1013
1014 let mut hasher1 = DefaultHasher::new();
1016 seq1.hash(&mut hasher1);
1017 let hash1 = hasher1.finish();
1018
1019 let mut hasher2 = DefaultHasher::new();
1020 seq2.hash(&mut hasher2);
1021 let hash2 = hasher2.finish();
1022
1023 assert_eq!(hash1, hash2);
1024
1025 assert_eq!(record(&seq1), [4, 0, 0, 0, 0, 0, 0, 0, 0xe4]);
1026 }
1027
1028 #[test]
1029 #[expect(
1030 clippy::similar_names,
1031 reason = "names identify the source sequence and slice variant"
1032 )]
1033 fn test_seq_slice_eq() {
1034 let seq1: Seq<Dna> = "ACGTAAAAAAAAAAAAACGTAAAACCCCGGGGTTTTA".try_into().unwrap();
1035 let seq2: Seq<Dna> = "ACGTAAAAAAAAAAAAACGTAAAACCCCGGGGTTTTAA".try_into().unwrap();
1036
1037 let slice1a: &SeqSlice<Dna> = &seq1[..];
1038 let slice1b: &SeqSlice<Dna> = &seq1[..];
1039 let slice2a: &SeqSlice<Dna> = &seq2[..seq2.len() - 1];
1040 let slice2b: &SeqSlice<Dna> = &seq2[..seq2.len() - 1];
1041
1042 let seq3: Seq<Dna> = slice2b.into();
1043
1044 assert_eq!(slice1a, slice2b);
1045 assert_eq!(&slice2a, &slice2b);
1046 assert_eq!(seq1, slice2a);
1047 assert_eq!(slice1b, seq3);
1048 assert_eq!(slice1a, slice1b);
1049 assert_eq!(seq1, seq3);
1050
1051 assert_ne!(seq1, seq2);
1052 assert_ne!(seq2, seq3);
1053 assert_ne!(seq2, slice2a);
1054 assert_ne!(seq2, slice1b);
1055
1056 assert_eq!(&slice1a, &slice1b);
1057
1058 assert_eq!(seq1, &seq1);
1059
1060 assert_eq!(seq1, &seq3);
1061 assert_eq!(&seq1, seq3);
1062 assert_eq!(&seq1, &seq3);
1063
1064 assert_eq!(slice1a, seq3);
1065 assert_eq!(seq1, slice2a);
1068 assert_eq!(&seq1, slice2a);
1069 assert_eq!(&seq1, slice2a);
1072 }
1073 #[test]
1074 fn test_seq_slice_hash() {
1075 let seq1: Seq<Dna> = "ACGTAAAAAAAAAAAAACGTAAAACCCCGGGGAAAAA".try_into().unwrap();
1076 let seq2: Seq<Dna> = "ACGTAAAAAAAAAAAAACGTAAAACCCCGGGGAAAAA".try_into().unwrap();
1077
1078 let seq3: Seq<Dna> = "ACGTAAAAAAAAAAAAACGTAAAACCCCGGGG".try_into().unwrap();
1079
1080 let slice1 = &seq1[..];
1081 let slice2 = &seq2[..];
1082
1083 let slice3 = &seq3[..];
1084
1085 let slice1_32 = &seq1[..32];
1086
1087 let mut hasher1 = DefaultHasher::new();
1088 seq1.hash(&mut hasher1);
1089 let full1 = hasher1.finish();
1090
1091 let mut hasher1a = DefaultHasher::new();
1092 seq1.hash(&mut hasher1a);
1093 let full1_alt = hasher1a.finish();
1094
1095 let mut hasher2 = DefaultHasher::new();
1096 seq2.hash(&mut hasher2);
1097 let full2 = hasher2.finish();
1098
1099 let mut hasher3 = DefaultHasher::new();
1100 slice1.hash(&mut hasher3);
1101 let full1_slice = hasher3.finish();
1102
1103 let mut hasher4 = DefaultHasher::new();
1104 slice2.hash(&mut hasher4);
1105 let full2_slice = hasher4.finish();
1106
1107 let mut hasher5 = DefaultHasher::new();
1108 slice3.hash(&mut hasher5);
1109 let short1_slice = hasher5.finish();
1110
1111 let mut hasher6 = DefaultHasher::new();
1112 slice1_32.hash(&mut hasher6);
1113 let seq1_short = hasher6.finish();
1114
1115 assert_eq!(full1, full1_alt);
1116 assert_eq!(full1, full2);
1117 assert_ne!(full2_slice, short1_slice);
1118 assert_eq!(full2, full1_slice);
1119 assert_eq!(short1_slice, seq1_short);
1120 assert_ne!(seq1_short, full1_slice);
1121
1122 assert_ne!(full1, short1_slice);
1123 }
1124
1125 #[test]
1126 fn test_fromstr() {
1127 let seq: Result<Seq<Dna>, ParseBioError> =
1128 "ACGATGAGTAGTCGCCATCGTATCTTTGACTGCCGATGCTA".parse();
1129 assert!(seq.is_ok());
1130
1131 let seq: Result<Seq<Dna>, ParseBioError> =
1132 "ACGATGAGTAGBCGCCATCGTATCTTTGACTGCCGATGCTA".parse();
1133 assert_eq!(seq, Err(ParseBioError::UnrecognisedBase(b'B')));
1134 }
1135
1136 #[test]
1137 fn test_lens() {
1138 assert_eq!(iupac!("AWANWATNA---SKAGTCAA").len(), 20);
1139 }
1140
1141 #[test]
1142 fn test_unique_bitarray_ident() {
1143 let s1 = dna!(
1144 "ATCGACTACGATCGCTACGATCGATCGATCGATCGAATCTCCCGCGCGATCATCGATCATCGCTACGTACGTCGAAAAATATAATGGG"
1145 );
1146 let s2 = dna!(
1147 "ATCGACTACGATCGCTACGATCGATCGATCGATCGAATCTCCCGCGCGATCATCGATCATCGCTACGTACGTCGAAAAATATAATGGG"
1148 );
1149
1150 let s3 = dna!(
1152 "CTCGACTACGATCGCTACGATCGATCGATCGATCGAATCTCCCGCGCGATCATCGATCATCGCTACGTACGTCGAAAAATATAATGGG"
1153 );
1154
1155 let s4 = dna!(
1157 "ATCGACTACGATCGCTACGATCGATCGATCGATCGAATCTCCCGCGCGATCATCGATCATCGCTACGTACGTCGAAAAATATAATGGGA"
1158 );
1159
1160 let s5 = dna!(
1162 "ATCGACTACGATCGCTACGATCGATCGATCGATCGAATCTCCCGCGCGATCATCGATCATCGCTACGTACGTCGAAAAATATAATGGC"
1163 );
1164
1165 assert_eq!(s1, s2);
1166 assert_ne!(s1, s3);
1167
1168 assert_ne!(s1.len(), s4.len());
1170 assert_ne!(s4.len(), s1.len());
1171
1172 assert_ne!(s5, s1);
1173 }
1174
1175 #[test]
1176 fn test_static() {
1177 use crate::seq::SeqArray;
1178
1179 static B: SeqArray<Dna, 5, 1> = SeqArray {
1180 _p: PhantomData,
1181 ba: bitarr![const usize, Lsb0; 1,1,0,1,0,0,1,0,1,1],
1182 };
1183
1184 let s: &'static SeqSlice<Dna> = &B;
1185
1186 let x: &'static str = "TGACT";
1187
1188 assert_eq!(s.to_string(), x);
1189 }
1190
1191 #[test]
1192 fn test_to_from_raw() {
1193 let s = "TCAGCTAGCTACGACTGATCGATCGACTGATGCCGCGCGCGGCGCCGCGCGCGCGCGCCGCGCGCCCCGCGCGCGGCGCGCGCCGCGCGCGCGCGCGGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGC";
1194
1195 let seq: Seq<Dna> = s.try_into().unwrap();
1196 let raw = seq.into_raw();
1197 let new = Seq::<Dna>::from_raw(s.len(), raw);
1198 assert_eq!(new.unwrap(), seq);
1199
1200 let bad = Seq::<Dna>::from_raw(s.len() + 1, raw);
1201 assert_ne!(bad.unwrap(), seq);
1202
1203 let bad = Seq::<Dna>::from_raw(342, raw);
1204 assert_eq!(bad, None);
1205 }
1206 #[test]
1207 fn test_seq_and_seq_slice_eq_and_hash() {
1208 let seq: Seq<text::Dna> = Seq::try_from("ACGT".to_string()).unwrap();
1209 let slice = &seq[..];
1210
1211 assert_eq!(seq, slice);
1213 assert_eq!(&seq, slice);
1214 assert_eq!(slice, &seq);
1215
1216 let mut hasher1 = std::collections::hash_map::DefaultHasher::new();
1218 seq.hash(&mut hasher1);
1219 let hash1 = hasher1.finish();
1220
1221 let mut hasher2 = std::collections::hash_map::DefaultHasher::new();
1222 slice.hash(&mut hasher2);
1223 let hash2 = hasher2.finish();
1224
1225 assert_eq!(hash1, hash2);
1226 }
1227
1228 #[derive(Default)]
1229 struct RecordingHasher(Vec<u8>);
1230
1231 impl Hasher for RecordingHasher {
1232 fn finish(&self) -> u64 {
1233 0
1234 }
1235 fn write(&mut self, bytes: &[u8]) {
1236 self.0.extend_from_slice(bytes);
1237 }
1238 }
1239
1240 fn record<T: Hash>(value: &T) -> Vec<u8> {
1241 let mut h = RecordingHasher::default();
1242 value.hash(&mut h);
1243 h.0
1244 }
1245
1246 #[test]
1247 fn test_hash_byte_stream_invariants() {
1248 fn check<A: Codec>(s: &str) {
1253 let seq: Seq<A> = s.try_into().unwrap_or_else(|_| panic!("parse {s:?}"));
1254 let bytes = record(&seq);
1255 assert_eq!(record::<&SeqSlice<A>>(&&seq[..]), bytes);
1256
1257 let n = seq.len();
1259 let body = (n * A::BITS as usize).div_ceil(8);
1260 assert_eq!(bytes.len(), 8 + body);
1261 assert_eq!(&bytes[..8], &(n as u64).to_le_bytes());
1262 }
1263 check::<Dna>("A");
1264 check::<Dna>("ACGT");
1265 check::<Dna>("ACGTA");
1266 check::<Dna>(&"ACGT".repeat(80)); check::<Iupac>("AC");
1268 check::<Iupac>("ACG");
1269 check::<Iupac>("NRYKBDHV");
1270 check::<Amino>("MWLLP"); check::<text::Dna>("ACGT"); }
1273
1274 #[test]
1275 fn test_kmer_hash_independent_of_storage_width() {
1276 let seq: Seq<Dna> = "ACGTACGTAC".try_into().unwrap();
1277 let slice: &SeqSlice<Dna> = &seq[..];
1278 let bytes = record(&slice);
1279 let km_usize: Kmer<Dna, 10, usize> = slice.try_into().unwrap();
1280 let km_u64: Kmer<Dna, 10, u64> = slice.try_into().unwrap();
1281 let km_u128: Kmer<Dna, 10, u128> = slice.try_into().unwrap();
1282 assert_eq!(record(&km_usize), bytes);
1283 assert_eq!(record(&km_u64), bytes);
1284 assert_eq!(record(&km_u128), bytes);
1285 }
1286
1287 #[test]
1288 fn test_prepend() {
1289 let mut seq1 =
1290 Seq::<Dna>::from_str("GCTCGATCGATCGATCGACTGACTGACGCGCGCATCCGATAAAAAAAAT").unwrap();
1291 seq1.prepend(dna!("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"));
1292 assert_eq!(
1293 seq1.to_string(),
1294 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGCTCGATCGATCGATCGACTGACTGACGCGCGCATCCGATAAAAAAAAT"
1295 );
1296
1297 let mut seq2 =
1298 Seq::<Dna>::from_str("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA").unwrap();
1299 seq2.prepend(dna!("GCTCGATCGATCGATCGACTGACTGACGCGCGCATCCGATAAAAAAAAT"));
1300 assert_eq!(
1301 seq2.to_string(),
1302 "GCTCGATCGATCGATCGACTGACTGACGCGCGCATCCGATAAAAAAAATAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
1303 );
1304
1305 assert_ne!(seq1, seq2);
1306 }
1307
1308 #[test]
1309 fn test_append() {
1310 let mut seq1 =
1311 Seq::<Dna>::from_str("GCTCGATCGATCGATCGACTGACTGACGCGCGCATCCGATAAAAAAAAT").unwrap();
1312 seq1.append(dna!("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"));
1313 assert_eq!(
1314 seq1.to_string(),
1315 "GCTCGATCGATCGATCGACTGACTGACGCGCGCATCCGATAAAAAAAATAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
1316 );
1317
1318 let mut seq2 =
1319 Seq::<Dna>::from_str("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA").unwrap();
1320 seq2.append(dna!("GCTCGATCGATCGATCGACTGACTGACGCGCGCATCCGATAAAAAAAAT"));
1321 assert_eq!(
1322 seq2.to_string(),
1323 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGCTCGATCGATCGATCGACTGACTGACGCGCGCATCCGATAAAAAAAAT"
1324 );
1325
1326 assert_ne!(seq1, seq2);
1327 }
1328
1329 #[test]
1330 fn test_remove() {
1331 let mut seq: Seq<Dna> = dna!("TCAGCATCGATCAATCG").into();
1332 seq.remove(4..6);
1333 assert_eq!(&seq, dna!("TCAGTCGATCAATCG"));
1334 seq.remove(..4);
1335 assert_eq!(&seq, dna!("TCGATCAATCG"));
1336 seq.remove(6..);
1337 assert_eq!(&seq, dna!("TCGATC"));
1338 }
1339
1340 #[test]
1341 fn test_insert() {
1342 let mut seq: Seq<Dna> = dna!("TCAGCATCGATCAATCG").into();
1343 let insertion = dna!("CCCCC");
1344
1345 seq.insert(4, insertion);
1346 assert_eq!(&seq, dna!("TCAGCCCCCCATCGATCAATCG"));
1347
1348 seq.insert(seq.len(), dna!("AAAAA"));
1349 assert_eq!(&seq, dna!("TCAGCCCCCCATCGATCAATCGAAAAA"));
1350 }
1351
1352 #[test]
1353 fn test_truncate() {
1354 let mut seq: Seq<Dna> = dna!("TCAGCATCGATCAATCG").into();
1355
1356 seq.truncate(seq.len());
1357 assert_eq!(&seq, dna!("TCAGCATCGATCAATCG"));
1358
1359 seq.truncate(10);
1360 assert_eq!(&seq, dna!("TCAGCATCGA"));
1361
1362 seq.truncate(0);
1363 assert_eq!(&seq, dna!(""));
1364 }
1365
1366 #[test]
1367 fn test_long_splice() {
1368 let mut seq: Seq<Dna> = dna!("TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT").into();
1369 let insertion = dna!("CCCCCCC");
1370
1371 seq.splice(32..38, insertion);
1372 assert_eq!(
1373 &seq,
1374 dna!("TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTCCCCCCCTTTTTTTTTTT")
1375 );
1376
1377 seq.splice(1..=1, dna!("AAA"));
1378 assert_eq!(
1379 &seq,
1380 dna!("TAAATTTTTTTTTTTTTTTTTTTTTTTTTTTTTTCCCCCCCTTTTTTTTTTT")
1381 );
1382
1383 seq.splice(10.., dna!("GGGG"));
1384 assert_eq!(&seq, dna!("TAAATTTTTTGGGG"));
1385 }
1386
1387 #[test]
1388 fn test_splice() {
1389 let mut seq: Seq<Dna> = dna!("TCAGCATCGATCAATCGT").into();
1390 let insertion = dna!("CCCCC");
1391
1392 seq.splice(4..6, insertion);
1393 assert_eq!(&seq, dna!("TCAGCCCCCTCGATCAATCGT"));
1394
1395 seq.splice(1..=1, dna!("AAA"));
1396 assert_eq!(&seq, dna!("TAAAAGCCCCCTCGATCAATCGT"));
1397
1398 seq.splice(10.., dna!("TTTT"));
1399 assert_eq!(&seq, dna!("TAAAAGCCCCTTTT"));
1400 }
1401}