use crate::{
data::mappings::TWO_BIT_MAPPING,
kmer::{Kmer, KmerCounter, KmerEncoder, KmerError, KmerLen, KmerSet, MaxLenToType, SupportedKmerLen},
math::{AnyInt, Uint},
};
use std::hash::{Hash, Hasher, RandomState};
pub(crate) type TwoBitKmerLen<const MAX_LEN: usize> = KmerLen<MAX_LEN, TwoBitKmerEncoder<MAX_LEN>>;
pub(crate) type TwoBitMaxLenToType<const MAX_LEN: usize> = MaxLenToType<MAX_LEN, TwoBitKmerEncoder<MAX_LEN>>;
pub type TwoBitKmerSet<const MAX_LEN: usize, S = RandomState> = KmerSet<MAX_LEN, TwoBitKmerEncoder<MAX_LEN>, S>;
pub type TwoBitKmerCounter<const MAX_LEN: usize, S = RandomState> = KmerCounter<MAX_LEN, TwoBitKmerEncoder<MAX_LEN>, S>;
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
#[repr(transparent)]
pub struct TwoBitEncodedKmer<const MAX_LEN: usize>(TwoBitMaxLenToType<MAX_LEN>)
where
TwoBitKmerLen<MAX_LEN>: SupportedKmerLen;
impl<const MAX_LEN: usize, T: Uint> From<T> for TwoBitEncodedKmer<MAX_LEN>
where
TwoBitKmerLen<MAX_LEN>: SupportedKmerLen<T = T>,
{
#[inline]
fn from(value: T) -> Self {
Self(value)
}
}
#[derive(Copy, Clone, Debug)]
pub struct TwoBitKmerEncoder<const MAX_LEN: usize>
where
TwoBitKmerLen<MAX_LEN>: SupportedKmerLen, {
kmer_length: usize,
kmer_mask: TwoBitMaxLenToType<MAX_LEN>,
}
impl<T: Uint, const MAX_LEN: usize> TwoBitKmerEncoder<MAX_LEN>
where
TwoBitKmerLen<MAX_LEN>: SupportedKmerLen<T = T>,
{
#[inline]
#[must_use]
pub fn encode_base(base: u8) -> T {
T::from(TWO_BIT_MAPPING[base])
}
#[inline]
#[must_use]
pub fn decode_base(encoded_base: T) -> u8 {
b"ACGT"[encoded_base.cast_as::<usize>()]
}
}
impl<const MAX_LEN: usize> PartialEq for TwoBitKmerEncoder<MAX_LEN>
where
TwoBitKmerLen<MAX_LEN>: SupportedKmerLen,
{
#[inline]
fn eq(&self, other: &Self) -> bool {
self.kmer_length == other.kmer_length
}
}
impl<const MAX_LEN: usize> Eq for TwoBitKmerEncoder<MAX_LEN> where TwoBitKmerLen<MAX_LEN>: SupportedKmerLen {}
impl<const MAX_LEN: usize> Hash for TwoBitKmerEncoder<MAX_LEN>
where
TwoBitKmerLen<MAX_LEN>: SupportedKmerLen,
{
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.kmer_length.hash(state);
}
}
impl<const MAX_LEN: usize, T: Uint> KmerEncoder<MAX_LEN> for TwoBitKmerEncoder<MAX_LEN>
where
TwoBitKmerLen<MAX_LEN>: SupportedKmerLen<T = T>,
{
type EncodedKmer = TwoBitEncodedKmer<MAX_LEN>;
type SeqIter<'a> = TwoBitKmerIterator<'a, MAX_LEN>;
type SeqIntoIter = TwoBitKmerIntoIterator<MAX_LEN>;
type SeqIterRev<'a> = TwoBitKmerIteratorRev<'a, MAX_LEN>;
type SeqIntoIterRev = TwoBitKmerIntoIteratorRev<MAX_LEN>;
#[inline]
#[allow(clippy::cast_possible_truncation)]
fn new(kmer_length: usize) -> Result<Self, KmerError> {
if kmer_length <= MAX_LEN && kmer_length > 1 {
let kmer_mask = (T::ONE.unbounded_shl(2 * kmer_length as u32)).wrapping_sub(T::ONE);
Ok(Self { kmer_length, kmer_mask })
} else {
Err(KmerError::InvalidLength)
}
}
#[inline]
fn kmer_length(&self) -> usize {
self.kmer_length
}
#[inline]
fn encode_kmer(&self, kmer: impl AsRef<[u8]>) -> Self::EncodedKmer {
let mut encoded_kmer = T::ZERO;
for &base in kmer.as_ref() {
encoded_kmer = (encoded_kmer << 2) | Self::encode_base(base);
}
TwoBitEncodedKmer(encoded_kmer)
}
fn decode_kmer(&self, mut encoded_kmer: Self::EncodedKmer) -> Kmer<MAX_LEN> {
let mut buffer = [0; MAX_LEN];
for i in (0..self.kmer_length).rev() {
let encoded_base = encoded_kmer.0 & T::from_literal(0b11);
buffer[i] = Self::decode_base(encoded_base);
encoded_kmer.0 >>= 2;
}
unsafe { Kmer::new_unchecked(self.kmer_length, buffer) }
}
fn iter_from_sequence<'a, S: AsRef<[u8]> + ?Sized>(&self, seq: &'a S) -> Self::SeqIter<'a> {
TwoBitKmerIterator::new(self, seq.as_ref())
}
fn iter_consuming_seq<S>(&self, seq: S) -> Self::SeqIntoIter
where
S: Into<Vec<u8>>,
for<'a> &'a S: AsRef<Vec<u8>>, {
TwoBitKmerIntoIterator::new(self, seq.into())
}
fn iter_from_sequence_rev<'a, S: AsRef<[u8]> + ?Sized>(&self, seq: &'a S) -> Self::SeqIterRev<'a> {
TwoBitKmerIteratorRev::new(self, seq.as_ref())
}
fn iter_consuming_seq_rev<S>(&self, seq: S) -> Self::SeqIntoIterRev
where
S: Into<Vec<u8>>,
for<'a> &'a S: AsRef<Vec<u8>>, {
TwoBitKmerIntoIteratorRev::new(self, seq.into())
}
}
pub struct TwoBitKmerIterator<'a, const MAX_LEN: usize>
where
TwoBitKmerLen<MAX_LEN>: SupportedKmerLen, {
current_kmer: TwoBitEncodedKmer<MAX_LEN>,
remaining: std::slice::Iter<'a, u8>,
kmer_mask: TwoBitMaxLenToType<MAX_LEN>,
}
impl<'a, const MAX_LEN: usize> TwoBitKmerIterator<'a, MAX_LEN>
where
TwoBitKmerLen<MAX_LEN>: SupportedKmerLen,
{
#[inline]
fn new(encoder: &TwoBitKmerEncoder<MAX_LEN>, seq: &'a [u8]) -> Self {
if seq.len() < encoder.kmer_length {
Self::empty()
} else {
let index = encoder.kmer_length - 1;
let pre_first_kmer = encoder.encode_kmer(&seq[..index]);
TwoBitKmerIterator {
current_kmer: pre_first_kmer,
remaining: seq[index..].iter(),
kmer_mask: encoder.kmer_mask,
}
}
}
#[inline]
#[must_use]
fn empty() -> Self {
TwoBitKmerIterator {
current_kmer: TwoBitEncodedKmer(TwoBitMaxLenToType::<MAX_LEN>::ZERO),
remaining: [].iter(),
kmer_mask: TwoBitMaxLenToType::<MAX_LEN>::ZERO,
}
}
#[inline]
#[must_use]
pub(crate) fn shift_and_add_base(
new_base: u8, kmer: TwoBitEncodedKmer<MAX_LEN>, kmer_mask: TwoBitMaxLenToType<MAX_LEN>,
) -> TwoBitEncodedKmer<MAX_LEN> {
let encoded_base = TwoBitKmerEncoder::encode_base(new_base);
let shifted_kmer = kmer.0 << 2;
((shifted_kmer | encoded_base) & kmer_mask).into()
}
}
impl<const MAX_LEN: usize> Iterator for TwoBitKmerIterator<'_, MAX_LEN>
where
TwoBitKmerLen<MAX_LEN>: SupportedKmerLen,
{
type Item = TwoBitEncodedKmer<MAX_LEN>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let base = *self.remaining.next()?;
self.current_kmer = TwoBitKmerIterator::shift_and_add_base(base, self.current_kmer, self.kmer_mask);
Some(self.current_kmer)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.remaining.size_hint()
}
}
impl<const MAX_LEN: usize> ExactSizeIterator for TwoBitKmerIterator<'_, MAX_LEN> where
TwoBitKmerLen<MAX_LEN>: SupportedKmerLen
{
}
pub struct TwoBitKmerIntoIterator<const MAX_LEN: usize>
where
TwoBitKmerLen<MAX_LEN>: SupportedKmerLen, {
seq: Vec<u8>,
index: usize,
current_kmer: TwoBitEncodedKmer<MAX_LEN>,
kmer_mask: TwoBitMaxLenToType<MAX_LEN>,
}
impl<const MAX_LEN: usize> TwoBitKmerIntoIterator<MAX_LEN>
where
TwoBitKmerLen<MAX_LEN>: SupportedKmerLen,
{
#[inline]
fn new(encoder: &TwoBitKmerEncoder<MAX_LEN>, seq: Vec<u8>) -> Self {
if seq.len() < encoder.kmer_length {
Self::empty()
} else {
let index = encoder.kmer_length - 1;
let pre_first_kmer = encoder.encode_kmer(&seq[..index]);
TwoBitKmerIntoIterator {
seq,
index,
current_kmer: pre_first_kmer,
kmer_mask: encoder.kmer_mask,
}
}
}
#[inline]
#[must_use]
fn empty() -> Self {
Self {
seq: Vec::new(),
index: 0,
current_kmer: TwoBitEncodedKmer(TwoBitMaxLenToType::<MAX_LEN>::ZERO),
kmer_mask: TwoBitMaxLenToType::<MAX_LEN>::ZERO,
}
}
}
impl<const MAX_LEN: usize> Iterator for TwoBitKmerIntoIterator<MAX_LEN>
where
TwoBitKmerLen<MAX_LEN>: SupportedKmerLen,
{
type Item = TwoBitEncodedKmer<MAX_LEN>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let base = *self.seq.get(self.index)?;
self.index += 1;
self.current_kmer = TwoBitKmerIterator::shift_and_add_base(base, self.current_kmer, self.kmer_mask);
Some(self.current_kmer)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let size = self.seq.len() - self.index;
(size, Some(size))
}
}
impl<const MAX_LEN: usize> ExactSizeIterator for TwoBitKmerIntoIterator<MAX_LEN> where
TwoBitKmerLen<MAX_LEN>: SupportedKmerLen
{
}
pub struct TwoBitKmerIteratorRev<'a, const MAX_LEN: usize>
where
TwoBitKmerLen<MAX_LEN>: SupportedKmerLen, {
current_kmer: TwoBitEncodedKmer<MAX_LEN>,
remaining: std::slice::Iter<'a, u8>,
kmer_length: usize,
}
impl<'a, const MAX_LEN: usize> TwoBitKmerIteratorRev<'a, MAX_LEN>
where
TwoBitKmerLen<MAX_LEN>: SupportedKmerLen,
{
fn new(encoder: &TwoBitKmerEncoder<MAX_LEN>, seq: &'a [u8]) -> Self {
if seq.len() < encoder.kmer_length {
Self::empty()
} else {
let index = seq.len() + 1 - encoder.kmer_length;
let pre_last_kmer = encoder.encode_kmer(&seq[index..]).0 << 2;
TwoBitKmerIteratorRev {
current_kmer: pre_last_kmer.into(),
remaining: seq[..index].iter(),
kmer_length: encoder.kmer_length,
}
}
}
#[inline]
#[must_use]
fn empty() -> Self {
Self {
current_kmer: TwoBitEncodedKmer(TwoBitMaxLenToType::<MAX_LEN>::ZERO),
remaining: [].iter(),
kmer_length: 0,
}
}
#[inline]
#[must_use]
pub(crate) fn shift_and_add_base_rev(
new_base: u8, kmer: TwoBitEncodedKmer<MAX_LEN>, kmer_length: usize,
) -> TwoBitEncodedKmer<MAX_LEN> {
let encoded_base = TwoBitKmerEncoder::encode_base(new_base);
let shifted_encoded_base = encoded_base << (2 * (kmer_length - 1));
((kmer.0 >> 2) | shifted_encoded_base).into()
}
}
impl<const MAX_LEN: usize> Iterator for TwoBitKmerIteratorRev<'_, MAX_LEN>
where
TwoBitKmerLen<MAX_LEN>: SupportedKmerLen,
{
type Item = TwoBitEncodedKmer<MAX_LEN>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let base = *self.remaining.next_back()?;
self.current_kmer = TwoBitKmerIteratorRev::shift_and_add_base_rev(base, self.current_kmer, self.kmer_length);
Some(self.current_kmer)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.remaining.size_hint()
}
}
impl<const MAX_LEN: usize> ExactSizeIterator for TwoBitKmerIteratorRev<'_, MAX_LEN> where
TwoBitKmerLen<MAX_LEN>: SupportedKmerLen
{
}
pub struct TwoBitKmerIntoIteratorRev<const MAX_LEN: usize>
where
TwoBitKmerLen<MAX_LEN>: SupportedKmerLen, {
seq: Vec<u8>,
current_kmer: TwoBitEncodedKmer<MAX_LEN>,
kmer_length: usize,
}
impl<const MAX_LEN: usize> TwoBitKmerIntoIteratorRev<MAX_LEN>
where
TwoBitKmerLen<MAX_LEN>: SupportedKmerLen,
{
fn new(encoder: &TwoBitKmerEncoder<MAX_LEN>, mut seq: Vec<u8>) -> Self {
if seq.len() < encoder.kmer_length {
Self::empty()
} else {
let index = seq.len() + 1 - encoder.kmer_length;
let pre_last_kmer = encoder.encode_kmer(&seq[index..]).0 << 2;
seq.truncate(index);
TwoBitKmerIntoIteratorRev {
seq,
current_kmer: pre_last_kmer.into(),
kmer_length: encoder.kmer_length,
}
}
}
#[inline]
#[must_use]
fn empty() -> Self {
Self {
seq: Vec::new(),
current_kmer: TwoBitEncodedKmer(TwoBitMaxLenToType::<MAX_LEN>::ZERO),
kmer_length: 0,
}
}
}
impl<const MAX_LEN: usize> Iterator for TwoBitKmerIntoIteratorRev<MAX_LEN>
where
TwoBitKmerLen<MAX_LEN>: SupportedKmerLen,
{
type Item = TwoBitEncodedKmer<MAX_LEN>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let base = self.seq.pop()?;
self.current_kmer = TwoBitKmerIteratorRev::shift_and_add_base_rev(base, self.current_kmer, self.kmer_length);
Some(self.current_kmer)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let size = self.seq.len();
(size, Some(size))
}
}
impl<const MAX_LEN: usize> ExactSizeIterator for TwoBitKmerIntoIteratorRev<MAX_LEN> where
TwoBitKmerLen<MAX_LEN>: SupportedKmerLen
{
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_valid_decoding() {
assert_eq!(TwoBitKmerEncoder::<21>::decode_base(0), b'A');
assert_eq!(TwoBitKmerEncoder::<21>::decode_base(1), b'C');
assert_eq!(TwoBitKmerEncoder::<21>::decode_base(2), b'G');
assert_eq!(TwoBitKmerEncoder::<21>::decode_base(3), b'T');
}
#[test]
#[should_panic(expected = "index out of bounds: the len is 4 but the index is 4")]
fn test_invalid_decoding() {
let _ = TwoBitKmerEncoder::<21>::decode_base(4);
}
}