#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize, Deserialize)]
pub enum Modification {
Simple(SimpleModification),
CrossLink {
peptide: usize,
sequence_index: crate::SequencePosition,
linker: SimpleModification,
name: CrossLinkName,
side: CrossLinkSide,
},
Ambiguous {
group: String,
id: usize,
modification: SimpleModification,
localisation_score: Option<OrderedFloat<f64>>,
preferred: bool,
},
}
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
pub enum CrossLinkSide {
Symmetric(std::collections::BTreeSet<usize>),
Left(std::collections::BTreeSet<usize>),
Right(std::collections::BTreeSet<usize>),
}
impl PartialOrd for CrossLinkSide {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for CrossLinkSide {
fn cmp(&self, other: &Self) -> Ordering {
match (self, other) {
(Self::Symmetric(_), Self::Symmetric(_)) | (Self::Left(_), Self::Left(_)) => {
Ordering::Equal
}
(Self::Symmetric(_), _) => Ordering::Greater,
(_, Self::Symmetric(_)) => Ordering::Less,
(Self::Left(_), _) => Ordering::Greater,
(_, Self::Left(_)) => Ordering::Less,
(Self::Right(_), Self::Right(_)) => Ordering::Equal,
}
}
}
impl std::hash::Hash for CrossLinkSide {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
use itertools::Itertools;
let (i, r) = match self {
Self::Symmetric(r) => (0, r),
Self::Left(r) => (1, r),
Self::Right(r) => (2, r),
};
state.write_u8(i);
state.write(
&r.iter()
.sorted()
.flat_map(|r| r.to_ne_bytes())
.collect_vec(),
);
}
}
pub type SimpleModification = std::sync::Arc<SimpleModificationInner>;
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Serialize, Deserialize, Hash)]
pub enum SimpleModificationInner {
Mass(OrderedMass),
Formula(MolecularFormula),
Glycan(Vec<(MonoSaccharide, isize)>),
GlycanStructure(GlycanStructure),
Gno {
composition: GnoComposition,
id: ModificationId,
structure_score: Option<usize>,
subsumption_level: GnoSubsumption,
motif: Option<(String, String)>,
taxonomy: thin_vec::ThinVec<(String, usize)>,
glycomeatlas: thin_vec::ThinVec<(String, Vec<(String, String)>)>,
},
Database {
specificities: Vec<(Vec<PlacementRule>, Vec<NeutralLoss>, Vec<DiagnosticIon>)>,
formula: MolecularFormula,
id: ModificationId,
},
Linker {
specificities: Vec<LinkerSpecificity>,
formula: MolecularFormula,
id: ModificationId,
length: Option<OrderedFloat<f64>>,
},
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Serialize, Deserialize, Hash, Default)]
pub struct ModificationId {
pub ontology: Ontology,
pub name: String,
pub id: Option<usize>,
pub description: String,
pub synonyms: thin_vec::ThinVec<String>,
pub cross_ids: thin_vec::ThinVec<(String, String)>,
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Serialize, Deserialize, Hash)]
pub enum CrossLinkName {
Branch,
Name(String),
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Serialize, Deserialize, Hash)]
pub enum LinkerSpecificity {
Symmetric(
Vec<PlacementRule>,
Vec<(MolecularFormula, MolecularFormula)>,
Vec<DiagnosticIon>,
),
Asymmetric(
(Vec<PlacementRule>, Vec<PlacementRule>),
Vec<(MolecularFormula, MolecularFormula)>,
Vec<DiagnosticIon>,
),
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Serialize, Deserialize, Hash)]
pub enum GnoComposition {
Weight(OrderedMass),
Composition(Vec<(MonoSaccharide, isize)>),
Topology(GlycanStructure),
}
#[derive(
Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default, Hash, Serialize, Deserialize,
)]
pub enum GnoSubsumption {
#[default]
AverageWeight,
BaseComposition,
Composition,
Topology,
Saccharide,
}
impl std::fmt::Display for GnoSubsumption {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::AverageWeight => write!(f, "Average weight"),
Self::BaseComposition => write!(f, "Base composition (no isomeric information)"),
Self::Composition => write!(f, "Composition"),
Self::Topology => write!(f, "Topology (no linkage)"),
Self::Saccharide => write!(f, "Saccharide"),
}
}
}