Skip to main content

bio_seq/
seq.rs

1// Copyright 2021-2024 Jeff Knaggs
2// Licensed under the MIT license (http://opensource.org/licenses/MIT)
3// This file may not be copied, modified, or distributed
4// except according to those terms.
5
6//! Arbitrary length sequences of bit-packed genomic data
7//!
8//! `Seq` and `&SeqSlice` are analogous to `String` and `&str`. A `Seq` owns its data and a `SeqSlice` is a read-only window into a `Seq`.
9pub 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/// A arbitrary length sequence of bit-packed symbols
41///
42/// Stored on the heap
43#[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>() //.wrapping_shr(shift)
58        }
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        //self.len().hash(state);
66    }
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    pub fn new() -> Self {
77        Seq {
78            _p: PhantomData,
79            bv: Bv::new(),
80        }
81    }
82
83    fn bit_range<R: RangeBounds<usize>>(&self, range: R) -> (usize, usize) {
84        let s = match range.start_bound() {
85            Bound::Included(&n) => n,
86            Bound::Excluded(&n) => n.checked_add(1).expect("bound overflow"),
87            Bound::Unbounded => 0,
88        };
89
90        let e = match range.end_bound() {
91            Bound::Included(&n) => n.checked_add(1).expect("bound overflow"),
92            Bound::Excluded(&n) => n,
93            Bound::Unbounded => self.len(),
94        };
95
96        assert!(s <= e, "Start of range must be less than or equal to end");
97        assert!(e <= self.len(), "Range out of bounds");
98
99        (s * A::BITS as usize, e * A::BITS as usize)
100    }
101
102    /// Trim leading and trailing characters that don't match bases/symbols
103    /// ```
104    /// # use bio_seq::prelude::*;
105    /// let seq = b"NNNNAGAATGATGGGGGGGGGGGCGNNNNNNNNNNN";
106    /// let trimmed: Seq<Dna> = Seq::trim_u8(seq).unwrap();
107    /// assert_eq!(trimmed, dna!("AGAATGATGGGGGGGGGGGCG"));
108    /// ```
109    ///
110    /// # Errors
111    ///
112    /// Will return an `UnrecognisedBase` error for non-leading or non-trailing end bases, just as
113    /// `TryFrom<&[u8]>` would.
114    pub fn trim_u8(v: &[u8]) -> Result<Self, ParseBioError> {
115        let start = v
116            .iter()
117            .position(|&byte| A::try_from_ascii(byte).is_some())
118            .unwrap_or(v.len());
119
120        let end = v[start..]
121            .iter()
122            .rposition(|&byte| A::try_from_ascii(byte).is_some())
123            .map_or(start, |pos| start + pos + 1);
124
125        v[start..end]
126            .iter()
127            .map(|&byte| A::try_from_ascii(byte).ok_or(ParseBioError::UnrecognisedBase(byte)))
128            .collect()
129    }
130
131    pub fn with_capacity(len: usize) -> Self {
132        Seq {
133            _p: PhantomData,
134            bv: Bv::with_capacity(len * A::BITS as usize),
135        }
136    }
137
138    pub fn bit_and(self, rhs: Seq<A>) -> Seq<A> {
139        Seq::<A> {
140            _p: PhantomData,
141            bv: Bv::from_bitslice(&(self.bv & rhs.bv)),
142        }
143    }
144
145    pub fn bit_or(self, rhs: Seq<A>) -> Seq<A> {
146        Seq::<A> {
147            _p: PhantomData,
148            bv: Bv::from_bitslice(&(self.bv | rhs.bv)),
149        }
150    }
151
152    pub fn push(&mut self, item: A) {
153        let byte: u8 = item.to_bits();
154        self.bv
155            .extend_from_bitslice(&byte.view_bits::<Order>()[..A::BITS as usize]);
156    }
157
158    pub fn clear(&mut self) {
159        self.bv.clear();
160    }
161
162    /// Truncate a sequence
163    /// ```
164    /// # use bio_seq::prelude::*;
165    /// let mut seq: Seq<Dna> = dna!("CCCCC").into();
166    /// seq.truncate(2);
167    /// assert_eq!(&seq, dna!("CC"));
168    /// ```
169    pub fn truncate(&mut self, len: usize) {
170        self.bv.truncate(len * A::BITS as usize);
171    }
172
173    /// Prepend a slice
174    /// ```
175    /// # use bio_seq::prelude::*;
176    /// let mut seq: Seq<Dna> = dna!("CCCCC").into();
177    /// seq.prepend(dna!("TTTT"));
178    /// assert_eq!(&seq, dna!("TTTTCCCCC"));
179    /// ```
180    pub fn prepend(&mut self, other: &SeqSlice<A>) {
181        let mut bv = Bv::with_capacity(self.bv.len() + other.bs.len());
182        bv.extend_from_bitslice(&other.bs);
183        bv.extend_from_bitslice(&self.bv);
184        self.bv = bv;
185    }
186
187    /// Append a slice
188    /// ```
189    /// # use bio_seq::prelude::*;
190    /// let mut seq: Seq<Dna> = dna!("CCCCC").into();
191    /// seq.append(dna!("TTTT"));
192    /// assert_eq!(&seq, dna!("CCCCCTTTT"));
193    /// ```
194    pub fn append(&mut self, other: &SeqSlice<A>) {
195        self.bv.extend_from_bitslice(&other.bs);
196    }
197
198    /// Remove a range and replace it with a slice
199    /// ```
200    /// # use bio_seq::prelude::*;
201    /// let mut seq: Seq<Dna> = dna!("AAAACCAAAA").into();
202    /// seq.splice(4..6, dna!("TTTT"));
203    /// assert_eq!(&seq, dna!("AAAATTTTAAAA"));
204    /// ```
205    pub fn splice<R: RangeBounds<usize>>(&mut self, range: R, other: &SeqSlice<A>) {
206        let (s, e) = self.bit_range(range);
207
208        let mut bv = Bv::with_capacity(self.bv.len() - (e - s) + other.bs.len());
209
210        bv.extend_from_bitslice(&self.bs[..s]);
211        bv.extend_from_bitslice(&other.bs);
212        bv.extend_from_bitslice(&self.bs[e..]);
213
214        self.bv = bv;
215    }
216
217    /// Insert a slice into a sequence
218    /// ```
219    /// # use bio_seq::prelude::*;
220    /// let mut seq: Seq<Dna> = dna!("AAAAA").into();
221    /// seq.insert(3, dna!("TTTT"));
222    /// assert_eq!(&seq, dna!("AAATTTTAA"));
223    /// ```
224    ///
225    /// # Panics
226    /// Panics if index out of bounds
227    pub fn insert(&mut self, index: usize, other: &SeqSlice<A>) {
228        assert!(index <= self.len(), "Index out of bounds");
229
230        let i = index * A::BITS as usize;
231        let mut bv = Bv::with_capacity(self.bv.len() + other.bs.len());
232
233        bv.extend_from_bitslice(&self.bs[..i]);
234        bv.extend_from_bitslice(&other.bs);
235        bv.extend_from_bitslice(&self.bs[i..]);
236
237        self.bv = bv;
238    }
239
240    /// Remove a region of a sequence
241    /// ```
242    /// # use bio_seq::prelude::*;
243    /// let mut seq: Seq<Dna> = dna!("ACGTACGT").into();
244    /// seq.remove(2..5);
245    /// assert_eq!(&seq, dna!("ACCGT"));
246    /// ```
247    pub fn remove<R: RangeBounds<usize>>(&mut self, range: R) {
248        let (s, e) = self.bit_range(range);
249        self.bv.drain(s..e);
250    }
251
252    pub fn extend_from_iter<I: IntoIterator<Item = A>>(&mut self, iter: I) {
253        iter.into_iter().for_each(|base| self.push(base));
254    }
255
256    /// **Experimental** Decode sequence from raw `usize` array. This requires the exact length of the target sequence to be known.
257    /// ```
258    /// # use bio_seq::prelude::*;
259    /// let ints: [usize; 2] = [0b0101010101010101010101010101010111111111111111111111111111111111, 0b11100100];
260    /// let seq: Option<Seq<Dna>> = Seq::from_raw(36, &ints);
261    /// assert_eq!(seq.unwrap(), dna!("TTTTTTTTTTTTTTTTCCCCCCCCCCCCCCCCACGT"));
262    /// ```
263    pub fn from_raw(len: usize, bits: &[usize]) -> Option<Self> {
264        let mut bv: Bv = Bv::from_slice(bits);
265        let bit_len = len.checked_mul(A::BITS as usize)?;
266
267        if bit_len > bv.len() {
268            return None;
269        }
270        bv.truncate(bit_len);
271        Some(Seq {
272            _p: PhantomData,
273            bv,
274        })
275    }
276
277    /// **Experimental** Access raw sequence data as `&[usize]`
278    /// ```
279    /// # use bio_seq::prelude::*;
280    /// let seq: Seq<Dna> = dna!("TTTTTTTTTTTTTTTTCCCCCCCCCCCCCCCCACGT").into();
281    /// let ints: Vec<usize> = seq.into_raw().iter().copied().collect();
282    /// assert_eq!(ints[0], 0b0101010101010101010101010101010111111111111111111111111111111111);
283    /// assert_eq!(ints[1], 0b11100100); // ACGT
284    /// ```
285    pub fn into_raw(&self) -> &[usize] {
286        self.bv.as_raw_slice()
287    }
288}
289
290impl<A: Codec> ReverseMut for Seq<A> {
291    fn rev(&mut self) {
292        self.bv.reverse();
293        for chunk in self.bv.rchunks_exact_mut(A::BITS as usize) {
294            chunk.reverse();
295        }
296    }
297}
298
299impl<A: Codec + ComplementMut> ComplementMut for Seq<A> {
300    fn comp(&mut self) {
301        unsafe {
302            for base in self.bv.chunks_exact_mut(A::BITS as usize).remove_alias() {
303                let mut bc = A::unsafe_from_bits(base.load_le::<u8>());
304                bc.comp();
305                base.store(bc.to_bits() as usize);
306            }
307        }
308    }
309}
310
311impl<A: Codec + MaskableMut> MaskableMut for Seq<A> {
312    fn mask(&mut self) {
313        unsafe {
314            for base in self.bv.chunks_exact_mut(A::BITS as usize).remove_alias() {
315                let mut bc = A::unsafe_from_bits(base.load_le::<u8>());
316                bc.mask();
317                base.store(bc.to_bits() as usize);
318            }
319        }
320    }
321    fn unmask(&mut self) {
322        unsafe {
323            for base in self.bv.chunks_exact_mut(A::BITS as usize).remove_alias() {
324                let mut bc = A::unsafe_from_bits(base.load_le::<u8>());
325                bc.unmask();
326                base.store(bc.to_bits() as usize);
327            }
328        }
329    }
330}
331
332impl<A: Codec + MaskableMut> Maskable for Seq<A> {}
333
334impl<A: Codec + ComplementMut> ReverseComplementMut for Seq<A> where
335    Seq<A>: ComplementMut + ReverseMut
336{
337}
338
339impl<A: Codec> Reverse for Seq<A> {}
340
341impl<A: Codec + ComplementMut> Complement for Seq<A> {}
342
343impl<A: Codec + ComplementMut> ReverseComplement for Seq<A> where Seq<A>: ComplementMut + ReverseMut {}
344
345impl<A: Codec> PartialEq<SeqSlice<A>> for Seq<A> {
346    fn eq(&self, other: &SeqSlice<A>) -> bool {
347        self.as_ref() == other
348    }
349}
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<Seq<A>> for &Seq<A> {
358    fn eq(&self, other: &Seq<A>) -> bool {
359        **self == *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
369/// Borrow a `Seq<A>` as a `SeqSlice<A>`.
370///
371/// The `Borrow` trait to is used to obtain a reference to a `SeqSlice` from a `Seq`, allowing it to be used wherever a `SeqSlice` is expected.
372/// ```
373/// use std::collections::HashMap;
374/// use bio_seq::prelude::*;
375///
376/// let reference = dna!("ACGTTCGCATGCTACGACGATC");
377///
378/// let mut table: HashMap<Seq<Dna>, usize> = HashMap::new();
379///
380/// // Associate some kind of count with sequences as keys:
381/// table.insert(dna!("ACGTT").into(), 1);
382/// table.insert(dna!("ACACCCCC").into(), 0);
383///
384/// // The query is a short window in the reference `Seq`
385/// let query: &SeqSlice<Dna> = &reference[..5];
386///
387/// if let Some(value) = table.get(query) {
388///        // `SeqSlice` implements `Display`
389///        println!("{query}: {value}");
390/// }
391/// ```
392impl<A: Codec> Borrow<SeqSlice<A>> for Seq<A> {
393    fn borrow(&self) -> &SeqSlice<A> {
394        self.as_ref()
395    }
396}
397
398impl<A: Codec> Borrow<SeqSlice<A>> for &Seq<A> {
399    fn borrow(&self) -> &SeqSlice<A> {
400        self.as_ref()
401    }
402}
403
404/// Automatic dereferencing of `Seq<A>` to `SeqSlice<A>`.
405///
406/// ```
407/// # use bio_seq::prelude::*;
408/// fn count_bases(s: &SeqSlice<Dna>) -> usize {
409///    s.len()
410/// }
411///
412/// let seq: Seq<Dna> = dna!("CATCGATCGATC").into();
413/// let count = count_bases(&seq);
414/// assert_eq!(count, 12);
415/// ```
416///
417impl<A: Codec> Deref for Seq<A> {
418    type Target = SeqSlice<A>;
419
420    fn deref(&self) -> &Self::Target {
421        let bs: *const Bs = ptr::from_ref::<Bs>(&self.bv);
422        unsafe { &*(bs as *const SeqSlice<A>) }
423    }
424}
425
426/// A Seq can be borrowed as a `SeqSlice` through generic constraints.
427///
428/// ```
429/// # use bio_seq::prelude::*;
430/// fn count_bases<S: AsRef<SeqSlice<Dna>>>(s: S) -> usize {
431///    s.as_ref().len()
432/// }
433///
434/// let seq: Seq<Dna> = dna!("CATCGATCGATC").into();
435/// let count = count_bases(seq); // the AsRef implementation allows us to directly pass a Seq
436/// assert_eq!(count, 12);
437/// ```
438///
439impl<A: Codec> AsRef<SeqSlice<A>> for Seq<A> {
440    fn as_ref(&self) -> &SeqSlice<A> {
441        self
442    }
443}
444
445/// Creates a deep copy of the sequence.
446///
447/// ```
448/// #[macro_use]
449/// # use bio_seq::prelude::*;
450/// let mut seq1: Seq<Dna> = dna!("CATCGATCGATC").into();
451/// let seq2: Seq<Dna> = seq1.clone();
452///
453/// seq1.push(Dna::A);
454/// assert_ne!(seq1, seq2);
455/// ```
456///
457impl<A: Codec> Clone for Seq<A> {
458    fn clone(&self) -> Self {
459        Self {
460            _p: PhantomData,
461            bv: self.bv.clone(),
462        }
463    }
464}
465
466impl<A: Codec> FromIterator<A> for Seq<A> {
467    fn from_iter<I: IntoIterator<Item = A>>(iter: I) -> Self {
468        let i = iter.into_iter();
469        let mut seq = Seq::with_capacity(i.size_hint().0);
470        seq.extend(i);
471        seq
472    }
473}
474
475impl<A: Codec> From<&Vec<A>> for Seq<A> {
476    fn from(vec: &Vec<A>) -> Self {
477        // for a general conversion: vec.iter().copied().map(Into::into).collect()
478
479        vec.iter().copied().collect()
480    }
481}
482
483impl<A: Codec, B: Codec> From<&SeqSlice<A>> for Seq<B>
484where
485    A: Into<B>,
486{
487    fn from(slice: &SeqSlice<A>) -> Self {
488        slice.iter().map(Into::into).collect()
489    }
490}
491
492impl<A: Codec, B: Codec, const N: usize, const W: usize> From<&SeqArray<A, N, W>> for Seq<B>
493where
494    A: Into<B>,
495{
496    fn from(slice: &SeqArray<A, N, W>) -> Self {
497        slice.iter().map(Into::into).collect()
498    }
499}
500
501impl<A: Codec, B: Codec, const N: usize, const W: usize> From<SeqArray<A, N, W>> for Seq<B>
502where
503    A: Into<B>,
504{
505    fn from(slice: SeqArray<A, N, W>) -> Self {
506        slice.iter().map(Into::into).collect()
507    }
508}
509
510impl<A: Codec> TryFrom<&str> for Seq<A> {
511    type Error = ParseBioError;
512
513    fn try_from(s: &str) -> Result<Self, Self::Error> {
514        Seq::<A>::try_from(s.as_bytes())
515    }
516}
517
518impl<A: Codec> TryFrom<String> for Seq<A> {
519    type Error = ParseBioError;
520
521    fn try_from(s: String) -> Result<Self, Self::Error> {
522        Seq::<A>::try_from(s.as_str())
523    }
524}
525
526impl<A: Codec> TryFrom<&String> for Seq<A> {
527    type Error = ParseBioError;
528
529    fn try_from(s: &String) -> Result<Self, Self::Error> {
530        Seq::<A>::try_from(s.as_str())
531    }
532}
533
534impl<A: Codec> FromStr for Seq<A> {
535    type Err = ParseBioError;
536
537    fn from_str(s: &str) -> Result<Self, Self::Err> {
538        Seq::<A>::try_from(s)
539    }
540}
541
542impl<A: Codec> TryFrom<&[u8]> for Seq<A> {
543    type Error = ParseBioError;
544
545    fn try_from(v: &[u8]) -> Result<Self, Self::Error> {
546        v.iter()
547            .copied()
548            .map(|byte| A::try_from_ascii(byte).ok_or(ParseBioError::UnrecognisedBase(byte)))
549            .collect()
550    }
551}
552
553impl<A: Codec> TryFrom<Vec<u8>> for Seq<A> {
554    type Error = ParseBioError;
555
556    fn try_from(v: Vec<u8>) -> Result<Self, Self::Error> {
557        // potentional optimisation: with an extra allocation we could
558        // .collect::<Result<Vec<A>, _>>()
559        // .map(|v| { let mut seq = Self::with_capacity etc.
560        v.into_iter()
561            .map(|byte| A::try_from_ascii(byte).ok_or(ParseBioError::UnrecognisedBase(byte)))
562            .collect()
563    }
564}
565
566impl<A: Codec> From<Seq<A>> for String {
567    fn from(seq: Seq<A>) -> Self {
568        String::from(seq.as_ref())
569    }
570}
571
572impl<A: Codec> From<&Seq<A>> for String {
573    fn from(seq: &Seq<A>) -> Self {
574        String::from(seq.as_ref())
575    }
576}
577
578impl<A: Codec> fmt::Display for Seq<A> {
579    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
580        fmt::Display::fmt(self.as_ref(), f)
581    }
582}
583
584impl<A: Codec> Extend<A> for Seq<A> {
585    fn extend<T: IntoIterator<Item = A>>(&mut self, iter: T) {
586        self.extend_from_iter(iter);
587    }
588}
589
590impl From<Vec<usize>> for Seq<text::Dna> {
591    fn from(vec: Vec<usize>) -> Self {
592        Seq {
593            _p: PhantomData,
594            bv: Bv::from_vec(vec),
595        }
596    }
597}
598
599/// **Unstable** construct a `Seq` from a bitslice. This may change in the future.
600impl<A: Codec> From<&Bs> for Seq<A> {
601    fn from(bs: &Bs) -> Self {
602        Seq {
603            _p: PhantomData,
604            bv: bs.into(),
605        }
606    }
607}
608
609/// **Unstable** construct a `Seq` from a bitvec. This may change in the future.
610impl<A: Codec> From<Bv> for Seq<A> {
611    fn from(bv: Bv) -> Self {
612        Seq {
613            _p: PhantomData,
614            bv,
615        }
616    }
617}
618
619#[cfg(test)]
620mod tests {
621    use crate::codec::text;
622    use crate::prelude::*;
623    use crate::{Bv, Order};
624    use bitvec::prelude::*;
625    use core::borrow::Borrow;
626    use core::hash::{Hash, Hasher};
627    use core::marker::PhantomData;
628    use std::collections::hash_map::DefaultHasher;
629
630    #[test]
631    fn test_revcomp() {
632        let s1: Seq<Dna> = dna!("ATGTGTGCGACTGA").into();
633        let mut s2: Seq<Dna> = dna!("TCAGTCGCACACAT").into();
634        let s3: &SeqSlice<Dna> = &s1;
635
636        assert_eq!(s3.to_revcomp(), s2.to_revcomp().to_revcomp());
637        assert_eq!(s3.to_revcomp(), &s2);
638
639        s2.revcomp();
640
641        assert_eq!(s3.to_revcomp(), s2.to_revcomp());
642        assert_ne!(s3, s2.to_revcomp());
643    }
644
645    #[test]
646    fn test_revcomp_mismatched_sizes() {
647        let s1 = dna!("AAAA");
648        let mut s2: Seq<Dna> = dna!("TTTTT").into();
649        s2.revcomp();
650        assert_ne!(s1, s2);
651    }
652
653    #[test]
654    fn test_revcomp_idempotence() {
655        let mut s = dna!("AAACGCTACGTACGCGCCTTCGGGGCATCAGCACCAC").to_owned();
656        let sc = dna!("AAACGCTACGTACGCGCCTTCGGGGCATCAGCACCAC");
657        s.revcomp();
658        assert_eq!(s.to_revcomp(), sc);
659        s.comp();
660        s.rev();
661        s.rev();
662        s.comp();
663        assert_eq!(s.to_revcomp(), sc);
664    }
665    #[test]
666    fn slice_index_comparisions() {
667        let s1 = dna!("ATGTGTGCGACTGATGATCAAACGTAGCTACG");
668        let s2 = dna!("ACGTGTGTGCTAGCTAATCGATCAAAAAG");
669
670        assert_eq!(&s1[0], &s2[0]);
671        assert_ne!(&s1[1], &s2[1]);
672        assert_eq!(&s1[2..4], &s2[2..4]);
673        assert_eq!(&s1[15..21], &s2[19..25]);
674        assert_ne!(&s1[2..20], &s2[2..20]);
675    }
676
677    #[test]
678    #[allow(clippy::redundant_slicing)]
679    fn slice_index_owned() {
680        let seq = dna!("GCTCGATCACT");
681
682        assert_eq!(&seq[..], dna!("GCTCGATCACT"));
683        assert_eq!(&seq[..=4], dna!("GCTCG"));
684        assert_eq!(&seq[1..=4], dna!("CTCG"));
685        assert_eq!(&seq[1..4], dna!("CTC"));
686        assert_eq!(&seq[..4], dna!("GCTC"));
687        assert_eq!(&seq[1..], dna!("CTCGATCACT"));
688    }
689
690    #[test]
691    #[allow(clippy::redundant_slicing)]
692    fn slice_indexing() {
693        let seq = dna!("TGCATCGAT");
694
695        assert_ne!(&seq[..], &dna!("AGCATCGAA")[..]);
696        assert_ne!(&seq[3..=6], &dna!("ATC")[..]);
697        assert_ne!(&seq[..=6], &dna!("TGCATC")[..]);
698        assert_ne!(&seq[4..5], &dna!("TC")[..]);
699        assert_ne!(&seq[..6], &dna!("TGCAT")[..]);
700        assert_ne!(&seq[5..], &dna!("TCGAT")[..]);
701
702        assert_eq!(&seq[..], &dna!("TGCATCGAT")[..]);
703        assert_eq!(&seq[3..=6], &dna!("ATCG")[..]);
704        assert_eq!(&seq[..=6], &dna!("TGCATCG")[..]);
705        assert_eq!(&seq[4..5], &dna!("T")[..]);
706        assert_eq!(&seq[..6], &dna!("TGCATC")[..]);
707        assert_eq!(&seq[5..], &dna!("CGAT")[..]);
708    }
709
710    #[test]
711    #[allow(clippy::redundant_slicing)]
712    fn slice_index_ranges() {
713        let s1: &'static SeqSlice<Dna> = dna!("ACGACTGATCGA");
714        let s2: &'static SeqSlice<Dna> = dna!("TCGAACGACTGA");
715
716        assert_eq!(&s1[..8], &s2[4..]);
717        assert_eq!(&s1[8..], &s2[..4]);
718        assert_ne!(&s1[8..], &s2[8..]);
719        assert_ne!(&s1[..], &s2[..4]);
720
721        assert_eq!(&s1[..=7], &s2[4..]);
722        assert_eq!(&s1[8..], &s2[..=3]);
723        assert_ne!(&s1[8..11], &s2[8..=11]);
724        assert_ne!(&s1[..], &s2[..=4]);
725    }
726
727    #[test]
728    fn slice_nth() {
729        let s = dna!("ATGTGTGCGACTGATGATCAAACGTAGCTACG");
730
731        assert_eq!(s.nth(0), Dna::A);
732        assert_ne!(s.nth(0), Dna::G);
733
734        assert_eq!(s.nth(1), Dna::T);
735        assert_ne!(s.nth(1), Dna::C);
736
737        assert_eq!(s.nth(s.len() - 1), Dna::G);
738        assert_ne!(s.nth(s.len() - 1), Dna::C);
739    }
740
741    #[test]
742    #[allow(clippy::redundant_slicing)]
743    fn slice_rangeto_and_full() {
744        let s1 = dna!("ATCGACTAGCATGCTACG");
745        let s2 = dna!("ATCGACTAG");
746
747        assert_eq!(&s1[..s2.len()], &s2[..]);
748        assert_ne!(&s2[..s2.len()], &s1[..]);
749    }
750
751    #[test]
752    fn from_slice() {
753        let s1 = dna!("ATGTGTGCGACTGATGATCAAACGTAGCTACG");
754        let s: &SeqSlice<Dna> = &s1[15..21];
755        assert_eq!(format!("{s}"), "GATCAA");
756    }
757
758    #[test]
759    fn string_to_seq() {
760        let seq_str = "ACTGACTG";
761        let seq: Result<Seq<Dna>, _> = seq_str.try_into();
762        assert!(seq.is_ok());
763        assert_eq!(seq.unwrap().to_string(), seq_str);
764    }
765
766    #[test]
767    fn invalid_string_to_seq() {
768        let invalid_seq_str = "ACUGACTG";
769        let seq: Result<Seq<Dna>, _> = invalid_seq_str.try_into();
770        assert!(seq.is_err());
771    }
772
773    #[test]
774    fn seq_to_string() {
775        let seq_str = "ACTGACTG";
776        let seq: Seq<Dna> = seq_str.try_into().unwrap();
777        let result_str: String = seq.into();
778        assert_eq!(result_str, seq_str);
779    }
780
781    #[test]
782    fn seqslice_to_string() {
783        let seq_str = "ACTGACTG";
784        let seq: Seq<Dna> = seq_str.try_into().unwrap();
785        let slice = &seq[1..5];
786        let result_str: String = slice.into();
787        assert_eq!(result_str, "CTGA");
788    }
789
790    #[test]
791    #[should_panic(expected = "range 2..18 out of bounds: 16")]
792    fn invalid_seqslice_to_string() {
793        let seq_str = "ACTGACTG";
794        let seq: Seq<Dna> = seq_str.try_into().unwrap();
795        let _ = &seq[1..9];
796    }
797
798    #[test]
799    fn test_push() {
800        let mut seq = Seq::<Dna>::new();
801        seq.push(Dna::A);
802        seq.push(Dna::C);
803        seq.push(Dna::G);
804        seq.push(Dna::T);
805
806        assert_eq!(seq.len(), 4);
807        assert_eq!(String::from(seq), "ACGT");
808    }
809
810    #[test]
811    fn test_extend_amino() {
812        let mut seq = Seq::<Amino>::new();
813        seq.push(Amino::S);
814        seq.push(Amino::L);
815
816        seq.extend(vec![Amino::Y, Amino::M]);
817
818        assert_eq!(seq.len(), 4);
819        assert_eq!(String::from(seq), "SLYM");
820    }
821    #[test]
822    fn test_extend() {
823        let mut seq = Seq::<Dna>::new();
824        seq.push(Dna::A);
825        seq.push(Dna::C);
826
827        seq.extend(vec![Dna::G, Dna::T]);
828
829        assert_eq!(seq.len(), 4);
830        assert_eq!(String::from(seq), "ACGT");
831    }
832
833    #[test]
834    fn test_eqs() {
835        let seq: Seq<Dna> = "ACTAGCATCGA".try_into().unwrap();
836        let seq2: Seq<Dna> = "ACTAGCATCGA".try_into().unwrap();
837        let slice: &SeqSlice<Dna> = &seq;
838        let slice2: &SeqSlice<Dna> = &seq2[..];
839        assert_eq!(seq, slice);
840        assert_eq!(seq2, slice);
841        assert_eq!(seq2, slice2);
842        assert_eq!(slice, slice2);
843        assert_eq!(seq, seq2);
844    }
845
846    #[test]
847    fn test_str_eqs() {
848        let string: String = "ACTAGCATCGA".into();
849        let slice: &str = "GCTGCATCGATC";
850
851        let seq1: Seq<Dna> = Seq::<Dna>::try_from(slice).unwrap();
852        let seq2: Seq<Dna> = Seq::<Dna>::try_from(string.clone()).unwrap();
853
854        assert_eq!(seq2.to_string(), string);
855        assert_eq!(seq1.to_string(), slice);
856
857        assert_ne!(seq2.to_string(), slice);
858        assert_ne!(seq1.to_string(), string);
859    }
860
861    #[test]
862    fn test_from_iter() {
863        let iter = vec![Dna::A, Dna::C, Dna::G, Dna::T].into_iter();
864        let seq: Seq<Dna> = Seq::from_iter(iter);
865
866        assert_eq!(seq.len(), 4);
867        assert_eq!(String::from(seq), "ACGT");
868    }
869
870    #[test]
871    fn test_bit_order() {
872        let raw: usize = 0b10_11_01_11_10_01_00_01;
873        let mut bv: Bv = BitVec::default();
874        bv.extend(&raw.view_bits::<Order>()[..(Dna::BITS as usize * 8)]);
875        let s = Seq::<Dna> {
876            bv,
877            _p: PhantomData,
878        };
879        assert_eq!(dna!("CACGTCTG").to_string(), "CACGTCTG");
880        assert_eq!(String::from(s), "CACGTCTG");
881        //        assert_eq!(raw, Kmer::<Dna, 8>::from(&s[..8]).bs);
882    }
883
884    #[test]
885    fn test_borrow() {
886        let seq: Seq<Dna> = dna!("ACGACCCCCATAGATGGGCTG").into();
887        let slice: &SeqSlice<Dna> = seq.borrow();
888        assert_eq!(slice, &seq[..]);
889        assert_ne!(slice, &seq[1..]);
890    }
891
892    #[test]
893    #[allow(clippy::explicit_auto_deref)]
894    fn test_deref() {
895        let seq: Seq<Dna> = dna!("AGAATGATCG").into();
896        let slice: &SeqSlice<Dna> = &*seq;
897
898        assert_eq!(slice, &seq[..]);
899        assert_ne!(slice, &seq[1..]);
900    }
901
902    #[test]
903    fn test_asref() {
904        let seq: Seq<Dna> = dna!("AGAATGATCAAAATATATATAAAG").into();
905        let slice: &SeqSlice<Dna> = seq.as_ref();
906        assert_ne!(slice, &seq[2..5]);
907        assert_eq!(slice, &seq[..]);
908    }
909
910    #[test]
911    fn test_to_owned() {
912        let seq: Seq<Dna> = dna!("AGAATGAATCG").into();
913        let slice: &SeqSlice<Dna> = &seq;
914        let owned: Seq<Dna> = slice[2..5].to_owned();
915        assert_eq!(&owned, &seq[2..5]);
916        assert_eq!(owned, seq[2..5].to_owned());
917        assert_ne!(&owned, &seq[..]);
918    }
919
920    #[test]
921    fn test_clone() {
922        let seq: Seq<Dna> = dna!("AGAATGATGGGGGGGGGGGCG").into();
923        let cloned = seq.clone();
924        assert_eq!(seq, cloned);
925    }
926    #[test]
927    fn test_trim() {
928        let seq = b"AGAATGATGGGGGGGGGGGCG";
929        let s: Seq<Dna> = Seq::trim_u8(seq).unwrap();
930        assert_eq!(s, dna!("AGAATGATGGGGGGGGGGGCG"));
931
932        let seq = b"NNNNAGAATGATGGGGGGGGGGGCGNNNNNNNNNNN";
933        let s: Seq<Dna> = Seq::trim_u8(seq).unwrap();
934        assert_eq!(s, dna!("AGAATGATGGGGGGGGGGGCG"));
935
936        let seq = b"NNNNAGAATGATGGGGNGGGGGGGCGNNNNNNNNNNN";
937        let s: Result<Seq<Dna>, ParseBioError> = Seq::trim_u8(seq);
938        assert_eq!(s, Err(ParseBioError::UnrecognisedBase(b'N')));
939
940        let seq = b"AGAATGATGGGGGGGGGGGCG";
941        let s: Seq<Dna> = Seq::trim_u8(seq).unwrap();
942        assert_eq!(s, dna!("AGAATGATGGGGGGGGGGGCG"));
943
944        let seq = b"NNNNAGAATGATGGGGGGGGGGGCGNNNNNNNNNNN";
945        let s: Seq<Dna> = Seq::trim_u8(seq).unwrap();
946        assert_eq!(s, dna!("AGAATGATGGGGGGGGGGGCG"));
947
948        let seq = b"NNNNAGAATGATGGGGNGGGGGGGCGNNNNNNNNNNN";
949        let s: Result<Seq<Dna>, ParseBioError> = Seq::trim_u8(seq);
950        assert_eq!(s, Err(ParseBioError::UnrecognisedBase(b'N')));
951
952        let seq = b"";
953        let s: Result<Seq<Dna>, ParseBioError> = Seq::trim_u8(seq);
954        assert!(s.is_ok());
955        assert_eq!(s.unwrap(), dna!(""));
956
957        let seq = b"XXXX";
958        let s: Result<Seq<Dna>, ParseBioError> = Seq::trim_u8(seq);
959        assert!(s.is_ok());
960        assert_eq!(s.unwrap(), dna!(""));
961
962        let seq = b"XXACGT";
963        let s: Seq<Dna> = Seq::trim_u8(seq).unwrap();
964        assert_eq!(s, dna!("ACGT"));
965
966        let seq = b"ACGTXX";
967        let s: Seq<Dna> = Seq::trim_u8(seq).unwrap();
968        assert_eq!(s, dna!("ACGT"));
969
970        let seq = b"ACGTACGTACGTACGTACGTACGT";
971        let s: Seq<Dna> = Seq::trim_u8(seq).unwrap();
972        assert_eq!(s, dna!("ACGTACGTACGTACGTACGTACGT"));
973
974        let seq = b"XXACGTXXACGTXX";
975        let s: Result<Seq<Dna>, ParseBioError> = Seq::trim_u8(seq);
976        assert_eq!(s, Err(ParseBioError::UnrecognisedBase(b'X')));
977
978        let seq = b"A";
979        let s: Seq<Dna> = Seq::trim_u8(seq).unwrap();
980        assert_eq!(s, dna!("A"));
981
982        let seq = b"X";
983        let s: Result<Seq<Dna>, ParseBioError> = Seq::trim_u8(seq);
984        assert!(s.is_ok());
985        assert_eq!(s.unwrap(), dna!(""));
986
987        /*
988                let seq = b"acgtACGT";
989                let s: Seq<Dna> = Seq::trim_u8(seq).unwrap();
990                assert_eq!(s, dna!("ACGTACGT"));
991
992                let seq = b"AcGtAcGt";
993                let s: Seq<Dna> = Seq::trim_u8(seq).unwrap();
994                assert_eq!(s, dna!("ACGTACGT"));
995
996                let seq = b"AXCXGXTXaXcXgXt";
997                let s: Result<Seq<Dna>, ParseBioError> = Seq::trim_u8(seq);
998                assert_eq!(s, Err(ParseBioError::UnrecognisedBase(b'X')));
999        */
1000    }
1001
1002    #[test]
1003    fn test_seq_eq_and_hash() {
1004        let seq1: Seq<Dna> = "ACGT".try_into().unwrap();
1005        let seq2: Seq<Dna> = "ACGT".try_into().unwrap();
1006
1007        // Equality checks
1008        assert_eq!(seq1, seq2);
1009
1010        // Hash checks
1011        let mut hasher1 = DefaultHasher::new();
1012        seq1.hash(&mut hasher1);
1013        let hash1 = hasher1.finish();
1014
1015        let mut hasher2 = DefaultHasher::new();
1016        seq2.hash(&mut hasher2);
1017        let hash2 = hasher2.finish();
1018
1019        assert_eq!(hash1, hash2);
1020
1021        assert_eq!(record(&seq1), [4, 0, 0, 0, 0, 0, 0, 0, 0xe4]);
1022    }
1023
1024    #[test]
1025    #[allow(clippy::similar_names)]
1026    fn test_seq_slice_eq() {
1027        let seq1: Seq<Dna> = "ACGTAAAAAAAAAAAAACGTAAAACCCCGGGGTTTTA".try_into().unwrap();
1028        let seq2: Seq<Dna> = "ACGTAAAAAAAAAAAAACGTAAAACCCCGGGGTTTTAA".try_into().unwrap();
1029
1030        let slice1a: &SeqSlice<Dna> = &seq1[..];
1031        let slice1b: &SeqSlice<Dna> = &seq1[..];
1032        let slice2a: &SeqSlice<Dna> = &seq2[..seq2.len() - 1];
1033        let slice2b: &SeqSlice<Dna> = &seq2[..seq2.len() - 1];
1034
1035        let seq3: Seq<Dna> = slice2b.into();
1036
1037        assert_eq!(slice1a, slice2b);
1038        assert_eq!(&slice2a, &slice2b);
1039        assert_eq!(seq1, slice2a);
1040        assert_eq!(slice1b, seq3);
1041        assert_eq!(slice1a, slice1b);
1042        assert_eq!(seq1, seq3);
1043
1044        assert_ne!(seq1, seq2);
1045        assert_ne!(seq2, seq3);
1046        assert_ne!(seq2, slice2a);
1047        assert_ne!(seq2, slice1b);
1048
1049        assert_eq!(&slice1a, &slice1b);
1050
1051        assert_eq!(seq1, &seq1);
1052
1053        assert_eq!(seq1, &seq3);
1054        assert_eq!(&seq1, seq3);
1055        assert_eq!(&seq1, &seq3);
1056
1057        assert_eq!(slice1a, seq3);
1058        //assert_eq!(&slice1a, seq3);
1059
1060        assert_eq!(seq1, slice2a);
1061        assert_eq!(&seq1, slice2a);
1062        //assert_eq!(seq1, &slice2a);
1063
1064        assert_eq!(&seq1, slice2a);
1065    }
1066    #[test]
1067    fn test_seq_slice_hash() {
1068        let seq1: Seq<Dna> = "ACGTAAAAAAAAAAAAACGTAAAACCCCGGGGAAAAA".try_into().unwrap();
1069        let seq2: Seq<Dna> = "ACGTAAAAAAAAAAAAACGTAAAACCCCGGGGAAAAA".try_into().unwrap();
1070
1071        let seq3: Seq<Dna> = "ACGTAAAAAAAAAAAAACGTAAAACCCCGGGG".try_into().unwrap();
1072
1073        let slice1 = &seq1[..];
1074        let slice2 = &seq2[..];
1075
1076        let slice3 = &seq3[..];
1077
1078        let slice1_32 = &seq1[..32];
1079
1080        let mut hasher1 = DefaultHasher::new();
1081        seq1.hash(&mut hasher1);
1082        let full1 = hasher1.finish();
1083
1084        let mut hasher1a = DefaultHasher::new();
1085        seq1.hash(&mut hasher1a);
1086        let full1_alt = hasher1a.finish();
1087
1088        let mut hasher2 = DefaultHasher::new();
1089        seq2.hash(&mut hasher2);
1090        let full2 = hasher2.finish();
1091
1092        let mut hasher3 = DefaultHasher::new();
1093        slice1.hash(&mut hasher3);
1094        let full1_slice = hasher3.finish();
1095
1096        let mut hasher4 = DefaultHasher::new();
1097        slice2.hash(&mut hasher4);
1098        let full2_slice = hasher4.finish();
1099
1100        let mut hasher5 = DefaultHasher::new();
1101        slice3.hash(&mut hasher5);
1102        let short1_slice = hasher5.finish();
1103
1104        let mut hasher6 = DefaultHasher::new();
1105        slice1_32.hash(&mut hasher6);
1106        let seq1_short = hasher6.finish();
1107
1108        assert_eq!(full1, full1_alt);
1109        assert_eq!(full1, full2);
1110        assert_ne!(full2_slice, short1_slice);
1111        assert_eq!(full2, full1_slice);
1112        assert_eq!(short1_slice, seq1_short);
1113        assert_ne!(seq1_short, full1_slice);
1114
1115        assert_ne!(full1, short1_slice);
1116    }
1117
1118    #[test]
1119    fn test_fromstr() {
1120        let seq: Result<Seq<Dna>, ParseBioError> =
1121            "ACGATGAGTAGTCGCCATCGTATCTTTGACTGCCGATGCTA".parse();
1122        assert!(seq.is_ok());
1123
1124        let seq: Result<Seq<Dna>, ParseBioError> =
1125            "ACGATGAGTAGBCGCCATCGTATCTTTGACTGCCGATGCTA".parse();
1126        assert_eq!(seq, Err(ParseBioError::UnrecognisedBase(b'B')));
1127    }
1128
1129    #[test]
1130    fn test_lens() {
1131        assert_eq!(iupac!("AWANWATNA---SKAGTCAA").len(), 20);
1132    }
1133
1134    #[test]
1135    fn test_unique_bitarray_ident() {
1136        let s1 = dna!(
1137            "ATCGACTACGATCGCTACGATCGATCGATCGATCGAATCTCCCGCGCGATCATCGATCATCGCTACGTACGTCGAAAAATATAATGGG"
1138        );
1139        let s2 = dna!(
1140            "ATCGACTACGATCGCTACGATCGATCGATCGATCGAATCTCCCGCGCGATCATCGATCATCGCTACGTACGTCGAAAAATATAATGGG"
1141        );
1142
1143        // Changed first base
1144        let s3 = dna!(
1145            "CTCGACTACGATCGCTACGATCGATCGATCGATCGAATCTCCCGCGCGATCATCGATCATCGCTACGTACGTCGAAAAATATAATGGG"
1146        );
1147
1148        // Added `00` to end
1149        let s4 = dna!(
1150            "ATCGACTACGATCGCTACGATCGATCGATCGATCGAATCTCCCGCGCGATCATCGATCATCGCTACGTACGTCGAAAAATATAATGGGA"
1151        );
1152
1153        // Changed last base
1154        let s5 = dna!(
1155            "ATCGACTACGATCGCTACGATCGATCGATCGATCGAATCTCCCGCGCGATCATCGATCATCGCTACGTACGTCGAAAAATATAATGGC"
1156        );
1157
1158        assert_eq!(s1, s2);
1159        assert_ne!(s1, s3);
1160
1161        // these two tests won't compile because lengths are different
1162        assert_ne!(s1.len(), s4.len());
1163        assert_ne!(s4.len(), s1.len());
1164
1165        assert_ne!(s5, s1);
1166    }
1167
1168    #[test]
1169    fn test_static() {
1170        use crate::seq::SeqArray;
1171
1172        static B: SeqArray<Dna, 5, 1> = SeqArray {
1173            _p: PhantomData,
1174            ba: bitarr![const usize, Lsb0; 1,1,0,1,0,0,1,0,1,1],
1175        };
1176
1177        let s: &'static SeqSlice<Dna> = &B;
1178
1179        let x: &'static str = "TGACT";
1180
1181        assert_eq!(s.to_string(), x);
1182    }
1183
1184    #[test]
1185    fn test_to_from_raw() {
1186        let s = "TCAGCTAGCTACGACTGATCGATCGACTGATGCCGCGCGCGGCGCCGCGCGCGCGCGCCGCGCGCCCCGCGCGCGGCGCGCGCCGCGCGCGCGCGCGGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGC";
1187
1188        let seq: Seq<Dna> = s.try_into().unwrap();
1189        let raw = seq.into_raw();
1190        let new = Seq::<Dna>::from_raw(s.len(), raw);
1191        assert_eq!(new.unwrap(), seq);
1192
1193        let bad = Seq::<Dna>::from_raw(s.len() + 1, raw);
1194        assert_ne!(bad.unwrap(), seq);
1195
1196        let bad = Seq::<Dna>::from_raw(342, raw);
1197        assert_eq!(bad, None);
1198    }
1199    #[test]
1200    fn test_seq_and_seq_slice_eq_and_hash() {
1201        let seq: Seq<text::Dna> = Seq::try_from("ACGT".to_string()).unwrap();
1202        let slice = &seq[..];
1203
1204        // Equality checks
1205        assert_eq!(seq, slice);
1206        assert_eq!(&seq, slice);
1207        assert_eq!(slice, &seq);
1208
1209        // Hash checks
1210        let mut hasher1 = std::collections::hash_map::DefaultHasher::new();
1211        seq.hash(&mut hasher1);
1212        let hash1 = hasher1.finish();
1213
1214        let mut hasher2 = std::collections::hash_map::DefaultHasher::new();
1215        slice.hash(&mut hasher2);
1216        let hash2 = hasher2.finish();
1217
1218        assert_eq!(hash1, hash2);
1219    }
1220
1221    #[derive(Default)]
1222    struct RecordingHasher(Vec<u8>);
1223
1224    impl Hasher for RecordingHasher {
1225        fn finish(&self) -> u64 {
1226            0
1227        }
1228        fn write(&mut self, bytes: &[u8]) {
1229            self.0.extend_from_slice(bytes);
1230        }
1231    }
1232
1233    fn record<T: Hash>(value: &T) -> Vec<u8> {
1234        let mut h = RecordingHasher::default();
1235        value.hash(&mut h);
1236        h.0
1237    }
1238
1239    #[test]
1240    fn test_hash_byte_stream_invariants() {
1241        // Same logical content must produce the same byte stream regardless of
1242        // how it is spelt (Seq vs &SeqSlice) and across a range of codecs and
1243        // lengths — including ones with partial trailing bytes and ones long
1244        // enough to cross the internal flush buffer in `hash_bits`.
1245        fn check<A: Codec>(s: &str) {
1246            let seq: Seq<A> = s.try_into().unwrap_or_else(|_| panic!("parse {s:?}"));
1247            let bytes = record(&seq);
1248            assert_eq!(record::<&SeqSlice<A>>(&&seq[..]), bytes);
1249
1250            // Structural: 8-byte LE length prefix, then ceil(bits / 8) bytes.
1251            let n = seq.len();
1252            let body = (n * A::BITS as usize).div_ceil(8);
1253            assert_eq!(bytes.len(), 8 + body);
1254            assert_eq!(&bytes[..8], &(n as u64).to_le_bytes());
1255        }
1256        check::<Dna>("A");
1257        check::<Dna>("ACGT");
1258        check::<Dna>("ACGTA");
1259        check::<Dna>(&"ACGT".repeat(80)); // > 64-byte flush in `hash_bits`
1260        check::<Iupac>("AC");
1261        check::<Iupac>("ACG");
1262        check::<Iupac>("NRYKBDHV");
1263        check::<Amino>("MWLLP"); // 6-bit codec, partial trailing byte
1264        check::<text::Dna>("ACGT"); // 8-bit codec, byte-aligned
1265    }
1266
1267    #[test]
1268    fn test_kmer_hash_independent_of_storage_width() {
1269        let seq: Seq<Dna> = "ACGTACGTAC".try_into().unwrap();
1270        let slice: &SeqSlice<Dna> = &seq[..];
1271        let bytes = record(&slice);
1272        let km_usize: Kmer<Dna, 10, usize> = slice.try_into().unwrap();
1273        let km_u64: Kmer<Dna, 10, u64> = slice.try_into().unwrap();
1274        let km_u128: Kmer<Dna, 10, u128> = slice.try_into().unwrap();
1275        assert_eq!(record(&km_usize), bytes);
1276        assert_eq!(record(&km_u64), bytes);
1277        assert_eq!(record(&km_u128), bytes);
1278    }
1279
1280    #[test]
1281    fn test_prepend() {
1282        let mut seq1 =
1283            Seq::<Dna>::from_str("GCTCGATCGATCGATCGACTGACTGACGCGCGCATCCGATAAAAAAAAT").unwrap();
1284        seq1.prepend(dna!("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"));
1285        assert_eq!(
1286            seq1.to_string(),
1287            "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGCTCGATCGATCGATCGACTGACTGACGCGCGCATCCGATAAAAAAAAT"
1288        );
1289
1290        let mut seq2 =
1291            Seq::<Dna>::from_str("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA").unwrap();
1292        seq2.prepend(dna!("GCTCGATCGATCGATCGACTGACTGACGCGCGCATCCGATAAAAAAAAT"));
1293        assert_eq!(
1294            seq2.to_string(),
1295            "GCTCGATCGATCGATCGACTGACTGACGCGCGCATCCGATAAAAAAAATAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
1296        );
1297
1298        assert_ne!(seq1, seq2);
1299    }
1300
1301    #[test]
1302    fn test_append() {
1303        let mut seq1 =
1304            Seq::<Dna>::from_str("GCTCGATCGATCGATCGACTGACTGACGCGCGCATCCGATAAAAAAAAT").unwrap();
1305        seq1.append(dna!("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"));
1306        assert_eq!(
1307            seq1.to_string(),
1308            "GCTCGATCGATCGATCGACTGACTGACGCGCGCATCCGATAAAAAAAATAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
1309        );
1310
1311        let mut seq2 =
1312            Seq::<Dna>::from_str("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA").unwrap();
1313        seq2.append(dna!("GCTCGATCGATCGATCGACTGACTGACGCGCGCATCCGATAAAAAAAAT"));
1314        assert_eq!(
1315            seq2.to_string(),
1316            "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGCTCGATCGATCGATCGACTGACTGACGCGCGCATCCGATAAAAAAAAT"
1317        );
1318
1319        assert_ne!(seq1, seq2);
1320    }
1321
1322    #[test]
1323    fn test_remove() {
1324        let mut seq: Seq<Dna> = dna!("TCAGCATCGATCAATCG").into();
1325        seq.remove(4..6);
1326        assert_eq!(&seq, dna!("TCAGTCGATCAATCG"));
1327        seq.remove(..4);
1328        assert_eq!(&seq, dna!("TCGATCAATCG"));
1329        seq.remove(6..);
1330        assert_eq!(&seq, dna!("TCGATC"));
1331    }
1332
1333    #[test]
1334    fn test_insert() {
1335        let mut seq: Seq<Dna> = dna!("TCAGCATCGATCAATCG").into();
1336        let insertion = dna!("CCCCC");
1337
1338        seq.insert(4, insertion);
1339        assert_eq!(&seq, dna!("TCAGCCCCCCATCGATCAATCG"));
1340
1341        seq.insert(seq.len(), dna!("AAAAA"));
1342        assert_eq!(&seq, dna!("TCAGCCCCCCATCGATCAATCGAAAAA"));
1343    }
1344
1345    #[test]
1346    fn test_truncate() {
1347        let mut seq: Seq<Dna> = dna!("TCAGCATCGATCAATCG").into();
1348
1349        seq.truncate(seq.len());
1350        assert_eq!(&seq, dna!("TCAGCATCGATCAATCG"));
1351
1352        seq.truncate(10);
1353        assert_eq!(&seq, dna!("TCAGCATCGA"));
1354
1355        seq.truncate(0);
1356        assert_eq!(&seq, dna!(""));
1357    }
1358
1359    #[test]
1360    fn test_long_splice() {
1361        let mut seq: Seq<Dna> = dna!("TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT").into();
1362        let insertion = dna!("CCCCCCC");
1363
1364        seq.splice(32..38, insertion);
1365        assert_eq!(
1366            &seq,
1367            dna!("TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTCCCCCCCTTTTTTTTTTT")
1368        );
1369
1370        seq.splice(1..=1, dna!("AAA"));
1371        assert_eq!(
1372            &seq,
1373            dna!("TAAATTTTTTTTTTTTTTTTTTTTTTTTTTTTTTCCCCCCCTTTTTTTTTTT")
1374        );
1375
1376        seq.splice(10.., dna!("GGGG"));
1377        assert_eq!(&seq, dna!("TAAATTTTTTGGGG"));
1378    }
1379
1380    #[test]
1381    fn test_splice() {
1382        let mut seq: Seq<Dna> = dna!("TCAGCATCGATCAATCGT").into();
1383        let insertion = dna!("CCCCC");
1384
1385        seq.splice(4..6, insertion);
1386        assert_eq!(&seq, dna!("TCAGCCCCCTCGATCAATCGT"));
1387
1388        seq.splice(1..=1, dna!("AAA"));
1389        assert_eq!(&seq, dna!("TAAAAGCCCCCTCGATCAATCGT"));
1390
1391        seq.splice(10.., dna!("TTTT"));
1392        assert_eq!(&seq, dna!("TAAAAGCCCCTTTT"));
1393    }
1394}