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