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