use std::cell::Cell;
use std::cmp::Ordering;
use std::fmt::Formatter;
use std::hash::{Hash, Hasher};
use std::ops::{Deref, DerefMut};
use crate::symbol::iter_symbols;
use crate::{Nuc, Seq, iter::display};
use super::ambidna::{PackedAmbiDna, PackedArrayAmbiDna};
use super::packable_array::{ArrayDefault, Sealed as ArrayDivide};
use super::{PackableArray, RefCmp, UnpackingIter};
#[derive(Clone, Default)]
pub struct PackedDna(Vec<u8>);
impl PackedDna {
#[must_use]
pub fn len(&self) -> usize {
match &*self.0 {
[] => 0,
[bulk @ .., tail] => 4 * bulk.len() + (tail & 0b11) as usize,
}
}
#[must_use]
pub fn is_empty(&self) -> bool {
matches!(&*self.0, [] | [0])
}
pub fn push(&mut self, nuc: Nuc) {
assert_ne!(self.len(), isize::MAX as usize);
match &mut *self.0 {
[] => self.0.push(nuc.compress() << 6 | 1),
[.., last] => {
let len = *last & 0b11;
let offset = 6 - 2 * len;
*last = *last & !(0b11 << offset) | (nuc.compress() << offset);
if len == 3 {
self.0.push(0);
} else {
*last += 1;
}
}
}
}
pub fn pop(&mut self) -> Option<Nuc> {
match &mut *self.0 {
[] | [0] => None,
[.., last, 0] => {
let nuc = Nuc::decompress(*last);
*last = *last & !0b11 | 3;
self.0.pop();
Some(nuc)
}
[.., last] => {
let len = *last & 0b11;
let offset = 8 - 2 * len;
let nuc = Nuc::decompress(*last >> offset);
*last &= !(0b11 << offset);
*last -= 1;
if let [0] = &*self.0 {
self.0.clear(); }
Some(nuc)
}
}
}
#[must_use]
pub fn iter(&self) -> PackedDnaIter<'_> {
self.into_iter()
}
#[must_use]
pub fn iter_mut(&mut self) -> PackedDnaMutIter<'_> {
self.into_iter()
}
}
impl From<Seq<Vec<Nuc>>> for PackedDna {
fn from(dna: Seq<Vec<Nuc>>) -> PackedDna {
dna.0.into()
}
}
impl From<Vec<Nuc>> for PackedDna {
fn from(dna: Vec<Nuc>) -> PackedDna {
(&dna).into()
}
}
impl<T: AsRef<[Nuc]> + ?Sized> From<&T> for PackedDna {
fn from(dna: &T) -> PackedDna {
let dna = dna.as_ref();
let packed_len = match dna.len() {
0 => 0, l => l / 4 + 1,
};
let mut packed = vec![0; packed_len];
pack(&mut packed, dna);
if let Some(byte) = packed.last_mut() {
*byte |=
u8::try_from(dna.len() % 4).unwrap_or_else(|_| unreachable!("x % 4 fits in a u8"));
}
Self(packed)
}
}
impl From<PackedDna> for Seq<Vec<Nuc>> {
fn from(packed_dna: PackedDna) -> Seq<Vec<Nuc>> {
Seq(packed_dna.into())
}
}
impl From<&PackedDna> for Seq<Vec<Nuc>> {
fn from(packed_dna: &PackedDna) -> Seq<Vec<Nuc>> {
Seq(packed_dna.into())
}
}
impl From<PackedDna> for Vec<Nuc> {
fn from(packed_dna: PackedDna) -> Vec<Nuc> {
(&packed_dna).into()
}
}
impl From<&PackedDna> for Vec<Nuc> {
fn from(packed_dna: &PackedDna) -> Vec<Nuc> {
let mut dna = vec![Nuc::default(); packed_dna.len()];
unpack(&mut dna, &packed_dna.0);
dna
}
}
impl<'a> IntoIterator for &'a PackedDna {
type Item = Nuc;
type IntoIter = PackedDnaIter<'a>;
fn into_iter(self) -> Self::IntoIter {
PackedDnaIter(UnpackingIter::new(0..self.len(), &self.0))
}
}
impl<'a> IntoIterator for &'a mut PackedDna {
type Item = PackedNuc<'a>;
type IntoIter = PackedDnaMutIter<'a>;
fn into_iter(self) -> Self::IntoIter {
let len = self.len();
let backing = Cell::from_mut(self.0.as_mut_slice()).as_slice_of_cells();
PackedDnaMutIter(UnpackingIter::new(0..len, backing))
}
}
impl IntoIterator for PackedDna {
type Item = Nuc;
type IntoIter = PackedDnaIntoIter;
fn into_iter(self) -> Self::IntoIter {
PackedDnaIntoIter(UnpackingIter::new(0..self.len(), self.0))
}
}
impl Hash for PackedDna {
fn hash<H: Hasher>(&self, state: &mut H) {
match &*self.0 {
[] => [0u8].hash(state),
x => x.hash(state),
}
}
}
impl PartialEq for PackedDna {
fn eq(&self, other: &Self) -> bool {
match (&*self.0, &*other.0) {
([], [0]) | ([0], []) => true,
(x, y) => x == y,
}
}
}
impl Eq for PackedDna {}
impl PartialOrd for PackedDna {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for PackedDna {
fn cmp(&self, other: &Self) -> Ordering {
match (&*self.0, &*other.0) {
([] | [0], [] | [0]) => Ordering::Equal,
([] | [0], _) => Ordering::Less,
(_, [] | [0]) => Ordering::Greater,
([x_bulk @ .., x_last], [y_bulk @ .., y_last]) => {
let common_prefix_len = x_bulk.len().min(y_bulk.len());
let (x_prefix, x_remainder) = x_bulk.split_at(common_prefix_len);
let (y_prefix, y_remainder) = y_bulk.split_at(common_prefix_len);
x_prefix
.cmp(y_prefix)
.then_with(|| match (x_remainder, y_remainder) {
([], []) => x_last.cmp(y_last),
([], [y_next, ..]) => (x_last & !0b11).cmp(y_next).then(Ordering::Less),
([x_next, ..], []) => x_next.cmp(&(y_last & !0b11)).then(Ordering::Greater),
_ => unreachable!(),
})
}
}
}
}
impl<const N: usize> PartialEq<PackedArrayDna<N>> for PackedDna
where
[(); N]: PackableArray,
{
fn eq(&self, other: &PackedArrayDna<N>) -> bool {
self.iter().eq(other.iter())
}
}
impl<const N: usize> PartialOrd<PackedArrayDna<N>> for PackedDna
where
[(); N]: PackableArray,
{
fn partial_cmp(&self, other: &PackedArrayDna<N>) -> Option<Ordering> {
self.iter().partial_cmp(other.iter())
}
}
impl PartialEq<PackedAmbiDna> for PackedDna {
fn eq(&self, other: &PackedAmbiDna) -> bool {
self.iter().eq(other.iter())
}
}
impl PartialOrd<PackedAmbiDna> for PackedDna {
fn partial_cmp(&self, other: &PackedAmbiDna) -> Option<Ordering> {
self.iter().partial_cmp(other.iter())
}
}
impl<const N: usize> PartialEq<PackedArrayAmbiDna<N>> for PackedDna
where
[(); N]: PackableArray,
{
fn eq(&self, other: &PackedArrayAmbiDna<N>) -> bool {
self.iter().eq(other.iter())
}
}
impl<const N: usize> PartialOrd<PackedArrayAmbiDna<N>> for PackedDna
where
[(); N]: PackableArray,
{
fn partial_cmp(&self, other: &PackedArrayAmbiDna<N>) -> Option<Ordering> {
self.iter().partial_cmp(other.iter())
}
}
impl<T: PartialEq<Nuc>, const M: usize> PartialEq<[T; M]> for PackedDna {
fn eq(&self, other: &[T; M]) -> bool {
self.eq(&other.as_slice())
}
}
impl<T: PartialOrd<Nuc>, const M: usize> PartialOrd<[T; M]> for PackedDna {
fn partial_cmp(&self, other: &[T; M]) -> Option<Ordering> {
self.partial_cmp(&other.as_slice())
}
}
impl<T: PartialEq<Nuc>, const M: usize> PartialEq<&mut [T; M]> for PackedDna {
fn eq(&self, other: &&mut [T; M]) -> bool {
self.eq(&other.as_slice())
}
}
impl<T: PartialOrd<Nuc>, const M: usize> PartialOrd<&mut [T; M]> for PackedDna {
fn partial_cmp(&self, other: &&mut [T; M]) -> Option<Ordering> {
self.partial_cmp(&other.as_slice())
}
}
impl<T: PartialEq<Nuc>, const M: usize> PartialEq<&[T; M]> for PackedDna {
fn eq(&self, other: &&[T; M]) -> bool {
self.eq(&other.as_slice())
}
}
impl<T: PartialOrd<Nuc>, const M: usize> PartialOrd<&[T; M]> for PackedDna {
fn partial_cmp(&self, other: &&[T; M]) -> Option<Ordering> {
self.partial_cmp(&other.as_slice())
}
}
impl<T: PartialEq<Nuc>> PartialEq<Vec<T>> for PackedDna {
fn eq(&self, other: &Vec<T>) -> bool {
self.eq(&&**other)
}
}
impl<T: PartialOrd<Nuc>> PartialOrd<Vec<T>> for PackedDna {
fn partial_cmp(&self, other: &Vec<T>) -> Option<Ordering> {
self.partial_cmp(&&**other)
}
}
impl<T: PartialEq<Nuc>> PartialEq<&mut [T]> for PackedDna {
fn eq(&self, other: &&mut [T]) -> bool {
self.eq(&&**other)
}
}
impl<T: PartialOrd<Nuc>> PartialOrd<&mut [T]> for PackedDna {
fn partial_cmp(&self, other: &&mut [T]) -> Option<Ordering> {
self.partial_cmp(&&**other)
}
}
impl<T: PartialEq<Nuc>> PartialEq<&[T]> for PackedDna {
fn eq(&self, other: &&[T]) -> bool {
self.len() == other.len() && self.iter().map(RefCmp).eq(*other)
}
}
impl<T: PartialOrd<Nuc>> PartialOrd<&[T]> for PackedDna {
fn partial_cmp(&self, other: &&[T]) -> Option<Ordering> {
self.iter().map(RefCmp).partial_cmp(*other)
}
}
impl PartialEq<&str> for PackedDna {
fn eq(&self, rhs: &&str) -> bool {
self == *rhs
}
}
impl PartialEq<str> for PackedDna {
fn eq(&self, rhs: &str) -> bool {
self.iter().map(Ok).eq(iter_symbols(rhs))
}
}
impl std::fmt::Display for PackedDna {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
self.iter().fmt(f)
}
}
impl std::fmt::Debug for PackedDna {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
f.debug_tuple("PackedDna")
.field(&display(self.iter()))
.finish()
}
}
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct PackedArrayDna<const N: usize>(PackedBuf<N>)
where
[(); N]: PackableArray;
type PackedBuf<const N: usize> = <[(); N] as ArrayDivide>::By4<u8>;
impl<const N: usize> PackedArrayDna<N>
where
[(); N]: PackableArray,
{
#[must_use]
pub fn iter(&self) -> PackedDnaIter<'_> {
self.into_iter()
}
#[must_use]
pub fn iter_mut(&mut self) -> PackedDnaMutIter<'_> {
self.into_iter()
}
}
impl<const N: usize> Default for PackedArrayDna<N>
where
[(); N]: PackableArray,
{
fn default() -> Self {
Self(ArrayDefault::array_default())
}
}
impl<const N: usize> From<Seq<[Nuc; N]>> for PackedArrayDna<N>
where
[(); N]: PackableArray,
{
fn from(dna: Seq<[Nuc; N]>) -> PackedArrayDna<N> {
dna.0.into()
}
}
impl<const N: usize> From<&Seq<[Nuc; N]>> for PackedArrayDna<N>
where
[(); N]: PackableArray,
{
fn from(dna: &Seq<[Nuc; N]>) -> PackedArrayDna<N> {
dna.0.into()
}
}
impl<const N: usize> From<[Nuc; N]> for PackedArrayDna<N>
where
[(); N]: PackableArray,
{
fn from(dna: [Nuc; N]) -> PackedArrayDna<N> {
(&dna).into()
}
}
impl<const N: usize> From<&[Nuc; N]> for PackedArrayDna<N>
where
[(); N]: PackableArray,
{
fn from(dna: &[Nuc; N]) -> PackedArrayDna<N> {
let mut this = Self(ArrayDefault::array_default());
pack(this.0.as_mut(), dna);
this
}
}
impl<const N: usize> From<PackedArrayDna<N>> for Seq<[Nuc; N]>
where
[(); N]: PackableArray,
{
fn from(packed_dna: PackedArrayDna<N>) -> Seq<[Nuc; N]> {
Seq(packed_dna.into())
}
}
impl<const N: usize> From<&PackedArrayDna<N>> for Seq<[Nuc; N]>
where
[(); N]: PackableArray,
{
fn from(packed_dna: &PackedArrayDna<N>) -> Seq<[Nuc; N]> {
Seq(packed_dna.into())
}
}
impl<const N: usize> From<PackedArrayDna<N>> for [Nuc; N]
where
[(); N]: PackableArray,
{
fn from(packed_dna: PackedArrayDna<N>) -> [Nuc; N] {
(&packed_dna).into()
}
}
impl<const N: usize> From<&PackedArrayDna<N>> for [Nuc; N]
where
[(); N]: PackableArray,
{
fn from(packed_dna: &PackedArrayDna<N>) -> [Nuc; N] {
let mut dna = [Nuc::default(); N];
unpack(&mut dna, packed_dna.0.as_ref());
dna
}
}
impl<'a, const N: usize> IntoIterator for &'a PackedArrayDna<N>
where
[(); N]: PackableArray,
{
type Item = Nuc;
type IntoIter = PackedDnaIter<'a>;
fn into_iter(self) -> Self::IntoIter {
PackedDnaIter(UnpackingIter::new(0..N, self.0.as_ref()))
}
}
impl<'a, const N: usize> IntoIterator for &'a mut PackedArrayDna<N>
where
[(); N]: PackableArray,
{
type Item = PackedNuc<'a>;
type IntoIter = PackedDnaMutIter<'a>;
fn into_iter(self) -> Self::IntoIter {
let backing = Cell::from_mut(self.0.as_mut()).as_slice_of_cells();
PackedDnaMutIter(UnpackingIter::new(0..N, backing))
}
}
impl<const N: usize> IntoIterator for PackedArrayDna<N>
where
[(); N]: PackableArray,
{
type Item = Nuc;
type IntoIter = PackedArrayDnaIntoIter<N>;
fn into_iter(self) -> Self::IntoIter {
PackedArrayDnaIntoIter(UnpackingIter::new(0..N, self.0))
}
}
impl<const N: usize> PartialEq<PackedDna> for PackedArrayDna<N>
where
[(); N]: PackableArray,
{
fn eq(&self, other: &PackedDna) -> bool {
other == self
}
}
impl<const N: usize> PartialOrd<PackedDna> for PackedArrayDna<N>
where
[(); N]: PackableArray,
{
fn partial_cmp(&self, other: &PackedDna) -> Option<Ordering> {
other.partial_cmp(self).map(Ordering::reverse)
}
}
impl<const N: usize> PartialEq<PackedAmbiDna> for PackedArrayDna<N>
where
[(); N]: PackableArray,
{
fn eq(&self, other: &PackedAmbiDna) -> bool {
self.iter().eq(other.iter())
}
}
impl<const N: usize> PartialOrd<PackedAmbiDna> for PackedArrayDna<N>
where
[(); N]: PackableArray,
{
fn partial_cmp(&self, other: &PackedAmbiDna) -> Option<Ordering> {
self.iter().partial_cmp(other.iter())
}
}
impl<const N: usize> PartialEq<PackedArrayAmbiDna<N>> for PackedArrayDna<N>
where
[(); N]: PackableArray,
{
fn eq(&self, other: &PackedArrayAmbiDna<N>) -> bool {
self.iter().eq(other.iter())
}
}
impl<const N: usize> PartialOrd<PackedArrayAmbiDna<N>> for PackedArrayDna<N>
where
[(); N]: PackableArray,
{
fn partial_cmp(&self, other: &PackedArrayAmbiDna<N>) -> Option<Ordering> {
self.iter().partial_cmp(other.iter())
}
}
impl<T: PartialEq<Nuc>, const N: usize, const M: usize> PartialEq<[T; M]> for PackedArrayDna<N>
where
[(); N]: PackableArray,
{
fn eq(&self, other: &[T; M]) -> bool {
self.eq(&other.as_slice())
}
}
impl<T: PartialOrd<Nuc>, const N: usize, const M: usize> PartialOrd<[T; M]> for PackedArrayDna<N>
where
[(); N]: PackableArray,
{
fn partial_cmp(&self, other: &[T; M]) -> Option<Ordering> {
self.partial_cmp(&other.as_slice())
}
}
impl<T: PartialEq<Nuc>, const N: usize, const M: usize> PartialEq<&mut [T; M]> for PackedArrayDna<N>
where
[(); N]: PackableArray,
{
fn eq(&self, other: &&mut [T; M]) -> bool {
self.eq(&other.as_slice())
}
}
impl<T: PartialOrd<Nuc>, const N: usize, const M: usize> PartialOrd<&mut [T; M]>
for PackedArrayDna<N>
where
[(); N]: PackableArray,
{
fn partial_cmp(&self, other: &&mut [T; M]) -> Option<Ordering> {
self.partial_cmp(&other.as_slice())
}
}
impl<T: PartialEq<Nuc>, const N: usize, const M: usize> PartialEq<&[T; M]> for PackedArrayDna<N>
where
[(); N]: PackableArray,
{
fn eq(&self, other: &&[T; M]) -> bool {
self.eq(&other.as_slice())
}
}
impl<T: PartialOrd<Nuc>, const N: usize, const M: usize> PartialOrd<&[T; M]> for PackedArrayDna<N>
where
[(); N]: PackableArray,
{
fn partial_cmp(&self, other: &&[T; M]) -> Option<Ordering> {
self.partial_cmp(&other.as_slice())
}
}
impl<T: PartialEq<Nuc>, const N: usize> PartialEq<Vec<T>> for PackedArrayDna<N>
where
[(); N]: PackableArray,
{
fn eq(&self, other: &Vec<T>) -> bool {
self.eq(&&**other)
}
}
impl<T: PartialOrd<Nuc>, const N: usize> PartialOrd<Vec<T>> for PackedArrayDna<N>
where
[(); N]: PackableArray,
{
fn partial_cmp(&self, other: &Vec<T>) -> Option<Ordering> {
self.partial_cmp(&&**other)
}
}
impl<T: PartialEq<Nuc>, const N: usize> PartialEq<&mut [T]> for PackedArrayDna<N>
where
[(); N]: PackableArray,
{
fn eq(&self, other: &&mut [T]) -> bool {
self.eq(&&**other)
}
}
impl<T: PartialOrd<Nuc>, const N: usize> PartialOrd<&mut [T]> for PackedArrayDna<N>
where
[(); N]: PackableArray,
{
fn partial_cmp(&self, other: &&mut [T]) -> Option<Ordering> {
self.partial_cmp(&&**other)
}
}
impl<T: PartialEq<Nuc>, const N: usize> PartialEq<&[T]> for PackedArrayDna<N>
where
[(); N]: PackableArray,
{
fn eq(&self, other: &&[T]) -> bool {
N == other.len() && self.iter().map(RefCmp).eq(*other)
}
}
impl<T: PartialOrd<Nuc>, const N: usize> PartialOrd<&[T]> for PackedArrayDna<N>
where
[(); N]: PackableArray,
{
fn partial_cmp(&self, other: &&[T]) -> Option<Ordering> {
self.iter().map(RefCmp).partial_cmp(*other)
}
}
impl<const N: usize> PartialEq<&str> for PackedArrayDna<N>
where
[(); N]: PackableArray,
{
fn eq(&self, rhs: &&str) -> bool {
self == *rhs
}
}
impl<const N: usize> PartialEq<str> for PackedArrayDna<N>
where
[(); N]: PackableArray,
{
fn eq(&self, rhs: &str) -> bool {
self.iter().map(Ok).eq(iter_symbols(rhs))
}
}
impl<const N: usize> std::fmt::Display for PackedArrayDna<N>
where
[(); N]: PackableArray,
{
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
self.iter().fmt(f)
}
}
impl<const N: usize> std::fmt::Debug for PackedArrayDna<N>
where
[(); N]: PackableArray,
{
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
f.debug_tuple("PackedArrayDna")
.field(&display(self.iter()))
.finish()
}
}
fn pack(packed: &mut [u8], dna: &[Nuc]) {
let (quads, remainder) = dna.as_chunks();
for (byte, &[n1, n2, n3, n4]) in packed.iter_mut().zip(quads) {
*byte = n4.compress() | (n3.compress() << 2) | (n2.compress() << 4) | (n1.compress() << 6);
}
if let Some(byte) = packed.last_mut()
&& !remainder.is_empty()
{
*byte = 0;
for (offset, &nuc) in [6, 4, 2].into_iter().zip(remainder) {
*byte |= nuc.compress() << offset;
}
}
}
fn unpack(dna: &mut [Nuc], packed: &[u8]) {
let (quads, remainder) = dna.as_chunks_mut();
for ([n1, n2, n3, n4], &byte) in quads.iter_mut().zip(packed) {
*n4 = Nuc::decompress(byte);
*n3 = Nuc::decompress(byte >> 2);
*n2 = Nuc::decompress(byte >> 4);
*n1 = Nuc::decompress(byte >> 6);
}
if let Some(byte) = packed.last()
&& !remainder.is_empty()
{
for (offset, nuc) in [6, 4, 2].into_iter().zip(remainder) {
*nuc = Nuc::decompress(byte >> offset);
}
}
}
#[derive(Clone)]
pub struct PackedDnaIntoIter(UnpackingIter<2, 8, std::vec::IntoIter<u8>>);
impl PackedDnaIntoIter {
fn as_ref(&self) -> PackedDnaIter<'_> {
PackedDnaIter(self.0.as_ref())
}
}
impl Iterator for PackedDnaIntoIter {
type Item = Nuc;
fn next(&mut self) -> Option<Nuc> {
self.0
.next()
.map(|(shift, byte)| Nuc::decompress(byte >> shift))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl DoubleEndedIterator for PackedDnaIntoIter {
fn next_back(&mut self) -> Option<Nuc> {
self.0
.next_back()
.map(|(shift, byte)| Nuc::decompress(byte >> shift))
}
}
impl ExactSizeIterator for PackedDnaIntoIter {
fn len(&self) -> usize {
self.0.len()
}
}
impl std::fmt::Display for PackedDnaIntoIter {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
self.as_ref().fmt(f)
}
}
impl std::fmt::Debug for PackedDnaIntoIter {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
f.debug_tuple("PackedDnaIntoIter")
.field(&display(self.as_ref()))
.finish()
}
}
#[derive(Clone)]
pub struct PackedArrayDnaIntoIter<const N: usize>(
UnpackingIter<2, 8, <PackedBuf<N> as IntoIterator>::IntoIter>,
)
where
[(); N]: PackableArray;
impl<const N: usize> PackedArrayDnaIntoIter<N>
where
[(); N]: PackableArray,
{
fn as_ref(&self) -> PackedDnaIter<'_> {
PackedDnaIter(self.0.as_ref())
}
}
impl<const N: usize> Iterator for PackedArrayDnaIntoIter<N>
where
[(); N]: PackableArray,
{
type Item = Nuc;
fn next(&mut self) -> Option<Nuc> {
self.0
.next()
.map(|(shift, byte)| Nuc::decompress(byte >> shift))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<const N: usize> DoubleEndedIterator for PackedArrayDnaIntoIter<N>
where
[(); N]: PackableArray,
{
fn next_back(&mut self) -> Option<Nuc> {
self.0
.next_back()
.map(|(shift, byte)| Nuc::decompress(byte >> shift))
}
}
impl<const N: usize> ExactSizeIterator for PackedArrayDnaIntoIter<N>
where
[(); N]: PackableArray,
{
fn len(&self) -> usize {
self.0.len()
}
}
impl<const N: usize> std::fmt::Display for PackedArrayDnaIntoIter<N>
where
[(); N]: PackableArray,
{
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
self.as_ref().fmt(f)
}
}
impl<const N: usize> std::fmt::Debug for PackedArrayDnaIntoIter<N>
where
[(); N]: PackableArray,
{
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
f.debug_tuple("PackedArrayDnaIntoIter")
.field(&display(self.as_ref()))
.finish()
}
}
#[derive(Clone)]
pub struct PackedDnaIter<'a>(UnpackingIter<2, 8, std::slice::Iter<'a, u8>>);
impl Iterator for PackedDnaIter<'_> {
type Item = Nuc;
fn next(&mut self) -> Option<Nuc> {
self.0
.next()
.map(|(shift, byte)| Nuc::decompress(byte >> shift))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl DoubleEndedIterator for PackedDnaIter<'_> {
fn next_back(&mut self) -> Option<Nuc> {
self.0
.next_back()
.map(|(shift, byte)| Nuc::decompress(byte >> shift))
}
}
impl ExactSizeIterator for PackedDnaIter<'_> {
fn len(&self) -> usize {
self.0.len()
}
}
impl std::fmt::Display for PackedDnaIter<'_> {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
display(self.clone()).fmt(f)
}
}
impl std::fmt::Debug for PackedDnaIter<'_> {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
f.debug_tuple("PackedDnaIter")
.field(&display(self.clone()))
.finish()
}
}
pub struct PackedDnaMutIter<'a>(UnpackingIter<2, 8, std::slice::Iter<'a, Cell<u8>>>);
impl PackedDnaMutIter<'_> {
fn read_values(&self) -> impl Iterator<Item = Nuc> + Clone {
self.0
.clone()
.map(|(shift, byte)| Nuc::decompress(byte.get() >> shift))
}
}
impl<'a> Iterator for PackedDnaMutIter<'a> {
type Item = PackedNuc<'a>;
fn next(&mut self) -> Option<PackedNuc<'a>> {
self.0.next().map(PackedNuc::new)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<'a> DoubleEndedIterator for PackedDnaMutIter<'a> {
fn next_back(&mut self) -> Option<PackedNuc<'a>> {
self.0.next_back().map(PackedNuc::new)
}
}
impl ExactSizeIterator for PackedDnaMutIter<'_> {
fn len(&self) -> usize {
self.0.len()
}
}
impl std::fmt::Display for PackedDnaMutIter<'_> {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
display(self.read_values()).fmt(f)
}
}
impl std::fmt::Debug for PackedDnaMutIter<'_> {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
f.debug_tuple("PackedDnaMutIter")
.field(&display(self.read_values()))
.finish()
}
}
pub struct PackedNuc<'a> {
packed: &'a Cell<u8>,
shift: u8,
unpacked: Nuc,
}
impl<'a> PackedNuc<'a> {
fn new((shift, packed): (u8, &'a Cell<u8>)) -> Self {
let unpacked = Nuc::decompress(packed.get() >> shift);
Self {
packed,
shift,
unpacked,
}
}
}
impl Drop for PackedNuc<'_> {
fn drop(&mut self) {
self.packed
.update(|p| p & !(0b11 << self.shift) | self.unpacked.compress() << self.shift);
}
}
impl Deref for PackedNuc<'_> {
type Target = Nuc;
fn deref(&self) -> &Nuc {
&self.unpacked
}
}
impl DerefMut for PackedNuc<'_> {
fn deref_mut(&mut self) -> &mut Nuc {
&mut self.unpacked
}
}
impl AsRef<Nuc> for PackedNuc<'_> {
fn as_ref(&self) -> &Nuc {
self
}
}
impl AsMut<Nuc> for PackedNuc<'_> {
fn as_mut(&mut self) -> &mut Nuc {
self
}
}
impl std::fmt::Display for PackedNuc<'_> {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
self.unpacked.fmt(f)
}
}
impl std::fmt::Debug for PackedNuc<'_> {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
f.debug_tuple("PackedNuc").field(&self.unpacked).finish()
}
}
#[cfg(test)]
mod tests {
use proptest::{arbitrary::any, proptest};
use super::super::tests::{assert_both_roundtrips, assert_roundtrip};
use crate::proptest::{any_ambi_dna, any_dna};
use super::*;
#[cfg_attr(miri, ignore = "slow in miri; shouldn't touch unsafe code anyway")]
#[test]
fn all_short_roundtrips() {
assert_both_roundtrips(&[] as &[Nuc; 0]);
for n1 in Nuc::ALL {
assert_both_roundtrips(&[n1]);
for n2 in Nuc::ALL {
assert_both_roundtrips(&[n1, n2]);
for n3 in Nuc::ALL {
assert_both_roundtrips(&[n1, n2, n3]);
for n4 in Nuc::ALL {
assert_both_roundtrips(&[n1, n2, n3, n4]);
for n5 in Nuc::ALL {
assert_both_roundtrips(&[n1, n2, n3, n4, n5]);
for n6 in Nuc::ALL {
assert_both_roundtrips(&[n1, n2, n3, n4, n5, n6]);
for n7 in Nuc::ALL {
assert_both_roundtrips(&[n1, n2, n3, n4, n5, n6, n7]);
for n8 in Nuc::ALL {
assert_both_roundtrips(&[n1, n2, n3, n4, n5, n6, n7, n8]);
}
}
}
}
}
}
}
}
}
#[test]
fn smoke_test_iters() {
let dna = Nuc::seq(b"ACGT")[..].pack();
assert_eq!(Seq(Vec::from_iter(&dna)), "ACGT");
assert_eq!(Seq(Vec::from_iter(dna)), "ACGT");
let dna = Nuc::seq(b"ACGT").pack();
assert_eq!(Seq(Vec::from_iter(&dna)), "ACGT");
assert_eq!(Seq(Vec::from_iter(dna)), "ACGT");
}
#[test]
fn packed_dna_eq_str() {
let dna = Nuc::seq(b"ACGT")[..].pack();
assert_eq!(dna, "ACGT");
let dna = Nuc::seq(b"ACGT").pack();
assert_eq!(dna, "ACGT");
}
#[test]
fn display() {
let dna = Nuc::seq(b"ACGT")[..].pack();
assert_eq!(dna.to_string(), "ACGT");
assert_eq!(dna.iter().to_string(), "ACGT");
assert_eq!(dna.into_iter().to_string(), "ACGT");
let dna = Nuc::seq(b"ACGT").pack();
assert_eq!(dna.to_string(), "ACGT");
assert_eq!(dna.iter().to_string(), "ACGT");
assert_eq!(dna.into_iter().to_string(), "ACGT");
}
proptest! {
#[cfg_attr(miri, ignore = "slow in miri; shouldn't touch unsafe code anyway")]
#[test]
fn packed_dna_roundtrip(
dna in any_dna(9..50) ) {
assert_roundtrip(&*dna);
}
#[cfg_attr(miri, ignore = "slow in miri; shouldn't touch unsafe code anyway")]
#[test]
fn packed_array_dna9_roundtrip(
dna in any::<[Nuc; 9]>()
) {
assert_roundtrip(&dna);
}
#[cfg_attr(miri, ignore = "slow in miri; shouldn't touch unsafe code anyway")]
#[test]
fn packed_array_dna10_roundtrip(
dna in any::<[Nuc; 10]>()
) {
assert_roundtrip(&dna);
}
#[cfg_attr(miri, ignore = "slow in miri; shouldn't touch unsafe code anyway")]
#[test]
fn packed_array_dna11_roundtrip(
dna in any::<[Nuc; 11]>()
) {
assert_roundtrip(&dna);
}
#[cfg_attr(miri, ignore = "slow in miri; shouldn't touch unsafe code anyway")]
#[test]
fn packed_array_dna12_roundtrip(
dna in any::<[Nuc; 12]>()
) {
assert_roundtrip(&dna);
}
#[cfg_attr(miri, ignore = "slow in miri; shouldn't touch unsafe code anyway")]
#[test]
fn packed_dna_length(
dna in any_dna(0..50)
) {
let packed = PackedDna::from(&dna);
assert_eq!(packed.len(), dna.len());
assert_eq!(packed.is_empty(), dna.is_empty());
}
#[cfg_attr(miri, ignore = "slow in miri; shouldn't touch unsafe code anyway")]
#[test]
fn packed_dna_ord(
dna1 in any_dna(0..50),
dna2 in any_dna(0..50),
) {
let packed1 = PackedDna::from(&dna1);
let packed2 = PackedDna::from(&dna2);
assert_eq!(packed1.cmp(&packed2), dna1.cmp(&dna2));
assert_eq!(packed1.eq(&packed2), dna1.eq(&dna2));
}
#[cfg_attr(miri, ignore = "slow in miri; shouldn't touch unsafe code anyway")]
#[test]
fn packed_dna_ord_vs_slice(
dna1 in any_dna(0..50),
dna2 in any_dna(0..50),
) {
let packed1 = PackedDna::from(&dna1);
assert_eq!(packed1.partial_cmp(&dna2), dna1.partial_cmp(&dna2));
assert_eq!(packed1.eq(&dna2), dna1.eq(&dna2));
}
#[cfg_attr(miri, ignore = "slow in miri; shouldn't touch unsafe code anyway")]
#[test]
fn packed_dna_ord_vs_ambi_slice(
dna1 in any_dna(0..50),
ambi_dna2 in any_ambi_dna(0..50),
) {
let packed1 = PackedDna::from(&dna1);
assert_eq!(packed1.partial_cmp(&ambi_dna2), dna1.iter().partial_cmp(&ambi_dna2));
assert_eq!(packed1.eq(&ambi_dna2), dna1.eq(&ambi_dna2));
}
#[cfg_attr(miri, ignore = "slow in miri; shouldn't touch unsafe code anyway")]
#[test]
fn packed_dna5_ord(
dna1 in any::<[Nuc; 5]>(),
dna2 in any_dna(0..10),
) {
let packed1 = PackedArrayDna::from(&dna1);
assert_eq!(packed1.partial_cmp(&dna2), dna1.as_slice().partial_cmp(&dna2));
assert_eq!(packed1.eq(&dna2), dna1.as_slice().eq(&dna2));
}
#[cfg_attr(miri, ignore = "slow in miri; shouldn't touch unsafe code anyway")]
#[test]
fn push_and_pop(
mut dna in any_dna(0..25),
ops in proptest::collection::vec(any::<Option<Nuc>>(), 0..50),
) {
let mut packed = PackedDna::from(&dna);
for op in ops {
if let Some(nuc) = op {
packed.push(nuc);
dna.push(nuc);
} else {
assert_eq!(packed.pop(), dna.pop());
}
assert_eq!(packed, dna);
}
}
}
}