use crate::sequence::HasPeptidoformImpl;
pub trait AnnotatedPeptide: HasPeptidoformImpl {
fn regions(&self) -> &[(Region, usize)];
fn annotations(&self) -> &[(Annotation, usize)];
fn get_region(&self, index: usize) -> Option<(&Region, bool)> {
let regions = self.regions();
let mut left = index;
let mut regions_index = 0;
let mut next = ®ions[regions_index];
while left > next.1 {
left -= next.1;
regions_index += 1;
if regions_index == regions.len() {
return None;
}
next = ®ions[regions_index];
}
Some((&next.0, left == 1))
}
fn get_annotations(&self, index: usize) -> impl Iterator<Item = &Annotation> + '_ {
self.annotations()
.iter()
.filter(move |a| a.1 == index)
.map(|a| &a.0)
}
}
use bincode::{Decode, Encode};
use itertools::Itertools;
use serde::{Deserialize, Serialize};
#[expect(missing_docs)]
#[derive(Clone, Debug, Decode, Deserialize, Encode, Eq, Hash, PartialEq, Serialize)]
pub enum Region {
Framework(usize),
ComplementarityDetermining(usize),
Hinge(Option<usize>),
ConstantHeavy(usize),
ConstantLight,
SecratoryTail,
MembraneTail(Option<usize>),
Other(String),
Joined(Vec<Region>),
None,
}
#[derive(Clone, Debug, Decode, Deserialize, Encode, Eq, Hash, PartialEq, Serialize)]
pub enum Annotation {
Conserved,
NGlycan,
Other(String),
}
impl std::fmt::Display for Region {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Framework(n) => write!(f, "FR{n}"),
Self::ComplementarityDetermining(n) => write!(f, "CDR{n}"),
Self::Hinge(n) => write!(f, "H{}", n.map_or(String::new(), |n| n.to_string())),
Self::ConstantHeavy(n) => write!(f, "CH{n}"),
Self::ConstantLight => write!(f, "CL"),
Self::SecratoryTail => write!(f, "CHS"),
Self::MembraneTail(n) => write!(f, "M{}", n.map_or(String::new(), |n| n.to_string())),
Self::Other(o) => write!(f, "{o}"),
Self::Joined(o) => write!(f, "{}", o.iter().join("-")),
Self::None => Ok(()),
}
}
}
impl std::str::FromStr for Region {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
"" => Self::None,
"CL" => Self::ConstantLight,
"CHS" => Self::SecratoryTail,
"H" => Self::Hinge(None),
"M" => Self::MembraneTail(None),
cdr if cdr.starts_with("CDR") => cdr[3..].parse::<usize>().map_or_else(
|_| Self::Other(cdr.to_string()),
Self::ComplementarityDetermining,
),
fr if fr.starts_with("FR") => fr[2..]
.parse::<usize>()
.map_or_else(|_| Self::Other(fr.to_string()), Self::Framework),
ch if ch.starts_with("CH") => ch[2..]
.parse::<usize>()
.map_or_else(|_| Self::Other(ch.to_string()), Self::ConstantHeavy),
h if h.starts_with('H') => h[1..]
.parse::<usize>()
.map_or_else(|_| Self::Other(h.to_string()), |c| Self::Hinge(Some(c))),
m if m.starts_with('M') => m[1..].parse::<usize>().map_or_else(
|_| Self::Other(m.to_string()),
|c| Self::MembraneTail(Some(c)),
),
o => Self::Other(o.to_string()),
})
}
}
impl std::str::FromStr for Annotation {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
"C" | "Conserved" => Self::Conserved,
"N" | "NGlycan" => Self::NGlycan,
o => Self::Other(o.to_string()),
})
}
}
impl std::fmt::Display for Annotation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Conserved => write!(f, "Conserved"),
Self::NGlycan => write!(f, "NGlycan"),
Self::Other(o) => write!(f, "{o}"),
}
}
}