use std::cell::Cell;
use std::cmp::Ordering;
use std::fmt::Formatter;
use std::ops::{Deref, DerefMut};
use crate::symbol::iter_symbols;
use crate::{Amino, Seq, iter::display};
use super::ambipeptide::{PackedAmbiPeptide, PackedArrayAmbiPeptide};
use super::packable_array::{ArrayDefault, Sealed as ArrayDivide};
use super::{PackableArray, RefCmp, UnpackingIter};
#[derive(Clone, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct PackedPeptide(Vec<[u8; 2]>);
impl PackedPeptide {
#[must_use]
pub fn len(&self) -> usize {
match &*self.0 {
[] => 0,
bulk @ [.., tail] => {
3 * bulk.len() - (u16::from_be_bytes(*tail).trailing_zeros() / 5) as usize
}
}
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn push(&mut self, amino: Amino) {
assert_ne!(self.len(), isize::MAX as usize);
if let Some(last) = self.0.last_mut()
&& let val = u16::from_be_bytes(*last)
&& val.trailing_zeros() >= 5
{
let offset = val.trailing_zeros() / 5 * 5 - 5;
*last = (val | (amino.compress() << offset)).to_be_bytes();
} else {
self.0.push((amino.compress() << 10).to_be_bytes());
}
}
pub fn pop(&mut self) -> Option<Amino> {
let last = self.0.last_mut()?;
let val = u16::from_be_bytes(*last);
let offset = val.trailing_zeros() / 5 * 5;
if offset == 10 {
self.0.pop();
} else {
*last = (val & !(0b11111 << offset)).to_be_bytes();
}
Some(Amino::decompress(val >> offset))
}
#[must_use]
pub fn iter(&self) -> PackedPeptideIter<'_> {
self.into_iter()
}
#[must_use]
pub fn iter_mut(&mut self) -> PackedPeptideMutIter<'_> {
self.into_iter()
}
}
impl From<Seq<Vec<Amino>>> for PackedPeptide {
fn from(peptide: Seq<Vec<Amino>>) -> PackedPeptide {
peptide.0.into()
}
}
impl From<Vec<Amino>> for PackedPeptide {
fn from(peptide: Vec<Amino>) -> PackedPeptide {
(&peptide).into()
}
}
impl<T: AsRef<[Amino]> + ?Sized> From<&T> for PackedPeptide {
fn from(peptide: &T) -> PackedPeptide {
let peptide = peptide.as_ref();
let packed_len = peptide.len().div_ceil(3);
let mut packed = vec![[0, 0]; packed_len];
pack(&mut packed, peptide);
Self(packed)
}
}
impl From<PackedPeptide> for Seq<Vec<Amino>> {
fn from(packed_peptide: PackedPeptide) -> Seq<Vec<Amino>> {
Seq(packed_peptide.into())
}
}
impl From<&PackedPeptide> for Seq<Vec<Amino>> {
fn from(packed_peptide: &PackedPeptide) -> Seq<Vec<Amino>> {
Seq(packed_peptide.into())
}
}
impl From<PackedPeptide> for Vec<Amino> {
fn from(packed_peptide: PackedPeptide) -> Vec<Amino> {
(&packed_peptide).into()
}
}
impl From<&PackedPeptide> for Vec<Amino> {
fn from(packed_peptide: &PackedPeptide) -> Vec<Amino> {
let mut peptide = vec![Amino::default(); packed_peptide.len()];
unpack(&mut peptide, &packed_peptide.0);
peptide
}
}
impl<'a> IntoIterator for &'a PackedPeptide {
type Item = Amino;
type IntoIter = PackedPeptideIter<'a>;
fn into_iter(self) -> Self::IntoIter {
PackedPeptideIter(UnpackingIter::new(0..self.len(), &self.0))
}
}
impl<'a> IntoIterator for &'a mut PackedPeptide {
type Item = PackedAmino<'a>;
type IntoIter = PackedPeptideMutIter<'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();
PackedPeptideMutIter(UnpackingIter::new(0..len, backing))
}
}
impl IntoIterator for PackedPeptide {
type Item = Amino;
type IntoIter = PackedPeptideIntoIter;
fn into_iter(self) -> Self::IntoIter {
PackedPeptideIntoIter(UnpackingIter::new(0..self.len(), self.0))
}
}
impl<const N: usize> PartialEq<PackedArrayPeptide<N>> for PackedPeptide
where
[(); N]: PackableArray,
{
fn eq(&self, other: &PackedArrayPeptide<N>) -> bool {
self.0.as_flattened().eq(other.0.as_ref().as_flattened())
}
}
impl<const N: usize> PartialOrd<PackedArrayPeptide<N>> for PackedPeptide
where
[(); N]: PackableArray,
{
fn partial_cmp(&self, other: &PackedArrayPeptide<N>) -> Option<Ordering> {
self.0
.as_flattened()
.partial_cmp(other.0.as_ref().as_flattened())
}
}
impl PartialEq<PackedAmbiPeptide> for PackedPeptide {
fn eq(&self, other: &PackedAmbiPeptide) -> bool {
self.iter().eq(other.iter())
}
}
impl PartialOrd<PackedAmbiPeptide> for PackedPeptide {
fn partial_cmp(&self, other: &PackedAmbiPeptide) -> Option<Ordering> {
self.iter().partial_cmp(other.iter())
}
}
impl<const N: usize> PartialEq<PackedArrayAmbiPeptide<N>> for PackedPeptide {
fn eq(&self, other: &PackedArrayAmbiPeptide<N>) -> bool {
self.iter().eq(other.iter())
}
}
impl<const N: usize> PartialOrd<PackedArrayAmbiPeptide<N>> for PackedPeptide {
fn partial_cmp(&self, other: &PackedArrayAmbiPeptide<N>) -> Option<Ordering> {
self.iter().partial_cmp(other.iter())
}
}
impl<T: PartialEq<Amino>, const M: usize> PartialEq<[T; M]> for PackedPeptide {
fn eq(&self, other: &[T; M]) -> bool {
self.eq(&other.as_slice())
}
}
impl<T: PartialOrd<Amino>, const M: usize> PartialOrd<[T; M]> for PackedPeptide {
fn partial_cmp(&self, other: &[T; M]) -> Option<Ordering> {
self.partial_cmp(&other.as_slice())
}
}
impl<T: PartialEq<Amino>, const M: usize> PartialEq<&mut [T; M]> for PackedPeptide {
fn eq(&self, other: &&mut [T; M]) -> bool {
self.eq(&other.as_slice())
}
}
impl<T: PartialOrd<Amino>, const M: usize> PartialOrd<&mut [T; M]> for PackedPeptide {
fn partial_cmp(&self, other: &&mut [T; M]) -> Option<Ordering> {
self.partial_cmp(&other.as_slice())
}
}
impl<T: PartialEq<Amino>, const M: usize> PartialEq<&[T; M]> for PackedPeptide {
fn eq(&self, other: &&[T; M]) -> bool {
self.eq(&other.as_slice())
}
}
impl<T: PartialOrd<Amino>, const M: usize> PartialOrd<&[T; M]> for PackedPeptide {
fn partial_cmp(&self, other: &&[T; M]) -> Option<Ordering> {
self.partial_cmp(&other.as_slice())
}
}
impl<T: PartialEq<Amino>> PartialEq<Vec<T>> for PackedPeptide {
fn eq(&self, other: &Vec<T>) -> bool {
self.eq(&&**other)
}
}
impl<T: PartialOrd<Amino>> PartialOrd<Vec<T>> for PackedPeptide {
fn partial_cmp(&self, other: &Vec<T>) -> Option<Ordering> {
self.partial_cmp(&&**other)
}
}
impl<T: PartialEq<Amino>> PartialEq<&mut [T]> for PackedPeptide {
fn eq(&self, other: &&mut [T]) -> bool {
self.eq(&&**other)
}
}
impl<T: PartialOrd<Amino>> PartialOrd<&mut [T]> for PackedPeptide {
fn partial_cmp(&self, other: &&mut [T]) -> Option<Ordering> {
self.partial_cmp(&&**other)
}
}
impl<T: PartialEq<Amino>> PartialEq<&[T]> for PackedPeptide {
fn eq(&self, other: &&[T]) -> bool {
self.len() == other.len() && self.iter().map(RefCmp).eq(*other)
}
}
impl<T: PartialOrd<Amino>> PartialOrd<&[T]> for PackedPeptide {
fn partial_cmp(&self, other: &&[T]) -> Option<Ordering> {
self.iter().map(RefCmp).partial_cmp(*other)
}
}
impl PartialEq<&str> for PackedPeptide {
fn eq(&self, rhs: &&str) -> bool {
self == *rhs
}
}
impl PartialEq<str> for PackedPeptide {
fn eq(&self, rhs: &str) -> bool {
self.iter().map(Ok).eq(iter_symbols(rhs))
}
}
impl std::fmt::Display for PackedPeptide {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
self.iter().fmt(f)
}
}
impl std::fmt::Debug for PackedPeptide {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
f.debug_tuple("PackedPeptide")
.field(&display(self.iter()))
.finish()
}
}
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct PackedArrayPeptide<const N: usize>(PackedBuf<N>)
where
[(); N]: PackableArray;
type PackedBuf<const N: usize> = <[(); N] as ArrayDivide>::By3<[u8; 2]>;
impl<const N: usize> PackedArrayPeptide<N>
where
[(); N]: PackableArray,
{
#[must_use]
pub fn iter(&self) -> PackedPeptideIter<'_> {
self.into_iter()
}
#[must_use]
pub fn iter_mut(&mut self) -> PackedPeptideMutIter<'_> {
self.into_iter()
}
}
impl<const N: usize> Default for PackedArrayPeptide<N>
where
[(); N]: PackableArray,
{
fn default() -> Self {
Self(ArrayDefault::array_default())
}
}
impl<const N: usize> From<Seq<[Amino; N]>> for PackedArrayPeptide<N>
where
[(); N]: PackableArray,
{
fn from(peptide: Seq<[Amino; N]>) -> PackedArrayPeptide<N> {
peptide.0.into()
}
}
impl<const N: usize> From<&Seq<[Amino; N]>> for PackedArrayPeptide<N>
where
[(); N]: PackableArray,
{
fn from(peptide: &Seq<[Amino; N]>) -> PackedArrayPeptide<N> {
peptide.0.into()
}
}
impl<const N: usize> From<[Amino; N]> for PackedArrayPeptide<N>
where
[(); N]: PackableArray,
{
fn from(peptide: [Amino; N]) -> PackedArrayPeptide<N> {
(&peptide).into()
}
}
impl<const N: usize> From<&[Amino; N]> for PackedArrayPeptide<N>
where
[(); N]: PackableArray,
{
fn from(peptide: &[Amino; N]) -> PackedArrayPeptide<N> {
let mut this = Self(ArrayDefault::array_default());
pack(this.0.as_mut(), peptide);
this
}
}
impl<const N: usize> From<PackedArrayPeptide<N>> for Seq<[Amino; N]>
where
[(); N]: PackableArray,
{
fn from(packed_peptide: PackedArrayPeptide<N>) -> Seq<[Amino; N]> {
Seq(packed_peptide.into())
}
}
impl<const N: usize> From<&PackedArrayPeptide<N>> for Seq<[Amino; N]>
where
[(); N]: PackableArray,
{
fn from(packed_peptide: &PackedArrayPeptide<N>) -> Seq<[Amino; N]> {
Seq(packed_peptide.into())
}
}
impl<const N: usize> From<PackedArrayPeptide<N>> for [Amino; N]
where
[(); N]: PackableArray,
{
fn from(packed_peptide: PackedArrayPeptide<N>) -> [Amino; N] {
(&packed_peptide).into()
}
}
impl<const N: usize> From<&PackedArrayPeptide<N>> for [Amino; N]
where
[(); N]: PackableArray,
{
fn from(packed_peptide: &PackedArrayPeptide<N>) -> [Amino; N] {
let mut peptide = [Amino::default(); N];
unpack(&mut peptide, packed_peptide.0.as_ref());
peptide
}
}
impl<'a, const N: usize> IntoIterator for &'a PackedArrayPeptide<N>
where
[(); N]: PackableArray,
{
type Item = Amino;
type IntoIter = PackedPeptideIter<'a>;
fn into_iter(self) -> Self::IntoIter {
PackedPeptideIter(UnpackingIter::new(0..N, self.0.as_ref()))
}
}
impl<'a, const N: usize> IntoIterator for &'a mut PackedArrayPeptide<N>
where
[(); N]: PackableArray,
{
type Item = PackedAmino<'a>;
type IntoIter = PackedPeptideMutIter<'a>;
fn into_iter(self) -> Self::IntoIter {
let backing = Cell::from_mut(self.0.as_mut()).as_slice_of_cells();
PackedPeptideMutIter(UnpackingIter::new(0..N, backing))
}
}
impl<const N: usize> IntoIterator for PackedArrayPeptide<N>
where
[(); N]: PackableArray,
{
type Item = Amino;
type IntoIter = PackedArrayPeptideIntoIter<N>;
fn into_iter(self) -> Self::IntoIter {
PackedArrayPeptideIntoIter(UnpackingIter::new(0..N, self.0))
}
}
impl<const N: usize> PartialEq<PackedPeptide> for PackedArrayPeptide<N>
where
[(); N]: PackableArray,
{
fn eq(&self, other: &PackedPeptide) -> bool {
other == self
}
}
impl<const N: usize> PartialOrd<PackedPeptide> for PackedArrayPeptide<N>
where
[(); N]: PackableArray,
{
fn partial_cmp(&self, other: &PackedPeptide) -> Option<Ordering> {
other.partial_cmp(self).map(Ordering::reverse)
}
}
impl<const N: usize> PartialEq<PackedAmbiPeptide> for PackedArrayPeptide<N>
where
[(); N]: PackableArray,
{
fn eq(&self, other: &PackedAmbiPeptide) -> bool {
self.iter().eq(other.iter())
}
}
impl<const N: usize> PartialOrd<PackedAmbiPeptide> for PackedArrayPeptide<N>
where
[(); N]: PackableArray,
{
fn partial_cmp(&self, other: &PackedAmbiPeptide) -> Option<Ordering> {
self.iter().partial_cmp(other.iter())
}
}
impl<const N: usize> PartialEq<PackedArrayAmbiPeptide<N>> for PackedArrayPeptide<N>
where
[(); N]: PackableArray,
{
fn eq(&self, other: &PackedArrayAmbiPeptide<N>) -> bool {
self.iter().eq(other.iter())
}
}
impl<const N: usize> PartialOrd<PackedArrayAmbiPeptide<N>> for PackedArrayPeptide<N>
where
[(); N]: PackableArray,
{
fn partial_cmp(&self, other: &PackedArrayAmbiPeptide<N>) -> Option<Ordering> {
self.iter().partial_cmp(other.iter())
}
}
impl<T: PartialEq<Amino>, const N: usize, const M: usize> PartialEq<[T; M]>
for PackedArrayPeptide<N>
where
[(); N]: PackableArray,
{
fn eq(&self, other: &[T; M]) -> bool {
self.eq(&other.as_slice())
}
}
impl<T: PartialOrd<Amino>, const N: usize, const M: usize> PartialOrd<[T; M]>
for PackedArrayPeptide<N>
where
[(); N]: PackableArray,
{
fn partial_cmp(&self, other: &[T; M]) -> Option<Ordering> {
self.partial_cmp(&other.as_slice())
}
}
impl<T: PartialEq<Amino>, const N: usize, const M: usize> PartialEq<&mut [T; M]>
for PackedArrayPeptide<N>
where
[(); N]: PackableArray,
{
fn eq(&self, other: &&mut [T; M]) -> bool {
self.eq(&other.as_slice())
}
}
impl<T: PartialOrd<Amino>, const N: usize, const M: usize> PartialOrd<&mut [T; M]>
for PackedArrayPeptide<N>
where
[(); N]: PackableArray,
{
fn partial_cmp(&self, other: &&mut [T; M]) -> Option<Ordering> {
self.partial_cmp(&other.as_slice())
}
}
impl<T: PartialEq<Amino>, const N: usize, const M: usize> PartialEq<&[T; M]>
for PackedArrayPeptide<N>
where
[(); N]: PackableArray,
{
fn eq(&self, other: &&[T; M]) -> bool {
self.eq(&other.as_slice())
}
}
impl<T: PartialOrd<Amino>, const N: usize, const M: usize> PartialOrd<&[T; M]>
for PackedArrayPeptide<N>
where
[(); N]: PackableArray,
{
fn partial_cmp(&self, other: &&[T; M]) -> Option<Ordering> {
self.partial_cmp(&other.as_slice())
}
}
impl<T: PartialEq<Amino>, const N: usize> PartialEq<Vec<T>> for PackedArrayPeptide<N>
where
[(); N]: PackableArray,
{
fn eq(&self, other: &Vec<T>) -> bool {
self.eq(&&**other)
}
}
impl<T: PartialOrd<Amino>, const N: usize> PartialOrd<Vec<T>> for PackedArrayPeptide<N>
where
[(); N]: PackableArray,
{
fn partial_cmp(&self, other: &Vec<T>) -> Option<Ordering> {
self.partial_cmp(&&**other)
}
}
impl<T: PartialEq<Amino>, const N: usize> PartialEq<&mut [T]> for PackedArrayPeptide<N>
where
[(); N]: PackableArray,
{
fn eq(&self, other: &&mut [T]) -> bool {
self.eq(&&**other)
}
}
impl<T: PartialOrd<Amino>, const N: usize> PartialOrd<&mut [T]> for PackedArrayPeptide<N>
where
[(); N]: PackableArray,
{
fn partial_cmp(&self, other: &&mut [T]) -> Option<Ordering> {
self.partial_cmp(&&**other)
}
}
impl<T: PartialEq<Amino>, const N: usize> PartialEq<&[T]> for PackedArrayPeptide<N>
where
[(); N]: PackableArray,
{
fn eq(&self, other: &&[T]) -> bool {
N == other.len() && self.iter().map(RefCmp).eq(*other)
}
}
impl<T: PartialOrd<Amino>, const N: usize> PartialOrd<&[T]> for PackedArrayPeptide<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 PackedArrayPeptide<N>
where
[(); N]: PackableArray,
{
fn eq(&self, rhs: &&str) -> bool {
self == *rhs
}
}
impl<const N: usize> PartialEq<str> for PackedArrayPeptide<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 PackedArrayPeptide<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 PackedArrayPeptide<N>
where
[(); N]: PackableArray,
{
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
f.debug_tuple("PackedArrayPeptide")
.field(&display(self.iter()))
.finish()
}
}
fn pack(packed: &mut [[u8; 2]], peptide: &[Amino]) {
let (triplets, remainder) = peptide.as_chunks();
for (pair, &[a1, a2, a3]) in packed.iter_mut().zip(triplets) {
*pair = (a3.compress() | (a2.compress() << 5) | (a1.compress() << 10)).to_be_bytes();
}
match (packed.last_mut(), remainder) {
(_, []) => {}
(Some(pair), [a1]) => *pair = (a1.compress() << 10).to_be_bytes(),
(Some(pair), [a1, a2]) => {
*pair = ((a1.compress() << 10) | (a2.compress() << 5)).to_be_bytes();
}
_ => panic!(),
}
}
fn unpack(peptide: &mut [Amino], packed: &[[u8; 2]]) {
let (triplets, remainder) = peptide.as_chunks_mut();
for ([a1, a2, a3], &pair) in triplets.iter_mut().zip(packed) {
let val = u16::from_be_bytes(pair);
*a1 = Amino::decompress(val >> 10);
*a2 = Amino::decompress(val >> 5);
*a3 = Amino::decompress(val);
}
match (remainder, packed.last()) {
([], _) => {}
([a1], Some(pair)) => *a1 = Amino::decompress(u16::from_be_bytes(*pair) >> 10),
([a1, a2], Some(pair)) => {
let val = u16::from_be_bytes(*pair);
*a1 = Amino::decompress(val >> 10);
*a2 = Amino::decompress(val >> 5);
}
_ => panic!(),
}
}
#[derive(Clone)]
pub struct PackedPeptideIntoIter(UnpackingIter<5, 15, std::vec::IntoIter<[u8; 2]>>);
impl PackedPeptideIntoIter {
fn as_ref(&self) -> PackedPeptideIter<'_> {
PackedPeptideIter(self.0.as_ref())
}
}
impl Iterator for PackedPeptideIntoIter {
type Item = Amino;
fn next(&mut self) -> Option<Amino> {
self.0
.next()
.map(|(shift, bytes)| Amino::decompress(u16::from_be_bytes(bytes) >> shift))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl DoubleEndedIterator for PackedPeptideIntoIter {
fn next_back(&mut self) -> Option<Amino> {
self.0
.next_back()
.map(|(shift, bytes)| Amino::decompress(u16::from_be_bytes(bytes) >> shift))
}
}
impl ExactSizeIterator for PackedPeptideIntoIter {
fn len(&self) -> usize {
self.0.len()
}
}
impl std::fmt::Display for PackedPeptideIntoIter {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
self.as_ref().fmt(f)
}
}
impl std::fmt::Debug for PackedPeptideIntoIter {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
f.debug_tuple("PackedPeptideIntoIter")
.field(&display(self.as_ref()))
.finish()
}
}
#[derive(Clone)]
pub struct PackedArrayPeptideIntoIter<const N: usize>(
UnpackingIter<5, 15, <PackedBuf<N> as IntoIterator>::IntoIter>,
)
where
[(); N]: PackableArray;
impl<const N: usize> PackedArrayPeptideIntoIter<N>
where
[(); N]: PackableArray,
{
fn as_ref(&self) -> PackedPeptideIter<'_> {
PackedPeptideIter(self.0.as_ref())
}
}
impl<const N: usize> Iterator for PackedArrayPeptideIntoIter<N>
where
[(); N]: PackableArray,
{
type Item = Amino;
fn next(&mut self) -> Option<Amino> {
self.0
.next()
.map(|(shift, bytes)| Amino::decompress(u16::from_be_bytes(bytes) >> shift))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<const N: usize> DoubleEndedIterator for PackedArrayPeptideIntoIter<N>
where
[(); N]: PackableArray,
{
fn next_back(&mut self) -> Option<Amino> {
self.0
.next_back()
.map(|(shift, bytes)| Amino::decompress(u16::from_be_bytes(bytes) >> shift))
}
}
impl<const N: usize> ExactSizeIterator for PackedArrayPeptideIntoIter<N>
where
[(); N]: PackableArray,
{
fn len(&self) -> usize {
self.0.len()
}
}
impl<const N: usize> std::fmt::Display for PackedArrayPeptideIntoIter<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 PackedArrayPeptideIntoIter<N>
where
[(); N]: PackableArray,
{
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
f.debug_tuple("PackedArrayPeptideIntoIter")
.field(&display(self.as_ref()))
.finish()
}
}
#[derive(Clone)]
pub struct PackedPeptideIter<'a>(UnpackingIter<5, 15, std::slice::Iter<'a, [u8; 2]>>);
impl Iterator for PackedPeptideIter<'_> {
type Item = Amino;
fn next(&mut self) -> Option<Amino> {
self.0
.next()
.map(|(shift, bytes)| Amino::decompress(u16::from_be_bytes(*bytes) >> shift))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl DoubleEndedIterator for PackedPeptideIter<'_> {
fn next_back(&mut self) -> Option<Amino> {
self.0
.next_back()
.map(|(shift, bytes)| Amino::decompress(u16::from_be_bytes(*bytes) >> shift))
}
}
impl ExactSizeIterator for PackedPeptideIter<'_> {
fn len(&self) -> usize {
self.0.len()
}
}
impl std::fmt::Display for PackedPeptideIter<'_> {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
display(self.clone()).fmt(f)
}
}
impl std::fmt::Debug for PackedPeptideIter<'_> {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
f.debug_tuple("PackedPeptideIter")
.field(&display(self.clone()))
.finish()
}
}
pub struct PackedPeptideMutIter<'a>(UnpackingIter<5, 15, std::slice::Iter<'a, Cell<[u8; 2]>>>);
impl PackedPeptideMutIter<'_> {
fn read_values(&self) -> impl Iterator<Item = Amino> + Clone {
self.0
.clone()
.map(|(shift, bytes)| Amino::decompress(u16::from_be_bytes(bytes.get()) >> shift))
}
}
impl<'a> Iterator for PackedPeptideMutIter<'a> {
type Item = PackedAmino<'a>;
fn next(&mut self) -> Option<PackedAmino<'a>> {
self.0.next().map(PackedAmino::new)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<'a> DoubleEndedIterator for PackedPeptideMutIter<'a> {
fn next_back(&mut self) -> Option<PackedAmino<'a>> {
self.0.next_back().map(PackedAmino::new)
}
}
impl ExactSizeIterator for PackedPeptideMutIter<'_> {
fn len(&self) -> usize {
self.0.len()
}
}
impl std::fmt::Display for PackedPeptideMutIter<'_> {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
display(self.read_values()).fmt(f)
}
}
impl std::fmt::Debug for PackedPeptideMutIter<'_> {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
f.debug_tuple("PackedPeptideMutIter")
.field(&display(self.read_values()))
.finish()
}
}
pub struct PackedAmino<'a> {
packed: &'a Cell<[u8; 2]>,
shift: u8,
unpacked: Amino,
}
impl<'a> PackedAmino<'a> {
fn new((shift, packed): (u8, &'a Cell<[u8; 2]>)) -> Self {
let unpacked = Amino::decompress(u16::from_be_bytes(packed.get()) >> shift);
Self {
packed,
shift,
unpacked,
}
}
}
impl Drop for PackedAmino<'_> {
fn drop(&mut self) {
self.packed.update(|bytes| {
let updated = u16::from_be_bytes(bytes) & !(0b11111 << self.shift)
| self.unpacked.compress() << self.shift;
updated.to_be_bytes()
});
}
}
impl Deref for PackedAmino<'_> {
type Target = Amino;
fn deref(&self) -> &Amino {
&self.unpacked
}
}
impl DerefMut for PackedAmino<'_> {
fn deref_mut(&mut self) -> &mut Amino {
&mut self.unpacked
}
}
impl AsRef<Amino> for PackedAmino<'_> {
fn as_ref(&self) -> &Amino {
self
}
}
impl AsMut<Amino> for PackedAmino<'_> {
fn as_mut(&mut self) -> &mut Amino {
self
}
}
impl std::fmt::Display for PackedAmino<'_> {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
self.unpacked.fmt(f)
}
}
impl std::fmt::Debug for PackedAmino<'_> {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
f.debug_tuple("PackedAmino").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_peptide, any_peptide};
use super::*;
#[cfg_attr(miri, ignore = "slow in miri; shouldn't touch unsafe code anyway")]
#[test]
fn all_short_roundtrips() {
assert_both_roundtrips(&[] as &[Amino; 0]);
for a1 in Amino::ALL {
assert_both_roundtrips(&[a1]);
for a2 in Amino::ALL {
assert_both_roundtrips(&[a1, a2]);
for a3 in Amino::ALL {
assert_both_roundtrips(&[a1, a2, a3]);
for a4 in Amino::ALL {
assert_both_roundtrips(&[a1, a2, a3, a4]);
}
}
}
}
}
#[test]
fn smoke_test_iters() {
let peptide = Amino::seq(b"PEPTIDE")[..].pack();
assert_eq!(Seq(Vec::from_iter(&peptide)), "PEPTIDE");
assert_eq!(Seq(Vec::from_iter(peptide)), "PEPTIDE");
let peptide = Amino::seq(b"PEPTIDE").pack();
assert_eq!(Seq(Vec::from_iter(&peptide)), "PEPTIDE");
assert_eq!(Seq(Vec::from_iter(peptide)), "PEPTIDE");
}
#[test]
fn packed_peptide_eq_str() {
let dna = Amino::seq(b"PEPTIDE")[..].pack();
assert_eq!(dna, "PEPTIDE");
let dna = Amino::seq(b"PEPTIDE").pack();
assert_eq!(dna, "PEPTIDE");
}
#[test]
fn display() {
let peptide = Amino::seq(b"PEPTIDE")[..].pack();
assert_eq!(peptide.to_string(), "PEPTIDE");
assert_eq!(peptide.iter().to_string(), "PEPTIDE");
assert_eq!(peptide.into_iter().to_string(), "PEPTIDE");
let peptide = Amino::seq(b"PEPTIDE").pack();
assert_eq!(peptide.to_string(), "PEPTIDE");
assert_eq!(peptide.iter().to_string(), "PEPTIDE");
assert_eq!(peptide.into_iter().to_string(), "PEPTIDE");
}
proptest! {
#[cfg_attr(miri, ignore = "slow in miri; shouldn't touch unsafe code anyway")]
#[test]
fn packed_peptide_roundtrip(
peptide in any_peptide(5..25) ) {
assert_roundtrip(&*peptide);
}
#[cfg_attr(miri, ignore = "slow in miri; shouldn't touch unsafe code anyway")]
#[test]
fn packed_array_peptide5_roundtrip(
peptide in any::<[Amino; 5]>()
) {
assert_roundtrip(&peptide);
}
#[cfg_attr(miri, ignore = "slow in miri; shouldn't touch unsafe code anyway")]
#[test]
fn packed_array_peptide6_roundtrip(
peptide in any::<[Amino; 6]>()
) {
assert_roundtrip(&peptide);
}
#[cfg_attr(miri, ignore = "slow in miri; shouldn't touch unsafe code anyway")]
#[test]
fn packed_array_peptide7_roundtrip(
peptide in any::<[Amino; 7]>()
) {
assert_roundtrip(&peptide);
}
#[cfg_attr(miri, ignore = "slow in miri; shouldn't touch unsafe code anyway")]
#[test]
fn packed_peptide_lexical_ordering(
peptide1 in any_peptide(0..50),
peptide2 in any_peptide(0..50),
) {
let packed1 = PackedPeptide::from(peptide1.as_slice());
let packed2 = PackedPeptide::from(peptide2.as_slice());
assert_eq!(packed1.0.cmp(&packed2.0), peptide1.cmp(&peptide2));
}
#[cfg_attr(miri, ignore = "slow in miri; shouldn't touch unsafe code anyway")]
#[test]
fn packed_peptide_length(
peptide in any_peptide(0..50)
) {
let packed = PackedPeptide::from(&peptide);
assert_eq!(packed.len(), peptide.len());
assert_eq!(packed.is_empty(), peptide.is_empty());
}
#[cfg_attr(miri, ignore = "slow in miri; shouldn't touch unsafe code anyway")]
#[test]
fn packed_peptide_ord_vs_slice(
peptide1 in any_peptide(0..50),
peptide2 in any_peptide(0..50),
) {
let packed1 = PackedPeptide::from(&peptide1);
assert_eq!(packed1.partial_cmp(&peptide2), peptide1.partial_cmp(&peptide2));
assert_eq!(packed1.eq(&peptide2), peptide1.eq(&peptide2));
}
#[cfg_attr(miri, ignore = "slow in miri; shouldn't touch unsafe code anyway")]
#[test]
fn packed_peptide_ord_vs_ambi_slice(
peptide1 in any_peptide(0..50),
ambi_peptide2 in any_ambi_peptide(0..50),
) {
let packed1 = PackedPeptide::from(&peptide1);
assert_eq!(packed1.partial_cmp(&ambi_peptide2), peptide1.iter().partial_cmp(&ambi_peptide2));
assert_eq!(packed1.eq(&ambi_peptide2), peptide1.eq(&ambi_peptide2));
}
#[cfg_attr(miri, ignore = "slow in miri; shouldn't touch unsafe code anyway")]
#[test]
fn packed_peptide5_ord(
peptide1 in any::<[Amino; 5]>(),
peptide2 in any_peptide(0..10),
) {
let packed1 = PackedArrayPeptide::from(&peptide1);
assert_eq!(packed1.partial_cmp(&peptide2), peptide1.as_slice().partial_cmp(&peptide2));
assert_eq!(packed1.eq(&peptide2), peptide1.as_slice().eq(&peptide2));
}
#[cfg_attr(miri, ignore = "slow in miri; shouldn't touch unsafe code anyway")]
#[test]
fn push_and_pop(
mut peptide in any_peptide(0..25),
ops in proptest::collection::vec(any::<Option<Amino>>(), 0..50),
) {
let mut packed = PackedPeptide::from(&peptide);
for op in ops {
if let Some(amino) = op {
packed.push(amino);
peptide.push(amino);
} else {
assert_eq!(packed.pop(), peptide.pop());
}
assert_eq!(packed, peptide);
}
}
}
}