use crate::{
parse_json::{ParseJson, use_serde},
space::{Space, UsedSpace},
};
use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub enum SequencePosition {
NTerm,
Index(usize),
CTerm,
}
impl Space for SequencePosition {
fn space(&self) -> UsedSpace {
match self {
Self::Index(_) => UsedSpace {
stack: 16,
..Default::default()
},
_ => UsedSpace {
stack: 8,
padding: 8,
..Default::default()
},
}
}
}
impl std::ops::Add<u8> for SequencePosition {
type Output = Self;
fn add(self, rhs: u8) -> Self::Output {
match self {
Self::Index(i) => Self::Index(i.saturating_add(rhs as usize)),
n => n,
}
}
}
impl std::ops::Sub<u8> for SequencePosition {
type Output = Self;
fn sub(self, rhs: u8) -> Self::Output {
match self {
Self::Index(i) => Self::Index(i.saturating_sub(rhs as usize)),
n => n,
}
}
}
impl Default for SequencePosition {
fn default() -> Self {
Self::Index(0)
}
}
impl std::fmt::Display for SequencePosition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::NTerm => write!(f, "N-terminal"),
Self::Index(index) => write!(f, "{index}"),
Self::CTerm => write!(f, "C-terminal"),
}
}
}
impl SequencePosition {
#[must_use]
pub const fn reverse(self, peptide_length: usize) -> Self {
match self {
Self::NTerm => Self::CTerm,
Self::Index(i) => Self::Index(peptide_length - i),
Self::CTerm => Self::NTerm,
}
}
pub fn from_index(index: usize, peptide_length: usize) -> Self {
match index {
0 => Self::NTerm,
c if c == peptide_length + 1 => Self::CTerm,
i => {
if i <= peptide_length {
Self::Index(i - 1)
} else {
panic!(
"Index {index} it outside of range for a peptide of length {peptide_length}"
)
}
}
}
}
}
impl ParseJson for SequencePosition {
fn from_json_value(
value: serde_json::Value,
) -> Result<Self, context_error::BoxedError<'static, context_error::BasicKind>> {
use_serde(value)
}
}
#[derive(
Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Default, Debug, Serialize, Deserialize,
)]
pub struct PeptidePosition {
pub sequence_index: SequencePosition,
pub series_number: usize,
pub sequence_length: usize,
}
impl PeptidePosition {
pub const fn n(sequence_index: SequencePosition, length: usize) -> Self {
Self {
sequence_index,
series_number: match sequence_index {
SequencePosition::NTerm => 0,
SequencePosition::Index(i) => i + 1,
SequencePosition::CTerm => length,
},
sequence_length: length,
}
}
pub const fn c(sequence_index: SequencePosition, length: usize) -> Self {
Self {
sequence_index,
series_number: match sequence_index {
SequencePosition::NTerm => length,
SequencePosition::Index(i) => length.saturating_sub(i),
SequencePosition::CTerm => 0,
},
sequence_length: length,
}
}
pub fn is_n_terminal(&self) -> bool {
self.sequence_index == SequencePosition::NTerm
}
pub fn is_c_terminal(&self) -> bool {
self.sequence_index == SequencePosition::CTerm
}
#[must_use]
pub const fn flip_terminal(self) -> Self {
Self {
sequence_index: self.sequence_index,
series_number: self.sequence_length + 1 - self.series_number,
sequence_length: self.sequence_length,
}
}
}
#[allow(variant_size_differences)]
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
pub enum FlankingSequence {
#[default]
Unknown,
Terminal,
AminoAcid(crate::sequence::AminoAcid),
Sequence(Box<crate::sequence::Peptidoform<crate::sequence::SemiAmbiguous>>),
}
impl FlankingSequence {
pub const UNKNOWN: &Self = &Self::Unknown;
}