use crate::{
kmer::{EncodedKmerCollection, FindKmersInSeq, GetVariants, Kmer, KmerEncode, KmerEncoder, KmerError},
prelude::Len,
};
use std::{
collections::{HashSet, hash_set},
hash::{BuildHasher, RandomState},
iter::Copied,
};
#[derive(Clone, Eq, PartialEq, Debug)]
pub struct KmerSet<const MAX_LEN: usize, E: KmerEncoder<MAX_LEN>, S = RandomState>
where
S: BuildHasher, {
set: HashSet<E::EncodedKmer, S>,
encoder: E,
}
impl<const MAX_LEN: usize, E: KmerEncoder<MAX_LEN>> KmerSet<MAX_LEN, E> {
#[inline]
pub fn new(kmer_length: usize) -> Result<Self, KmerError> {
Ok(Self {
set: HashSet::default(),
encoder: E::new(kmer_length)?,
})
}
}
impl<const MAX_LEN: usize, E: KmerEncoder<MAX_LEN>, S: BuildHasher> KmerSet<MAX_LEN, E, S> {
#[inline]
pub fn with_hasher(kmer_length: usize, hasher: S) -> Result<Self, KmerError> {
Ok(Self {
set: HashSet::with_hasher(hasher),
encoder: E::new(kmer_length)?,
})
}
}
impl<const MAX_LEN: usize, E: KmerEncoder<MAX_LEN>, S: BuildHasher> KmerSet<MAX_LEN, E, S> {
pub fn insert_kmer<K>(&mut self, kmer: &K)
where
K: KmerEncode<MAX_LEN, E>, {
self.set.insert(kmer.encode_kmer(&self.encoder));
}
#[inline]
pub fn insert_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.insert_kmer(&variant));
}
#[inline]
pub fn insert_from_iter<I: IntoIterator<Item: KmerEncode<MAX_LEN, E>>>(&mut self, iter: I) {
iter.into_iter().for_each(|kmer| self.insert_kmer(&kmer));
}
#[inline]
pub fn insert_from_sequence(&mut self, seq: impl AsRef<[u8]>) {
self.encoder.iter_from_sequence(&seq).for_each(|kmer| self.insert_kmer(&kmer));
}
#[inline]
pub fn insert_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.insert_kmer_with_variants::<N>(&encoded_kmer);
}
}
#[inline]
#[must_use]
pub fn contains<K>(&self, kmer: &K) -> bool
where
K: KmerEncode<MAX_LEN, E>, {
self.set.contains(&kmer.encode_kmer(&self.encoder))
}
#[inline]
pub fn iter_encoded(&self) -> Copied<hash_set::Iter<'_, E::EncodedKmer>> {
self.set.iter().copied()
}
#[inline]
pub fn iter_decoded(&self) -> impl Iterator<Item = Kmer<MAX_LEN>> {
self.encoder.decode_iter(self.iter_encoded())
}
#[inline]
pub fn difference_encoded<'a>(
&'a self, other: &'a KmerSet<MAX_LEN, E, S>,
) -> Copied<hash_set::Difference<'a, E::EncodedKmer, S>> {
self.set.difference(&other.set).copied()
}
#[inline]
pub fn difference_decoded<'a>(&'a self, other: &'a KmerSet<MAX_LEN, E, S>) -> impl Iterator<Item = Kmer<MAX_LEN>> {
self.encoder.decode_iter(self.difference_encoded(other))
}
#[inline]
pub fn intersection<'a>(
&'a self, other: &'a KmerSet<MAX_LEN, E, S>,
) -> Copied<hash_set::Intersection<'a, E::EncodedKmer, S>> {
self.set.intersection(&other.set).copied()
}
#[inline]
pub fn intersection_decoded<'a>(&'a self, other: &'a KmerSet<MAX_LEN, E, S>) -> impl Iterator<Item = Kmer<MAX_LEN>> {
self.encoder.decode_iter(self.intersection(other))
}
#[inline]
pub fn symmetric_difference<'a>(
&'a self, other: &'a KmerSet<MAX_LEN, E, S>,
) -> Copied<hash_set::SymmetricDifference<'a, E::EncodedKmer, S>> {
self.set.symmetric_difference(&other.set).copied()
}
#[inline]
pub fn symmetric_difference_decoded<'a>(
&'a self, other: &'a KmerSet<MAX_LEN, E, S>,
) -> impl Iterator<Item = Kmer<MAX_LEN>> {
self.encoder.decode_iter(self.symmetric_difference(other))
}
#[inline]
pub fn union<'a>(&'a self, other: &'a KmerSet<MAX_LEN, E, S>) -> Copied<hash_set::Union<'a, E::EncodedKmer, S>> {
self.set.union(&other.set).copied()
}
#[inline]
pub fn union_decoded<'a>(&'a self, other: &'a KmerSet<MAX_LEN, E, S>) -> impl Iterator<Item = Kmer<MAX_LEN>> {
self.encoder.decode_iter(self.union(other))
}
}
impl<const MAX_LEN: usize, E: KmerEncoder<MAX_LEN>, S: BuildHasher> EncodedKmerCollection<MAX_LEN>
for KmerSet<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 KmerSet<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 KmerSet<MAX_LEN, E, S> {
type Item = Kmer<MAX_LEN>;
type IntoIter = KmerSetDecodedIntoIter<MAX_LEN, E, S>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
Self::IntoIter {
set_into_iter: self.set.into_iter(),
encoder: self.encoder,
}
}
}
pub struct KmerSetDecodedIntoIter<const MAX_LEN: usize, E: KmerEncoder<MAX_LEN>, S> {
pub(crate) set_into_iter: <HashSet<E::EncodedKmer, S> as IntoIterator>::IntoIter,
pub(crate) encoder: E,
}
impl<const MAX_LEN: usize, E: KmerEncoder<MAX_LEN>, S> Iterator for KmerSetDecodedIntoIter<MAX_LEN, E, S> {
type Item = Kmer<MAX_LEN>;
#[inline]
fn next(&mut self) -> Option<Kmer<MAX_LEN>> {
self.set_into_iter.next().map(|x| self.encoder.decode_kmer(x))
}
}
impl<const MAX_LEN: usize, E: KmerEncoder<MAX_LEN>, S> Len for KmerSet<MAX_LEN, E, S>
where
S: BuildHasher,
{
#[inline]
fn is_empty(&self) -> bool {
self.set.is_empty()
}
#[inline]
fn len(&self) -> usize {
self.set.len()
}
}