use crate::{
kmer::{EncodedKmerCollection, FindKmersInSeq, GetVariants, Kmer, KmerEncode, KmerError, encoders::KmerEncoder},
prelude::Len,
};
use std::{
collections::{HashMap, hash_map},
hash::{BuildHasher, RandomState},
ops::Index,
};
#[derive(Clone, Eq, PartialEq, Debug)]
pub struct KmerCounter<const MAX_LEN: usize, E: KmerEncoder<MAX_LEN>, S = RandomState>
where
S: BuildHasher, {
map: HashMap<E::EncodedKmer, usize, S>,
encoder: E,
}
impl<const MAX_LEN: usize, E: KmerEncoder<MAX_LEN>> KmerCounter<MAX_LEN, E> {
#[inline]
pub fn new(kmer_length: usize) -> Result<Self, KmerError> {
Ok(Self {
map: HashMap::default(),
encoder: E::new(kmer_length)?,
})
}
}
impl<const MAX_LEN: usize, E: KmerEncoder<MAX_LEN>, S: BuildHasher> KmerCounter<MAX_LEN, E, S> {
#[inline]
pub fn with_hasher(kmer_length: usize, hasher: S) -> Result<Self, KmerError> {
Ok(Self {
map: HashMap::with_hasher(hasher),
encoder: E::new(kmer_length)?,
})
}
}
impl<const MAX_LEN: usize, E: KmerEncoder<MAX_LEN>, S: BuildHasher> Index<E::EncodedKmer> for KmerCounter<MAX_LEN, E, S> {
type Output = usize;
#[inline]
fn index(&self, index: E::EncodedKmer) -> &Self::Output {
&self.map[&index]
}
}
impl<const MAX_LEN: usize, E: KmerEncoder<MAX_LEN>, S: BuildHasher> KmerCounter<MAX_LEN, E, S> {
pub fn tally_kmer<K>(&mut self, kmer: &K)
where
K: KmerEncode<MAX_LEN, E>, {
*self.map.entry(kmer.encode_kmer(&self.encoder)).or_default() += 1;
}
#[inline]
pub fn tally_kmer_with_variants<const N: usize>(&mut self, kmer: &impl KmerEncode<MAX_LEN, E>)
where
E: GetVariants<N, MAX_LEN>, {
self.encoder
.get_variants::<N>(kmer.encode_kmer(&self.encoder))
.for_each(|variant| self.tally_kmer(&variant));
}
#[inline]
pub fn tally_from_iter<I: IntoIterator<Item: KmerEncode<MAX_LEN, E>>>(&mut self, iter: I) {
iter.into_iter().for_each(|kmer| self.tally_kmer(&kmer));
}
#[inline]
pub fn tally_from_sequence(&mut self, seq: impl AsRef<[u8]>) {
self.encoder.iter_from_sequence(&seq).for_each(|kmer| self.tally_kmer(&kmer));
}
#[inline]
pub fn tally_from_sequence_with_variants<const N: usize>(&mut self, seq: impl AsRef<[u8]>)
where
E: GetVariants<N, MAX_LEN>, {
for encoded_kmer in self.encoder.iter_from_sequence(&seq) {
self.tally_kmer_with_variants::<N>(&encoded_kmer);
}
}
#[inline]
#[must_use]
pub fn contains<K>(&self, kmer: &K) -> bool
where
K: KmerEncode<MAX_LEN, E>, {
self.map.contains_key(&kmer.encode_kmer(&self.encoder))
}
#[inline]
pub fn get<K>(&self, kmer: &K) -> usize
where
K: KmerEncode<MAX_LEN, E>, {
self.map.get(&kmer.encode_kmer(&self.encoder)).copied().unwrap_or_default()
}
#[inline]
pub fn iter_encoded(&self) -> hash_map::Iter<'_, E::EncodedKmer, usize> {
self.map.iter()
}
#[inline]
pub fn iter_decoded(&self) -> impl Iterator<Item = (Kmer<MAX_LEN>, &usize)> {
self.map.iter().map(|(k, c)| (self.encoder.decode_kmer(*k), c))
}
#[inline]
pub fn keys_decoded(&self) -> impl Iterator<Item = Kmer<MAX_LEN>> {
self.map.keys().map(|encoded_kmer| self.encoder().decode_kmer(*encoded_kmer))
}
#[inline]
pub fn keys_encoded(&self) -> impl Iterator<Item = &E::EncodedKmer> {
self.map.keys()
}
}
impl<const MAX_LEN: usize, E: KmerEncoder<MAX_LEN>, S: BuildHasher> EncodedKmerCollection<MAX_LEN>
for KmerCounter<MAX_LEN, E, S>
{
type Encoder = E;
type EncodedKmer = E::EncodedKmer;
#[inline]
fn encoder(&self) -> &Self::Encoder {
&self.encoder
}
}
impl<const MAX_LEN: usize, E: KmerEncoder<MAX_LEN>, S: BuildHasher> FindKmersInSeq<MAX_LEN> for KmerCounter<MAX_LEN, E, S> {
#[inline]
fn contains<K>(&self, kmer: &K) -> bool
where
K: KmerEncode<MAX_LEN, Self::Encoder>, {
self.contains(kmer)
}
}
impl<const MAX_LEN: usize, E: KmerEncoder<MAX_LEN>, S: BuildHasher> IntoIterator for KmerCounter<MAX_LEN, E, S> {
type Item = (Kmer<MAX_LEN>, usize);
type IntoIter = KmerCounterDecodedIntoIter<MAX_LEN, E, S>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
Self::IntoIter {
map_into_iter: self.map.into_iter(),
encoder: self.encoder,
}
}
}
pub struct KmerCounterDecodedIntoIter<const MAX_LEN: usize, E: KmerEncoder<MAX_LEN>, S> {
pub(crate) map_into_iter: <HashMap<E::EncodedKmer, usize, S> as IntoIterator>::IntoIter,
pub(crate) encoder: E,
}
impl<const MAX_LEN: usize, E: KmerEncoder<MAX_LEN>, S> Iterator for KmerCounterDecodedIntoIter<MAX_LEN, E, S> {
type Item = (Kmer<MAX_LEN>, usize);
#[inline]
fn next(&mut self) -> Option<(Kmer<MAX_LEN>, usize)> {
self.map_into_iter.next().map(|(x, c)| (self.encoder.decode_kmer(x), c))
}
}
impl<const MAX_LEN: usize, E: KmerEncoder<MAX_LEN>, S> Len for KmerCounter<MAX_LEN, E, S>
where
S: BuildHasher,
{
#[inline]
fn is_empty(&self) -> bool {
self.map.is_empty()
}
#[inline]
fn len(&self) -> usize {
self.map.len()
}
}