use std::borrow::{Borrow, BorrowMut};
use std::fmt::{Debug, Display, Formatter};
use std::hash::Hash;
use std::ops::{Deref, DerefMut, Index, IndexMut};
use std::str::FromStr;
use ref_cast::{RefCastCustom, ref_cast_custom};
use crate::error::ParseSeqError;
use crate::iter::{Codons, Translated};
use crate::symbol::iter_symbols;
use crate::translation::{GeneticCode, Translation};
use crate::{DnaIterExt, DnaSliceExt, Nucleotide, Symbol};
#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, RefCastCustom)]
#[repr(transparent)]
pub struct Seq<T: ?Sized>(pub T);
impl<T: ?Sized> Seq<T> {
#[ref_cast_custom]
pub fn wrap(slice: &T) -> &Self;
#[ref_cast_custom]
pub fn wrap_mut(slice: &mut T) -> &mut Self;
pub fn reading_frames<'a, S: 'a>(&'a self) -> [&'a Seq<[<[S] as DnaSliceExt>::Nuc]>; 3]
where
T: AsRef<[S]>,
[S]: DnaSliceExt,
{
self.0.as_ref().reading_frames().map(Seq::wrap)
}
pub fn translated_by<'a, S: 'a, G>(
&'a self,
genetic_code: G,
) -> Translation<'a, <[S] as DnaSliceExt>::Nuc, G>
where
T: AsRef<[S]>,
[S]: DnaSliceExt,
G: GeneticCode,
{
self.0.as_ref().translated_by(genetic_code)
}
pub fn iter_translated_by<S, G>(
&self,
genetic_code: G,
) -> Translated<G, Codons<S, <&T as IntoIterator>::IntoIter>>
where
for<'a> &'a T: IntoIterator<Item = &'a S>,
S: Nucleotide,
G: GeneticCode,
{
self.0.into_iter().translated_by(genetic_code)
}
}
impl<T: ?Sized> Deref for Seq<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl<T: ?Sized> DerefMut for Seq<T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.0
}
}
impl<T, I> Index<I> for Seq<T>
where
T: Index<I, Output: SeqWrap + 'static>,
{
type Output = <T::Output as SeqWrap>::Wrapped;
fn index(&self, index: I) -> &Self::Output {
self.0.index(index).wrap_slice()
}
}
impl<T, I> IndexMut<I> for Seq<T>
where
T: IndexMut<I, Output: SeqWrap + 'static>,
{
fn index_mut(&mut self, index: I) -> &mut Self::Output {
self.0.index_mut(index).wrap_mut_slice()
}
}
impl<T: Borrow<[S]>, S> Borrow<Seq<[S]>> for Seq<T> {
fn borrow(&self) -> &Seq<[S]> {
Seq::wrap(self.0.borrow())
}
}
impl<T: BorrowMut<[S]>, S> BorrowMut<Seq<[S]>> for Seq<T> {
fn borrow_mut(&mut self) -> &mut Seq<[S]> {
Seq::wrap_mut(self.0.borrow_mut())
}
}
impl<S: Clone> ToOwned for Seq<[S]> {
type Owned = Seq<Vec<S>>;
fn to_owned(&self) -> Self::Owned {
Seq(self.0.to_owned())
}
}
impl<T: FromIterator<A>, A> FromIterator<A> for Seq<T> {
fn from_iter<U>(iter: U) -> Self
where
U: IntoIterator<Item = A>,
{
Self(T::from_iter(iter))
}
}
impl<T: IntoIterator> IntoIterator for Seq<T> {
type IntoIter = T::IntoIter;
type Item = T::Item;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<T: ?Sized, S> PartialEq<&str> for Seq<T>
where
for<'a> &'a T: IntoIterator<Item = &'a S>,
S: Symbol,
{
fn eq(&self, rhs: &&str) -> bool {
self == *rhs
}
}
impl<T: ?Sized, S> PartialEq<str> for Seq<T>
where
for<'a> &'a T: IntoIterator<Item = &'a S>,
S: Symbol,
{
fn eq(&self, rhs: &str) -> bool {
self.into_iter().copied().map(Ok).eq(iter_symbols(rhs))
}
}
impl<T: ?Sized> Display for Seq<T>
where
for<'a> &'a T: IntoIterator<Item: Display>,
{
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
Display::fmt(&crate::iter::Display::new(&self.0), f)
}
}
impl<T: ?Sized> Debug for Seq<T>
where
for<'a> &'a T: IntoIterator<Item: Display>,
{
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
f.debug_tuple("Seq")
.field(&crate::iter::Display::new(&self.0))
.finish()
}
}
impl<T, U> FromStr for Seq<T>
where
for<'a> &'a T: IntoIterator<Item = &'a U>,
T: FromIterator<U>,
U: Symbol,
{
type Err = ParseSeqError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
iter_symbols(s).collect::<Result<_, _>>().map(Self)
}
}
pub trait SeqWrap {
type Wrapped: ?Sized;
fn wrap_slice(&self) -> &Self::Wrapped;
fn wrap_mut_slice(&mut self) -> &mut Self::Wrapped;
}
impl<S> SeqWrap for [S] {
type Wrapped = Seq<Self>;
fn wrap_slice(&self) -> &Self::Wrapped {
Seq::wrap(self)
}
fn wrap_mut_slice(&mut self) -> &mut Self::Wrapped {
Seq::wrap_mut(self)
}
}
impl<T> SeqWrap for T {
type Wrapped = Self;
fn wrap_slice(&self) -> &Self::Wrapped {
self
}
fn wrap_mut_slice(&mut self) -> &mut Self::Wrapped {
self
}
}
#[cfg(feature = "serde")]
mod serde_impls {
use std::fmt::{Display, Formatter};
use std::marker::PhantomData;
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Visitor};
use super::{Seq, Symbol};
impl<T> Serialize for Seq<T>
where
Self: Display,
{
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(&self.to_string())
}
}
impl<'de, T, U> Deserialize<'de> for Seq<T>
where
for<'a> &'a T: IntoIterator<Item = &'a U>,
T: FromIterator<U>,
U: Symbol,
{
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
deserializer.deserialize_str(SeqVisitor(PhantomData))
}
}
struct SeqVisitor<T>(PhantomData<T>);
impl<T, U> Visitor<'_> for SeqVisitor<T>
where
for<'a> &'a T: IntoIterator<Item = &'a U>,
T: FromIterator<U>,
U: Symbol,
{
type Value = Seq<T>;
fn expecting(&self, f: &mut Formatter) -> std::fmt::Result {
write!(f, "a string of {}s", U::NAME)
}
fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
v.parse().map_err(E::custom)
}
}
}
#[cfg(all(test, feature = "serde"))]
mod serde_tests {
use crate::Dna;
#[test]
fn dna_roundtrip() {
let original_dna: Dna = "CATTAG".parse().unwrap();
let json = serde_json::to_string(&original_dna).unwrap();
assert_eq!(json, "\"CATTAG\"");
let deserialized_dna: Dna = serde_json::from_str(&json).unwrap();
assert_eq!(deserialized_dna, original_dna);
}
#[test]
fn invalid_dna() {
let err = serde_json::from_str::<Dna>("[]").unwrap_err();
assert!(err.to_string().contains("expected a string of nucleotides"));
let err = serde_json::from_str::<Dna>("\"CATXTAG\"").unwrap_err();
assert!(
err.to_string()
.contains("invalid nucleotide 'X' at position 3")
);
}
}
#[cfg(test)]
mod tests {
use std::collections::VecDeque;
use crate::{Dna, NCBI1, Nuc, Seq};
#[test]
fn sanity_check_that_seq_works_with_arrays() {
let mut dna = Nuc::seq(b"ACGT");
assert_eq!(dna, "ACGT");
let peptide = dna.translated_by(NCBI1).to_seq();
assert_eq!(peptide, "T");
dna[2] = Nuc::A;
assert_eq!(dna[1..], "CAT");
let owned: Dna = dna[2..].to_owned();
assert_eq!(owned, "AT");
}
#[test]
fn sanity_check_that_seq_works_with_vecs() {
let mut dna = Seq(Nuc::arr(b"ACGT").to_vec());
assert_eq!(dna, "ACGT");
let peptide = dna.translated_by(NCBI1).to_seq();
assert_eq!(peptide, "T");
dna[2] = Nuc::A;
assert_eq!(dna[1..], "CAT");
let owned: Dna = dna[2..].to_owned();
assert_eq!(owned, "AT");
}
#[test]
fn sanity_check_that_seq_works_with_slices() {
let dna = Seq::wrap(const { &Nuc::arr(b"ACGT") });
assert_eq!(dna, "ACGT");
let peptide = dna.translated_by(NCBI1).to_seq();
assert_eq!(peptide, "T");
assert_eq!(dna[1..], "CGT");
let owned: Dna = dna[2..].to_owned();
assert_eq!(owned, "GT");
}
#[test]
fn sanity_check_that_seq_works_with_vecdeques() {
type VdSeq<T> = Seq<VecDeque<T>>;
let mut dna = VdSeq::from_iter(Nuc::arr(b"ACGT"));
assert_eq!(dna, "ACGT");
let peptide: VdSeq<_> = dna.iter_translated_by(NCBI1).collect();
assert_eq!(peptide, "T");
dna[2] = Nuc::A;
assert_eq!(dna, "ACAT");
}
}