use std::fmt::Formatter;
use std::fmt::Result as FmtResult;
use lightmotif::abc::Dna;
use lightmotif::pwm::ScoringMatrix;
use crate::errors::Error;
use crate::seq::mismatches;
use crate::seq::reverse_complement;
use crate::seq::DisambiguationIterator;
#[derive(Debug, Clone)]
pub struct Primer {
template: String,
profile: ScoringMatrix<Dna>,
}
impl Primer {
pub fn new<S: Into<String>>(template: S) -> Result<Self, Error> {
let t = template.into();
let encoded = DisambiguationIterator::new(&t)?.map(|s| {
lightmotif::EncodedSequence::encode(s.as_bytes())
.expect("DisambiguationIterator only produces valid DNA strings")
});
let pssm = lightmotif::CountMatrix::from_sequences(encoded)
.expect("DesambiguationIterator only produces sequences of the same length")
.to_freq(0.1)
.to_scoring(None);
Ok(Self {
template: t,
profile: pssm,
})
}
#[inline]
pub fn len(&self) -> usize {
self.template.len()
}
#[inline]
pub fn template(&self) -> &str {
self.template.as_str()
}
#[inline]
pub fn profile(&self) -> &ScoringMatrix<Dna> {
&self.profile
}
#[inline]
pub fn mismatches(&self, seq: &str) -> usize {
assert_eq!(self.len(), seq.len());
mismatches(&self.template, seq)
}
#[inline]
pub fn reverse_complement(&self) -> Primer {
reverse_complement(&self.template)
.and_then(Self::new)
.expect("Primer.reverse_complement always produces a valid Primer")
}
}
#[cfg(feature = "serde")]
mod ser {
use super::*;
use serde::ser::Serializer;
use serde::Serialize;
impl Serialize for Primer {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(self.template.as_str())
}
}
}
#[cfg(feature = "serde")]
mod de {
use super::*;
use serde::de::Deserializer;
use serde::de::Error as DeError;
use serde::de::Unexpected;
use serde::de::Visitor;
use serde::Deserialize;
struct PrimerVisitor;
impl<'de> Visitor<'de> for PrimerVisitor {
type Value = Primer;
fn expecting(&self, formatter: &mut Formatter) -> FmtResult {
write!(formatter, "a string")
}
fn visit_str<E: DeError>(self, s: &str) -> Result<Self::Value, E> {
Primer::new(s).map_err(|_| DeError::invalid_value(Unexpected::Str(s), &self))
}
}
impl<'de> Deserialize<'de> for Primer {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_str(PrimerVisitor)
}
}
}