Skip to main content

bio_seq/
lib.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//! Bit-packed and well-typed biological sequences
7//!
8//! The strength of rust is that we can safely separate the science (well-typed) and the engineering (bit-packed) of bioinformatics. An incremental benchmark improvement in the reverse complement algorithm should benefit the user of a succinct datastructure without anyone unwillingly learning about endianess.
9//!
10//! Contributions are very welcome. There's lots of low hanging fruit for optimisation and ideally we should only have to write them once!
11//!
12//! ## Sequences
13//!
14//! A [`Seq`](seq::Seq) is a heap allocated [sequence](seq) of symbols that owns its data. A [`SeqSlice`](seq::SeqSlice) is a read-only window into a `Seq`. Static [`SeqArray`s](seq::SeqArray) can be declared with the [`dna!`](macro@dna) and [`iupac!`](macro@iupac) macros but these should be dereferenced as `&'static SeqSlice`s.
15//!
16//! [`Kmer`s](mod@kmer) are shorter, fixed-length sequences. They generally fit in a single register and implement `Copy`. They are used for optimised algorithms on sequences and succinct datastructures. The default implementation uses a `usize` for storage. Using the 2-bit `Dna` encoding a `Kmer<Dna, 32>` occupies 64 bits.
17//!
18//! These sequence types are parameterised with [`Codec`s](`codec`) (e.g. `Seq<Dna>`, `Seq<Amino>`, etc.) that define how symbols are encoded into strings of bits and decoded as readable strings.
19//!
20//! ## Quick start
21//!
22//! Add `bio-seq` to `Cargo.toml`:
23//!
24//! ```toml
25//! [dependencies]
26//! bio-seq = "0.15"
27//! ```
28//!
29//! ```rust
30//! use bio_seq::prelude::*;
31//!
32//! let seq = dna!("ATACGATCGATCGATCGATCCGT");
33//!
34//! // iterate over the 8-mers of the reverse complement
35//! for kmer in seq.to_revcomp().kmers::<8>() {
36//!     println!("{kmer}");
37//! }
38//!
39//! // ACGGATCG
40//! // CGGATCGA
41//! // GGATCGAT
42//! // GATCGATC
43//! // ATCGATCG
44//! // ...
45//! ```
46//!
47//! Sequences are analogous to rust's string types and follow similar dereferencing conventions:
48//!
49//! ```rust
50//! # use bio_seq::prelude::*;
51//! // The `dna!` macro packs a static sequence with 2-bits per symbol at compile time:
52//! let s: &'static str = "hello!";
53//! let seq: &'static SeqSlice<Dna> = dna!("CGCTAGCTACGATCGCAT");
54//!
55//! // Sequences can also be copied into `Kmer`s:
56//! let kmer: Kmer<Dna, 18> = dna!("CGCTAGCTACGATCGCAT").try_into().unwrap();
57//! // or with the kmer! macro:
58//! let kmer = kmer!("CGCTAGCTACGATCGCAT");
59//!
60//! // `Seq`s can be allocated on the heap like `String`s are:
61//! let s: String = "hello!".into();
62//! let seq: Seq<Dna> = dna!("CGCTAGCTACGATCGCAT").into();
63//!
64//! // Alternatively, a `Seq` can be fallibly encoded at runtime:
65//! let seq: Seq<Dna> = "CGCTAGCTACGATCGCAT".try_into().unwrap();
66//!
67//! // `&SeqSlice` is analogous to `&str`:
68//! let slice: &str = &s[1..3];
69//! let seqslice: &SeqSlice<Dna> = &seq[2..4];
70//! ```
71//!
72//! ## Bit-packed encodings
73//!
74//! Encodings of genomic symbols are implemented as [`Codec`s](codec). This crate provides four common ones:
75//!   - [`codec::dna`]: 2-bit encoding of the four nucleotides
76//!   - [`codec::text`]: 8-bit ASCII encoding of nucleotides, meant to be compatible with plaintext sequencing data formats
77//!   - [`codec::iupac`]: 4-bit encoding of ambiguous nucleotide identities (the IUPAC ambiguity codes)
78//!   - [`codec::amino`]: 6-bit encoding of amino acids
79//!
80//! Each of these encodings is designed to facilitate common bioinformatics tasks, such as minimising k-mers and implementing succinct datastructures. The [translation] module provides traits and methods for translating between nucleotide and amino acid sequences.
81//!
82//! Custom codecs can also be implemented with the `Codec` trait and derived on specially crafted enums.
83//!
84
85#![warn(clippy::pedantic)]
86#![allow(clippy::must_use_candidate)]
87#![allow(clippy::return_self_not_must_use)]
88#![allow(clippy::module_name_repetitions)]
89// the lint doesn't seem to recognise our implementations
90#![allow(clippy::into_iter_without_iter)]
91//#[cfg(not(target_pointer_width = "64"))]
92//compile_error!("bio-seq currently only supports 64-bit platforms");
93//#![feature(simd_wasm64)]
94//#![feature(portable_simd)]
95
96use bitvec::prelude::*;
97
98type Order = Lsb0;
99type Bs = BitSlice<usize, Order>;
100type Bv = BitVec<usize, Order>;
101type Ba<const W: usize> = BitArray<[usize; W], Order>;
102
103mod hash;
104
105pub mod codec;
106pub mod error;
107#[macro_use]
108pub mod kmer;
109pub mod seq;
110
111pub use bio_seq_derive::{dna, iupac};
112
113#[doc(hidden)]
114pub use bitvec::bitarr as __bio_seq_bitarr;
115
116#[doc(hidden)]
117pub use bitvec::prelude::Lsb0 as __bio_seq_Lsb0;
118
119#[cfg(feature = "translation")]
120pub mod translation;
121
122pub mod prelude {
123    pub use crate::codec::Codec;
124    pub use crate::codec::amino::Amino;
125    pub use crate::codec::dna::Dna;
126    pub use crate::codec::iupac::Iupac;
127    pub use crate::{
128        Complement, ComplementMut, Maskable, MaskableMut, Reverse, ReverseComplement,
129        ReverseComplementMut, ReverseMut,
130    };
131
132    pub use crate::kmer::Kmer;
133    pub use crate::seq::{Seq, SeqArray, SeqSlice};
134
135    #[cfg(feature = "translation")]
136    pub use crate::translation;
137
138    pub use core::str::FromStr;
139
140    pub use crate::error::ParseBioError;
141
142    pub use crate::{dna, iupac, kmer};
143
144    #[doc(hidden)]
145    pub use crate::__bio_seq_Lsb0;
146    #[doc(hidden)]
147    pub use crate::__bio_seq_bitarr;
148    #[doc(hidden)]
149    pub use crate::__bio_seq_count_words;
150}
151
152/// Nucleotide bases and sequences can be complemented
153pub trait ComplementMut {
154    fn comp(&mut self);
155}
156
157pub trait Complement: ComplementMut + ToOwned
158where
159    <Self as ToOwned>::Owned: ComplementMut,
160{
161    /// ```
162    /// use bio_seq::prelude::{Dna, Complement};
163    /// assert_eq!(Dna::A.to_comp(), Dna::T);
164    /// ````
165    fn to_comp(&self) -> <Self as ToOwned>::Owned {
166        let mut owned = self.to_owned();
167        owned.comp();
168        owned
169    }
170}
171
172//impl<T: ?Sized + ComplementMut + ToOwned> Complement for T where <T as ToOwned>::Owned: ComplementMut {}
173
174/// A reversible sequence
175pub trait ReverseMut {
176    /// Reverse sequence in place
177    fn rev(&mut self);
178}
179
180pub trait Reverse: ReverseMut + ToOwned
181where
182    <Self as ToOwned>::Owned: ReverseMut,
183{
184    fn to_rev(&self) -> <Self as ToOwned>::Owned {
185        let mut owned = self.to_owned();
186        owned.rev();
187        owned
188    }
189}
190
191//impl<T: ?Sized + ReverseMut + ToOwned> Reverse for T where <T as ToOwned>::Owned: ReverseMut {}
192
193/// A reversible sequence that can be complemented can be reverse complemented
194pub trait ReverseComplementMut: ComplementMut + ReverseMut {
195    /// Reverse complement a sequence in place
196    fn revcomp(&mut self) {
197        self.comp();
198        self.rev();
199    }
200}
201
202//impl<T: ?Sized + ReverseMut + ComplementMut> ReverseComplementMut for T {}
203
204pub trait ReverseComplement: ReverseComplementMut + ToOwned
205where
206    <Self as ToOwned>::Owned: ReverseComplementMut,
207{
208    fn to_revcomp(&self) -> <Self as ToOwned>::Owned {
209        let mut owned = self.to_owned();
210        owned.revcomp();
211        owned
212    }
213}
214
215// TODO: Marker trait to allow overriding this blanket impl
216//impl<T: ReverseComplementMut + ToOwned> ReverseComplement for T where
217//    <T as ToOwned>::Owned: ReverseComplementMut
218//{
219//}
220
221/// Some sequence types may be maskable
222pub trait MaskableMut {
223    fn mask(&mut self);
224    fn unmask(&mut self);
225}
226
227pub trait Maskable: MaskableMut + ToOwned
228where
229    <Self as ToOwned>::Owned: MaskableMut,
230{
231    fn to_mask(&self) -> <Self as ToOwned>::Owned {
232        let mut owned = self.to_owned();
233        owned.mask();
234        owned
235    }
236    fn to_unmask(&self) -> <Self as ToOwned>::Owned {
237        let mut owned = self.to_owned();
238        owned.unmask();
239        owned
240    }
241}
242
243//impl<T: MaskableMut + ToOwned> Maskable for T where <T as ToOwned>::Owned: MaskableMut {}
244
245#[macro_export]
246macro_rules! __bio_seq_count_words {
247    ($len:expr) => {{ $len.div_ceil(usize::BITS) as usize }};
248}
249
250#[cfg(test)]
251mod tests {
252    use crate::codec::dna::Dna::{A, C, G, T};
253    use crate::prelude::*;
254    use std::hash::{DefaultHasher, Hash, Hasher};
255
256    #[test]
257    fn alt_repr() {
258        assert_eq!(iupac!("-").nth(0), Iupac::X);
259    }
260
261    #[test]
262    #[allow(clippy::many_single_char_names)]
263    fn into_usize() {
264        let a: usize = dna!("ACGT").to_owned().into_raw()[0];
265        assert_eq!(a, 0b11_10_01_00);
266
267        let b: usize = dna!("CGCG").to_owned().into_raw()[0];
268        assert_eq!(b, 0b10_01_10_01);
269
270        let c: usize = Seq::from(&vec![T, T]).into();
271        assert_eq!(c, 0b11_11);
272
273        let d: usize = Seq::<Dna>::from_str("TCA").unwrap().into();
274        assert_eq!(d, 0b00_01_11);
275
276        let e: usize = Seq::<Dna>::from_str("TGA").unwrap().into();
277        assert_eq!(e, 0b00_10_11);
278
279        let f: usize = Seq::from(&vec![C, G, T, A, C, G, A, T]).into();
280        assert_eq!(f, 0b11_00_10_01_00_11_10_01);
281
282        let g: usize = Seq::from(&vec![A]).into();
283        assert_eq!(g, 0b00);
284    }
285
286    #[test]
287    fn test_display_aminos() {
288        let a: Seq<Amino> = Seq::from_str("DCMNLKG*HI").unwrap();
289        assert_eq!(format!("{a}"), "DCMNLKG*HI");
290    }
291    #[test]
292    fn test_display_dna() {
293        let seq = Seq::from(&vec![A, C, G, T, T, A, T, C]);
294        assert_eq!(format!("{seq}"), "ACGTTATC");
295        assert_eq!(format!("{}", dna!("ACGT")), "ACGT");
296    }
297
298    #[test]
299    fn iterate_bases() {
300        let seq = dna!("ACGTACGT");
301        assert_eq!(
302            seq.into_iter().collect::<Vec<Dna>>(),
303            vec![A, C, G, T, A, C, G, T]
304        );
305    }
306
307    #[test]
308    fn from_string() {
309        let seq = Seq::<Dna>::from_str("ACGTACGT").unwrap();
310        assert_eq!(
311            seq.into_iter().collect::<Vec<Dna>>(),
312            vec![A, C, G, T, A, C, G, T]
313        );
314    }
315    #[test]
316    fn rev_seq() {
317        let seq = dna!("ACGTACGT");
318        assert_eq!(
319            seq.rev_iter().collect::<Vec<Dna>>(),
320            vec![T, G, C, A, T, G, C, A]
321        );
322        assert_eq!(
323            seq.to_rev().into_iter().collect::<Vec<Dna>>(),
324            vec![T, G, C, A, T, G, C, A]
325        );
326        assert_eq!(
327            iupac!("GN-").rev_iter().collect::<Vec<Iupac>>(),
328            vec![Iupac::X, Iupac::N, Iupac::G]
329        );
330
331        assert_eq!(
332            Seq::<Amino>::try_from("DCMNLKGHI")
333                .unwrap()
334                .to_rev()
335                .into_iter()
336                .collect::<Vec<Amino>>(),
337            vec![
338                Amino::I,
339                Amino::H,
340                Amino::G,
341                Amino::K,
342                Amino::L,
343                Amino::N,
344                Amino::M,
345                Amino::C,
346                Amino::D
347            ]
348        );
349    }
350    #[test]
351    fn iterate_kmers() {
352        let seq = dna!("ACGTAAGGGG");
353        for (kmer, answer) in seq
354            .kmers::<4>()
355            .zip(["ACGT", "CGTA", "GTAA", "TAAG", "AAGG", "AGGG", "GGGG"])
356        {
357            assert_eq!(format!("{kmer}"), answer);
358        }
359    }
360
361    #[test]
362    fn iterate_kmer8() {
363        let seq = dna!("AAAACCCCGGGG");
364        for (kmer, answer) in seq
365            .kmers::<8>()
366            .zip(["AAAACCCC", "AAACCCCG", "AACCCCGG", "ACCCCGGG", "CCCCGGGG"])
367        {
368            assert_eq!(format!("{kmer}"), answer);
369        }
370    }
371
372    #[test]
373    fn iterate_kmer4() {
374        let seq = dna!("AAAACCCCGGGGTTTT");
375        for (kmer, answer) in seq.kmers::<4>().zip([
376            "AAAA", "AAAC", "AACC", "ACCC", "CCCC", "CCCG", "CCGG", "CGGG", "GGGG", "GGGT", "GGTT",
377            "GTTT", "TTTT",
378        ]) {
379            assert_eq!(format!("{kmer}"), answer);
380        }
381    }
382
383    #[test]
384    fn iupac_bitwise_ops() {
385        let s1: &SeqSlice<Iupac> = iupac!("AS-GYTNA");
386        let s2: &SeqSlice<Iupac> = iupac!("ANTGCAT-");
387
388        let s3: &SeqSlice<Iupac> = iupac!("ACGTSWKM");
389        let s4: &SeqSlice<Iupac> = iupac!("WKMSTNNA");
390
391        assert_eq!(s1 | s2, iupac!("ANTGYWNA"));
392        assert_eq!(s3 & s4, iupac!("A----WKA"));
393    }
394    #[test]
395    fn min_sequence() {
396        let seq = dna!("GCTCGATCGTAAAAAATCGTATT");
397
398        let minimised = seq.kmers::<8>().min().unwrap();
399        assert_eq!(minimised, Kmer::try_from(dna!("GTAAAAAA")).unwrap());
400    }
401
402    #[test]
403    fn hash_minimiser() {
404        use core::cmp::min;
405
406        fn hash(seq: &SeqSlice<Dna>) -> u64 {
407            u64::from(seq != dna!("GGCTCTCTCTCCTCCA"))
408        }
409
410        let seq =
411            dna!("AGCGCTAGTCGTACTGCCGCATCGCTAGCGCTAAAAAAAAAAAAAAAAGGGGTGTGTGGGTTGTGGAGGAGAGAGAGCC");
412
413        //        let minimised = seq.kmers::<16>().map(hash).min().unwrap();
414
415        let (minimiser_rc, min_hash_rc) = seq
416            .to_revcomp()
417            .kmers::<16>()
418            .map(|kmer| (kmer, hash(&kmer)))
419            .min_by_key(|&(_, hash)| hash)
420            .unwrap();
421
422        let (minimiser, min_hash) = seq
423            .kmers::<16>()
424            .map(|kmer| (kmer, hash(&kmer)))
425            .min_by_key(|&(_, hash)| hash)
426            .unwrap();
427
428        //        let x = min(min_hash, min_hash_rc);
429
430        let (canonical_minimiser, canonical_hash) = seq
431            .kmers::<16>()
432            .map(|kmer| {
433                let canonical_hash = min(hash(&kmer), hash(&kmer.to_revcomp()));
434                (kmer, canonical_hash)
435            })
436            .min_by_key(|&(_, hash)| hash)
437            .unwrap();
438
439        println!(
440            "{minimiser_rc} {min_hash_rc}\n{minimiser} {min_hash}\n{canonical_minimiser} {canonical_hash}"
441        );
442        assert_eq!(min_hash_rc, canonical_hash);
443        assert_ne!(min_hash, canonical_hash);
444        assert_eq!(minimiser_rc, canonical_minimiser.to_revcomp());
445    }
446
447    #[test]
448    #[allow(clippy::needless_borrows_for_generic_args)]
449    #[allow(clippy::needless_borrow)]
450    fn hash_characteristics() {
451        fn hash<T: Hash>(chunk: T) -> u64 {
452            let mut hasher = DefaultHasher::new();
453            chunk.hash(&mut hasher);
454            hasher.finish()
455        }
456
457        let s1 = dna!("AGCGCTAGTCGTACTGCCGCATCGCTAGCGCT");
458        let s2 = dna!("AGCGCTAGTCGTACTGCCGCATCGCTAGCGCTA");
459
460        let q1: Seq<Dna> = dna!("AGCGCTAGTCGTACTGCCGCATCGCTAGCGCT").into();
461        let q2: Seq<Dna> = dna!("AGCGCTAGTCGTACTGCCGCATCGCTAGCGCTA").into();
462
463        let s3 = dna!("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
464        let s4 = dna!("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
465
466        let q3 = dna!("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
467        let q4 = dna!("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
468
469        let l3: &SeqSlice<Dna> = &q3;
470        let l3_a: &SeqSlice<Dna> = &q4[1..];
471        let l3_b: &SeqSlice<Dna> = &q4[..32];
472        let l4: &SeqSlice<Dna> = &q4;
473
474        let k1: Kmer<Dna, 32, u64> = s1.try_into().unwrap();
475        let k1_a: Kmer<Dna, 32, u64> = s1.try_into().unwrap();
476
477        let k3: Kmer<Dna, 32, u64> = s3.try_into().unwrap();
478
479        assert_eq!(hash(&l3), hash(q3));
480        assert_eq!(hash(&l3), hash(&l3_a));
481        assert_eq!(hash(&l3_a), hash(&l3_b));
482
483        assert_eq!(hash(&s2), hash(&q2));
484
485        assert_eq!(hash(&s1), hash(s1));
486        assert_eq!(hash(s2), hash(&s2));
487        assert_ne!(hash(&s4), hash(&s3));
488
489        assert_ne!(hash(&l3), hash(&l4));
490        assert_ne!(hash(&l3_a), hash(&l4));
491
492        assert_ne!(hash(&q2), hash(&q1));
493
494        assert_eq!(hash(q3), hash(s3));
495        assert_eq!(hash(s1), hash(&q1));
496        assert_ne!(hash(s3), hash(s4));
497
498        assert_ne!(hash(&k3), hash(&k1));
499        assert_eq!(hash(&k1_a), hash(&k1));
500        assert_eq!(hash(s1), hash(&k1));
501    }
502
503    #[test]
504    fn sequence_type_hashes() {
505        fn hash<T: Hash>(chunk: &T) -> u64 {
506            let mut hasher = DefaultHasher::new();
507            chunk.hash(&mut hasher);
508            hasher.finish()
509        }
510
511        let seq_arr: &SeqSlice<Dna> = dna!("AGCGCTAGTCGTACTGCCGCATCGCTAGCGCT");
512        let seq: Seq<Dna> = seq_arr.into();
513        let seq_slice: &SeqSlice<Dna> = &seq;
514        let kmer: Kmer<Dna, 32, u64> = seq_arr.try_into().unwrap();
515
516        assert_eq!(hash(&seq_arr), hash(&seq));
517        assert_eq!(hash(&seq), hash(&seq_slice));
518        assert_eq!(hash(&seq_slice), hash(&kmer));
519    }
520
521    #[test]
522    fn nth_chars() {
523        assert_eq!(iupac!("ACGTRYSWKMBDHVN-").nth(0), Iupac::A);
524        assert_ne!(iupac!("ACGTRYSWKMBDHVN-").nth(0), Iupac::C);
525        assert_eq!(iupac!("ACGTRYSWKMBDHVN-").nth(15), Iupac::X);
526        assert_eq!(iupac!("ACGTRYSWKMBDHVN-").nth(3), Iupac::from(Dna::T));
527        assert_ne!(iupac!("ACGTRYSWKMBDHVN-").nth(3), Iupac::from(Dna::G));
528
529        assert_eq!(
530            Seq::<Amino>::try_from("DCMNLKGHI").unwrap().nth(1),
531            Amino::C
532        );
533        assert_ne!(
534            Seq::<Amino>::try_from("DCMNLKGHI").unwrap().nth(7),
535            Amino::I
536        );
537    }
538
539    #[test]
540    fn colexicographic_order() {
541        for (i, e) in ["AA", "CA", "GA", "TA", "AC", "CC", "GC", "TC"]
542            .iter()
543            .enumerate()
544        {
545            assert_eq!(format!("{}", Kmer::<Dna, 2>::from(i)), e.to_string());
546            assert_eq!(Kmer::<Dna, 2>::from(i), *e);
547        }
548    }
549
550    #[test]
551    #[allow(clippy::redundant_slicing)]
552    #[allow(clippy::needless_borrow)]
553    #[allow(clippy::similar_names)]
554    fn sequence_type_equality() {
555        let raw_a = "AATTGTGGGTTCGTCTGCGGCTCCGCCCTTAGTACTATAGGACGATCAGCACCATAAGAACAA";
556        let raw_b = "AATTGTGGGTTCGTCTGCGGCTCCGCCCTTAGTACTATAGGACGATCAGCACCATAAGAACAAA";
557        let raw_c = "AATTGTGGGTTCGTCTGCGGCTCCGCCCTTAGTACTATAGGACGATCAGCACCATAAGAACAAA";
558        let raw_d = "AATTGTGGGTTCGTCTGCGGCTCCGCCCTTAGTACTATAGGACGATCAGCACCATAAGAACAAAA";
559
560        assert_eq!(raw_a.len(), 63);
561        assert_eq!(raw_b.len(), 64);
562        assert_eq!(raw_d.len(), 65);
563
564        assert_eq!(raw_c, raw_b);
565        assert_eq!(raw_c, &raw_b[..]);
566
567        assert_ne!(raw_b, raw_d);
568        assert_ne!(raw_a, raw_b);
569
570        // Seq
571
572        let seq_a: Seq<Dna> = raw_a.try_into().unwrap();
573        let seq_b: Seq<Dna> = raw_b.try_into().unwrap();
574        let seq_c: Seq<Dna> = raw_c.try_into().unwrap();
575        let seq_d: Seq<Dna> = raw_d.try_into().unwrap();
576
577        assert_eq!(seq_a.len(), raw_a.len());
578        assert_eq!(seq_d.len(), raw_d.len());
579
580        assert_eq!(seq_c, seq_b);
581        assert_eq!(seq_c, &seq_b);
582
583        assert_ne!(seq_a, &seq_b);
584        assert_ne!(seq_a, seq_b);
585        assert_ne!(seq_c, seq_d);
586
587        // SeqSlice
588
589        let slice_a: &SeqSlice<Dna> = &seq_a;
590        let slice_b: &SeqSlice<Dna> = &seq_b;
591        let slice_c: &SeqSlice<Dna> = &seq_c;
592        let slice_d: &SeqSlice<Dna> = &seq_d;
593
594        assert_eq!(slice_a.len(), raw_a.len());
595        assert_eq!(slice_d.len(), raw_d.len());
596
597        assert_eq!(slice_c, slice_b);
598        assert_eq!(slice_c, &slice_b[..]);
599
600        assert_ne!(slice_a, slice_b);
601        assert_ne!(slice_c, slice_d);
602        assert_ne!(slice_c, &slice_d[..]);
603
604        // SeqArray references
605
606        let array_a = dna!("AATTGTGGGTTCGTCTGCGGCTCCGCCCTTAGTACTATAGGACGATCAGCACCATAAGAACAA");
607        let array_b = dna!("AATTGTGGGTTCGTCTGCGGCTCCGCCCTTAGTACTATAGGACGATCAGCACCATAAGAACAAA");
608        let array_c: &'static SeqSlice<Dna> =
609            dna!("AATTGTGGGTTCGTCTGCGGCTCCGCCCTTAGTACTATAGGACGATCAGCACCATAAGAACAAA");
610        let array_d: &'static SeqSlice<Dna> =
611            dna!("AATTGTGGGTTCGTCTGCGGCTCCGCCCTTAGTACTATAGGACGATCAGCACCATAAGAACAAAA");
612
613        assert_eq!(array_a.len(), raw_a.len());
614        assert_eq!(array_d.len(), raw_d.len());
615
616        assert_eq!(array_c, array_b);
617
618        assert_ne!(array_a, array_b);
619        assert_ne!(array_c, array_d);
620
621        // Kmers
622
623        let kmer_ax_32: Kmer<Dna, 32, u64> = kmer!("AATTGTGGGTTCGTCTGCGGCTCCGCCCTTAG", u64);
624        let kmer_bx_32 = Kmer::<Dna, 32, u64>::from_str(&raw_b[..32]).unwrap();
625
626        let kmer_x_32: Kmer<Dna, 32, u64> = kmer!("AATTGTGGGTTCGTCTGCGCCTCCGCCCTTAG", u64);
627
628        assert_eq!(kmer_ax_32.len(), 32);
629
630        assert_eq!(kmer_ax_32, kmer_bx_32);
631        assert_ne!(kmer_ax_32, kmer_x_32);
632
633        let kmer_b_64 = Kmer::<Dna, 64, u128>::from_str(&raw_b).unwrap();
634        let kmer_cx_64 = Kmer::<Dna, 64, u128>::from_str(&raw_d[..64]).unwrap();
635        let kmer_dx_64 = Kmer::<Dna, 64, u128>::from_str(&raw_d[1..]).unwrap();
636
637        assert_eq!(kmer_cx_64.len(), 64);
638
639        assert_eq!(kmer_b_64, kmer_cx_64);
640        assert_ne!(kmer_b_64, kmer_dx_64);
641
642        // Cross-type equality:
643
644        assert_eq!(seq_c, slice_b);
645        assert_eq!(seq_c, *array_b);
646        //        assert_eq!(seq_c, kmer_b_64);
647
648        assert_eq!(&seq_c, slice_b);
649        assert_eq!(&seq_c, array_b);
650        //        assert_eq!(&seq_c, kmer_b_64);
651
652        assert_eq!(slice_c, seq_b);
653        assert_eq!(slice_c, &seq_b);
654        assert_eq!(&slice_c, array_b);
655        //        assert_eq!(slice_c, kmer_b_64);
656
657        assert_eq!(array_c, &seq_b);
658        assert_eq!(array_c, seq_b);
659        assert_eq!(array_c, slice_b);
660        //        assert_eq!(array_c, kmer_b_64);
661
662        //        assert_eq!(kmer_b_64, &seq_c);
663        //        assert_eq!(kmer_b_64, seq_c);
664        //        assert_eq!(kmer_b_64, slice_c);
665        //        assert_eq!(kmer_b_64, array_c);
666
667        // Cross-type inequality (shorter):
668
669        assert_ne!(&seq_a, slice_b);
670        assert_ne!(&seq_a, array_b);
671        assert_ne!(seq_a, slice_b);
672        assert_ne!(seq_a, array_b);
673        //        assert_ne!(seq_a, kmer_b_64);
674        //        assert_ne!(&seq_a, kmer_b_64);
675
676        assert_ne!(slice_a, &seq_b);
677        assert_ne!(slice_a, seq_b);
678        assert_ne!(&slice_a, array_b);
679        //        assert_ne!(slice_a, kmer_b_64);
680
681        assert_ne!(array_a, &seq_b);
682        assert_ne!(array_a, seq_b);
683        assert_ne!(array_a, slice_b);
684        //        assert_ne!(array_a, kmer_b_64);
685
686        //        assert_ne!(kmer_b_64, &seq_a);
687        //        assert_ne!(kmer_b_64, seq_a);
688        //        assert_ne!(kmer_b_64, slice_a);
689        //        assert_ne!(kmer_b_64, array_a);
690
691        // Cross-type inequality (longer):
692
693        assert_ne!(seq_d, slice_b);
694        assert_ne!(seq_d, array_b);
695        //        assert_ne!(seq_d, kmer_b_64);
696        assert_ne!(&seq_d, slice_b);
697        assert_ne!(&seq_d, array_b);
698        //        assert_ne!(&seq_d, kmer_b_64);
699
700        assert_ne!(slice_d, &seq_b);
701        assert_ne!(slice_d, seq_b);
702        assert_ne!(&slice_d, array_b);
703        //        assert_ne!(slice_d, kmer_b_64);
704
705        assert_ne!(array_d, &seq_b);
706        assert_ne!(array_d, seq_b);
707
708        assert_ne!(slice_b, array_d);
709        assert_ne!(array_d, slice_b);
710        //        assert_ne!(array_d, kmer_b_64);
711
712        //        assert_ne!(kmer_b_64, &seq_d);
713        //        assert_ne!(kmer_b_64, seq_d);
714        //        assert_ne!(kmer_b_64, slice_d);
715        //        assert_ne!(kmer_b_64, array_d);
716    }
717}
718
719#[cfg(test)]
720#[cfg(target_arch = "wasm32")]
721mod wasm_tests {
722    use crate::prelude::*;
723    use wasm_bindgen_test::*;
724
725    #[wasm_bindgen_test]
726    fn sequence_type_equality() {
727        let raw_a = "AATTGTGGGTTCGTCTGCGGCTCCGCCCTTAGTACTATAGGACGATCAGCACCATAAGAACAA";
728        let raw_b = "AATTGTGGGTTCGTCTGCGGCTCCGCCCTTAGTACTATAGGACGATCAGCACCATAAGAACAAA";
729        let raw_c = "AATTGTGGGTTCGTCTGCGGCTCCGCCCTTAGTACTATAGGACGATCAGCACCATAAGAACAAA";
730        let raw_d = "AATTGTGGGTTCGTCTGCGGCTCCGCCCTTAGTACTATAGGACGATCAGCACCATAAGAACAAAA";
731
732        assert_eq!(raw_a.len(), 63);
733        assert_eq!(raw_b.len(), 64);
734        assert_eq!(raw_d.len(), 65);
735
736        assert_eq!(raw_c, raw_b);
737        assert_eq!(raw_c, &raw_b[..]);
738
739        assert_ne!(raw_b, raw_d);
740        assert_ne!(raw_a, raw_b);
741
742        // Seq
743
744        let seq_a: Seq<Dna> = raw_a.try_into().unwrap();
745        let seq_b: Seq<Dna> = raw_b.try_into().unwrap();
746        let seq_c: Seq<Dna> = raw_c.try_into().unwrap();
747        let seq_d: Seq<Dna> = raw_d.try_into().unwrap();
748
749        assert_eq!(seq_a.len(), raw_a.len());
750        assert_eq!(seq_d.len(), raw_d.len());
751
752        assert_eq!(seq_c, seq_b);
753        assert_eq!(seq_c, &seq_b);
754
755        assert_ne!(seq_a, &seq_b);
756        assert_ne!(seq_a, seq_b);
757        assert_ne!(seq_c, seq_d);
758
759        // SeqSlice
760
761        let slice_a: &SeqSlice<Dna> = &seq_a;
762        let slice_b: &SeqSlice<Dna> = &seq_b;
763        let slice_c: &SeqSlice<Dna> = &seq_c;
764        let slice_d: &SeqSlice<Dna> = &seq_d;
765
766        assert_eq!(slice_a.len(), raw_a.len());
767        assert_eq!(slice_d.len(), raw_d.len());
768
769        assert_eq!(slice_c, slice_b);
770        assert_eq!(slice_c, &slice_b[..]);
771
772        assert_ne!(slice_a, slice_b);
773        assert_ne!(slice_c, slice_d);
774        assert_ne!(slice_c, &slice_d[..]);
775
776        // SeqArray references
777
778        let array_a = dna!("AATTGTGGGTTCGTCTGCGGCTCCGCCCTTAGTACTATAGGACGATCAGCACCATAAGAACAA");
779        let array_b = dna!("AATTGTGGGTTCGTCTGCGGCTCCGCCCTTAGTACTATAGGACGATCAGCACCATAAGAACAAA");
780        let array_c: &'static SeqSlice<Dna> =
781            dna!("AATTGTGGGTTCGTCTGCGGCTCCGCCCTTAGTACTATAGGACGATCAGCACCATAAGAACAAA");
782        let array_d: &'static SeqSlice<Dna> =
783            dna!("AATTGTGGGTTCGTCTGCGGCTCCGCCCTTAGTACTATAGGACGATCAGCACCATAAGAACAAAA");
784
785        assert_eq!(array_a.len(), raw_a.len());
786        assert_eq!(array_d.len(), raw_d.len());
787
788        assert_eq!(array_c, array_b);
789
790        assert_ne!(array_a, array_b);
791        assert_ne!(array_c, array_d);
792
793        assert_eq!(seq_c, slice_b);
794        assert_eq!(seq_c, *array_b);
795
796        assert_eq!(&seq_c, slice_b);
797        assert_eq!(&seq_c, array_b);
798
799        assert_eq!(slice_c, seq_b);
800        assert_eq!(slice_c, &seq_b);
801        assert_eq!(&slice_c, array_b);
802
803        assert_eq!(array_c, &seq_b);
804        assert_eq!(array_c, seq_b);
805        assert_eq!(array_c, slice_b);
806        // Cross-type inequality (shorter):
807
808        assert_ne!(&seq_a, slice_b);
809        assert_ne!(&seq_a, array_b);
810        assert_ne!(seq_a, slice_b);
811        assert_ne!(seq_a, array_b);
812        assert_ne!(slice_a, &seq_b);
813        assert_ne!(slice_a, seq_b);
814        assert_ne!(&slice_a, array_b);
815
816        assert_ne!(array_a, &seq_b);
817        assert_ne!(array_a, seq_b);
818        assert_ne!(array_a, slice_b);
819        // Cross-type inequality (longer):
820
821        assert_ne!(seq_d, slice_b);
822        assert_ne!(seq_d, array_b);
823        assert_ne!(&seq_d, slice_b);
824        assert_ne!(&seq_d, array_b);
825
826        assert_ne!(slice_d, &seq_b);
827        assert_ne!(slice_d, seq_b);
828        assert_ne!(&slice_d, array_b);
829
830        assert_ne!(array_d, &seq_b);
831        assert_ne!(array_d, seq_b);
832
833        assert_ne!(slice_b, array_d);
834        assert_ne!(array_d, slice_b);
835    }
836
837    #[wasm_bindgen_test]
838    fn wasm_kmers() {
839        //let raw_a = "AATTGTGGGTTCGTCTGCGGCTCCGCCCTTAGTACTATAGGACGATCAGCACCATAAGAACAA";
840        let raw_b = "AATTGTGGGTTCGTCTGCGGCTCCGCCCTTAGTACTATAGGACGATCAGCACCATAAGAACAAA";
841        //let raw_c = "AATTGTGGGTTCGTCTGCGGCTCCGCCCTTAGTACTATAGGACGATCAGCACCATAAGAACAAA";
842        let raw_d = "AATTGTGGGTTCGTCTGCGGCTCCGCCCTTAGTACTATAGGACGATCAGCACCATAAGAACAAAA";
843
844        let kmer_ax_32: Kmer<Dna, 32, u64> = kmer!("AATTGTGGGTTCGTCTGCGGCTCCGCCCTTAG", u64);
845        let kmer_bx_32 = Kmer::<Dna, 32, u64>::from_str(&raw_b[..32]).unwrap();
846
847        let kmer_x_32: Kmer<Dna, 32, u64> = kmer!("AATTGTGGGTTCGTCTGCGCCTCCGCCCTTAG", u64);
848
849        assert_eq!(kmer_ax_32.len(), 32);
850
851        assert_eq!(kmer_ax_32, kmer_bx_32);
852        assert_ne!(kmer_ax_32, kmer_x_32);
853
854        let kmer_b_64 = Kmer::<Dna, 64, u128>::from_str(&raw_b).unwrap();
855        let kmer_cx_64 = Kmer::<Dna, 64, u128>::from_str(&raw_d[..64]).unwrap();
856        let kmer_dx_64 = Kmer::<Dna, 64, u128>::from_str(&raw_d[1..]).unwrap();
857
858        assert_eq!(kmer_cx_64.len(), 64);
859
860        assert_eq!(kmer_b_64, kmer_cx_64);
861        assert_ne!(kmer_b_64, kmer_dx_64);
862    }
863
864    /*
865        #[wasm_bindgen_test]
866        fn test_splice() {
867            let mut seq: Seq<Dna> = dna!("TCAGCATCGATCAATCG").into();
868            let insertion = dna!("CCCCC");
869
870            seq.splice(4..6, insertion);
871            assert_eq!(&seq, dna!("TCAGCCCCCTCGATCAATCG"));
872
873            seq.splice(1..=1, dna!("AAA"));
874            assert_eq!(&seq, dna!("TAAAAGCCCCCTCGATCAATCG"));
875
876            seq.splice(10.., dna!("TTTT"));
877            assert_eq!(&seq, dna!("TAAAAGCCCCTTTT"));
878        }
879    */
880}