use std::{borrow::Cow, marker::PhantomData, ops::Range};
#[cfg(feature = "mzannotate")]
use mzannotate::prelude::AnnotatedSpectrum;
#[cfg(not(feature = "mzannotate"))]
use serde::{Deserialize, Serialize};
use crate::*;
use mzcore::{
sequence::{
AtLeast, CompoundPeptidoformIon, FlankingSequence, HasPeptidoformImpl, Linear, Linked,
Peptidoform, SemiAmbiguous, SimpleLinear, UnAmbiguous,
},
system::{Mass, MassOverCharge, Ratio, Time, isize::Charge},
};
#[cfg_attr(not(feature = "mzannotate"), derive(Serialize, Deserialize))]
#[derive(Clone, Debug)]
pub struct IdentifiedPeptidoform<Complexity, PeptidoformAvailability> {
pub score: Option<f64>,
pub local_confidence: Option<Vec<f64>>,
pub data: IdentifiedPeptidoformData,
pub(super) complexity_marker: PhantomData<Complexity>,
pub(super) peptidoform_availability_marker: PhantomData<PeptidoformAvailability>,
}
#[cfg_attr(not(feature = "mzannotate"), derive(Serialize, Deserialize))]
#[derive(Clone, Debug)]
#[expect(clippy::upper_case_acronyms)]
pub enum IdentifiedPeptidoformData {
BasicCSV(BasicCSVData),
DeepNovoFamily(DeepNovoFamilyData),
Fasta(FastaData),
InstaNovo(InstaNovoData),
MaxQuant(MaxQuantData),
MetaMorpheus(MetaMorpheusData),
MSFragger(MSFraggerData),
MZTab(MZTabData),
NovoB(NovoBData),
Novor(NovorData),
Opair(OpairData),
Peaks(PeaksData),
PepNet(PepNetData),
PiHelixNovo(PiHelixNovoData),
PiPrimeNovo(PiPrimeNovoData),
PLGS(PLGSData),
PLink(PLinkData),
PowerNovo(PowerNovoData),
Proteoscape(ProteoscapeData),
PUniFind(PUniFindData),
Sage(SageData),
SpectrumSequenceList(SpectrumSequenceListData),
#[cfg(feature = "mzannotate")]
AnnotatedSpectrum(AnnotatedSpectrum),
}
impl<PeptidoformAvailability> IdentifiedPeptidoform<Linear, PeptidoformAvailability> {
fn inner_peptidoform(&self) -> Option<&Peptidoform<Linear>> {
match &self.data {
IdentifiedPeptidoformData::Novor(NovorData { peptide, .. })
| IdentifiedPeptidoformData::InstaNovo(InstaNovoData { peptide, .. })
| IdentifiedPeptidoformData::Opair(OpairData { peptide, .. })
| IdentifiedPeptidoformData::PiHelixNovo(PiHelixNovoData { peptide, .. })
| IdentifiedPeptidoformData::PepNet(PepNetData { peptide, .. })
| IdentifiedPeptidoformData::PowerNovo(PowerNovoData { peptide, .. })
| IdentifiedPeptidoformData::PUniFind(PUniFindData {
peptidoform: peptide,
..
})
| IdentifiedPeptidoformData::Proteoscape(ProteoscapeData {
peptide: (_, peptide, _),
..
})
| IdentifiedPeptidoformData::Sage(SageData { peptide, .. }) => Some(peptide.as_ref()),
IdentifiedPeptidoformData::MSFragger(MSFraggerData { peptide, .. })
| IdentifiedPeptidoformData::PLGS(PLGSData { peptide, .. }) => Some(peptide.as_ref()),
IdentifiedPeptidoformData::Peaks(PeaksData { peptide, .. }) => {
if peptide.1.len() == 1 {
Some(peptide.1[0].as_ref())
} else {
None
}
}
IdentifiedPeptidoformData::SpectrumSequenceList(SpectrumSequenceListData {
peptide,
..
})
| IdentifiedPeptidoformData::PiPrimeNovo(PiPrimeNovoData { peptide, .. })
| IdentifiedPeptidoformData::DeepNovoFamily(DeepNovoFamilyData { peptide, .. }) => {
peptide.as_ref().map(AsRef::as_ref)
}
IdentifiedPeptidoformData::MZTab(MZTabData { peptidoform, .. })
| IdentifiedPeptidoformData::MaxQuant(MaxQuantData {
peptide: peptidoform,
..
}) => peptidoform.as_ref().map(AsRef::as_ref),
IdentifiedPeptidoformData::Fasta(f) => Some(f.peptide().as_ref()),
IdentifiedPeptidoformData::NovoB(NovoBData {
score_forward,
score_reverse,
peptide_forward,
peptide_reverse,
..
}) => if score_forward >= score_reverse {
peptide_forward.as_ref()
} else {
peptide_reverse.as_ref()
}
.map(AsRef::as_ref),
IdentifiedPeptidoformData::MetaMorpheus(MetaMorpheusData { peptide, .. })
| IdentifiedPeptidoformData::BasicCSV(BasicCSVData {
sequence: peptide, ..
}) => peptide
.singular_peptidoform_ref()
.and_then(|p| p.as_linear()),
IdentifiedPeptidoformData::PLink(PLinkData { peptidoform, .. }) => {
peptidoform.singular_ref().and_then(|p| p.as_linear())
}
#[cfg(feature = "mzannotate")]
IdentifiedPeptidoformData::AnnotatedSpectrum(spectrum) => {
use itertools::Itertools;
use mzannotate::mzspeclib::AnalyteTarget;
let ion = spectrum
.analytes
.iter()
.filter_map(|a| match &a.target {
AnalyteTarget::PeptidoformIon(pep) => Some(pep),
_ => None,
})
.exactly_one()
.ok()?;
ion.singular_ref().and_then(|p| p.as_linear())
}
}
}
}
impl<PeptidoformAvailability> IdentifiedPeptidoform<SimpleLinear, PeptidoformAvailability> {
fn inner_peptidoform(&self) -> Option<&Peptidoform<SimpleLinear>> {
match &self.data {
IdentifiedPeptidoformData::Novor(NovorData { peptide, .. })
| IdentifiedPeptidoformData::InstaNovo(InstaNovoData { peptide, .. })
| IdentifiedPeptidoformData::PiHelixNovo(PiHelixNovoData { peptide, .. })
| IdentifiedPeptidoformData::Opair(OpairData { peptide, .. })
| IdentifiedPeptidoformData::PepNet(PepNetData { peptide, .. })
| IdentifiedPeptidoformData::PowerNovo(PowerNovoData { peptide, .. })
| IdentifiedPeptidoformData::PUniFind(PUniFindData {
peptidoform: peptide,
..
})
| IdentifiedPeptidoformData::Proteoscape(ProteoscapeData {
peptide: (_, peptide, _),
..
})
| IdentifiedPeptidoformData::Sage(SageData { peptide, .. }) => Some(peptide.as_ref()),
IdentifiedPeptidoformData::MSFragger(MSFraggerData { peptide, .. })
| IdentifiedPeptidoformData::PLGS(PLGSData { peptide, .. }) => Some(peptide),
IdentifiedPeptidoformData::Peaks(PeaksData { peptide, .. }) => {
if peptide.1.len() == 1 {
Some(peptide.1[0].as_ref())
} else {
None
}
}
IdentifiedPeptidoformData::SpectrumSequenceList(SpectrumSequenceListData {
peptide,
..
})
| IdentifiedPeptidoformData::PiPrimeNovo(PiPrimeNovoData { peptide, .. })
| IdentifiedPeptidoformData::DeepNovoFamily(DeepNovoFamilyData { peptide, .. }) => {
peptide.as_ref().map(AsRef::as_ref)
}
IdentifiedPeptidoformData::MZTab(MZTabData { peptidoform, .. })
| IdentifiedPeptidoformData::MaxQuant(MaxQuantData {
peptide: peptidoform,
..
}) => peptidoform.as_ref(),
IdentifiedPeptidoformData::Fasta(f) => Some(f.peptide().as_ref()),
IdentifiedPeptidoformData::NovoB(NovoBData {
score_forward,
score_reverse,
peptide_forward,
peptide_reverse,
..
}) => if score_forward >= score_reverse {
peptide_forward.as_ref()
} else {
peptide_reverse.as_ref()
}
.map(AsRef::as_ref),
IdentifiedPeptidoformData::MetaMorpheus(MetaMorpheusData { peptide, .. })
| IdentifiedPeptidoformData::BasicCSV(BasicCSVData {
sequence: peptide, ..
}) => peptide
.singular_peptidoform_ref()
.and_then(|p| p.as_simple_linear()),
IdentifiedPeptidoformData::PLink(PLinkData { peptidoform, .. }) => peptidoform
.singular_ref()
.and_then(|p| p.as_simple_linear()),
#[cfg(feature = "mzannotate")]
IdentifiedPeptidoformData::AnnotatedSpectrum(spectrum) => {
use itertools::Itertools;
use mzannotate::mzspeclib::AnalyteTarget;
let ion = spectrum
.analytes
.iter()
.filter_map(|a| match &a.target {
AnalyteTarget::PeptidoformIon(pep) => Some(pep),
_ => None,
})
.exactly_one()
.ok()?;
ion.singular_ref().and_then(|p| p.as_simple_linear())
}
}
}
}
impl<PeptidoformAvailability> IdentifiedPeptidoform<SemiAmbiguous, PeptidoformAvailability> {
fn inner_peptidoform(&self) -> Option<&Peptidoform<SemiAmbiguous>> {
match &self.data {
IdentifiedPeptidoformData::Novor(NovorData { peptide, .. })
| IdentifiedPeptidoformData::InstaNovo(InstaNovoData { peptide, .. })
| IdentifiedPeptidoformData::Opair(OpairData { peptide, .. })
| IdentifiedPeptidoformData::PiHelixNovo(PiHelixNovoData { peptide, .. })
| IdentifiedPeptidoformData::PepNet(PepNetData { peptide, .. })
| IdentifiedPeptidoformData::PowerNovo(PowerNovoData { peptide, .. })
| IdentifiedPeptidoformData::PUniFind(PUniFindData {
peptidoform: peptide,
..
})
| IdentifiedPeptidoformData::Proteoscape(ProteoscapeData {
peptide: (_, peptide, _),
..
})
| IdentifiedPeptidoformData::Sage(SageData { peptide, .. }) => Some(peptide),
IdentifiedPeptidoformData::Peaks(PeaksData { peptide, .. }) => {
if peptide.1.len() == 1 {
Some(&peptide.1[0])
} else {
None
}
}
IdentifiedPeptidoformData::SpectrumSequenceList(SpectrumSequenceListData {
peptide,
..
})
| IdentifiedPeptidoformData::PiPrimeNovo(PiPrimeNovoData { peptide, .. })
| IdentifiedPeptidoformData::DeepNovoFamily(DeepNovoFamilyData { peptide, .. }) => {
peptide.as_ref()
}
IdentifiedPeptidoformData::MZTab(MZTabData { peptidoform, .. })
| IdentifiedPeptidoformData::MaxQuant(MaxQuantData {
peptide: peptidoform,
..
}) => peptidoform.as_ref().and_then(|p| p.as_semi_ambiguous()),
IdentifiedPeptidoformData::Fasta(f) => Some(f.peptide()),
IdentifiedPeptidoformData::NovoB(NovoBData {
score_forward,
score_reverse,
peptide_forward,
peptide_reverse,
..
}) => {
if score_forward >= score_reverse {
peptide_forward.as_ref()
} else {
peptide_reverse.as_ref()
}
}
IdentifiedPeptidoformData::MSFragger(MSFraggerData { peptide, .. })
| IdentifiedPeptidoformData::PLGS(PLGSData { peptide, .. }) => {
peptide.as_semi_ambiguous()
}
IdentifiedPeptidoformData::MetaMorpheus(MetaMorpheusData { peptide, .. })
| IdentifiedPeptidoformData::BasicCSV(BasicCSVData {
sequence: peptide, ..
}) => peptide
.singular_peptidoform_ref()
.and_then(|p| p.as_semi_ambiguous()),
IdentifiedPeptidoformData::PLink(PLinkData { peptidoform, .. }) => peptidoform
.singular_ref()
.and_then(|p| p.as_semi_ambiguous()),
#[cfg(feature = "mzannotate")]
IdentifiedPeptidoformData::AnnotatedSpectrum(spectrum) => {
use itertools::Itertools;
let ion = spectrum
.analytes
.iter()
.filter_map(|a| match &a.target {
mzannotate::mzspeclib::AnalyteTarget::PeptidoformIon(pep) => Some(pep),
_ => None,
})
.exactly_one()
.ok()?;
ion.singular_ref().and_then(|p| p.as_semi_ambiguous())
}
}
}
}
impl<PeptidoformAvailability> IdentifiedPeptidoform<UnAmbiguous, PeptidoformAvailability> {
fn inner_peptidoform(&self) -> Option<&Peptidoform<UnAmbiguous>> {
match &self.data {
IdentifiedPeptidoformData::Novor(NovorData { peptide, .. })
| IdentifiedPeptidoformData::InstaNovo(InstaNovoData { peptide, .. })
| IdentifiedPeptidoformData::Opair(OpairData { peptide, .. })
| IdentifiedPeptidoformData::PiHelixNovo(PiHelixNovoData { peptide, .. })
| IdentifiedPeptidoformData::PepNet(PepNetData { peptide, .. })
| IdentifiedPeptidoformData::PowerNovo(PowerNovoData { peptide, .. })
| IdentifiedPeptidoformData::PUniFind(PUniFindData {
peptidoform: peptide,
..
})
| IdentifiedPeptidoformData::Proteoscape(ProteoscapeData {
peptide: (_, peptide, _),
..
})
| IdentifiedPeptidoformData::Sage(SageData { peptide, .. }) => peptide.as_unambiguous(),
IdentifiedPeptidoformData::Peaks(PeaksData { peptide, .. }) => {
if peptide.1.len() == 1 {
peptide.1[0].as_unambiguous()
} else {
None
}
}
IdentifiedPeptidoformData::SpectrumSequenceList(SpectrumSequenceListData {
peptide,
..
})
| IdentifiedPeptidoformData::PiPrimeNovo(PiPrimeNovoData { peptide, .. })
| IdentifiedPeptidoformData::DeepNovoFamily(DeepNovoFamilyData { peptide, .. }) => {
peptide.as_ref().and_then(|p| p.as_unambiguous())
}
IdentifiedPeptidoformData::MZTab(MZTabData { peptidoform, .. })
| IdentifiedPeptidoformData::MaxQuant(MaxQuantData {
peptide: peptidoform,
..
}) => peptidoform.as_ref().and_then(|p| p.as_unambiguous()),
IdentifiedPeptidoformData::Fasta(f) => f.peptide().as_unambiguous(),
IdentifiedPeptidoformData::NovoB(NovoBData {
score_forward,
score_reverse,
peptide_forward,
peptide_reverse,
..
}) => {
if score_forward >= score_reverse {
peptide_forward.as_ref().and_then(|p| p.as_unambiguous())
} else {
peptide_reverse.as_ref().and_then(|p| p.as_unambiguous())
}
}
IdentifiedPeptidoformData::MSFragger(MSFraggerData { peptide, .. })
| IdentifiedPeptidoformData::PLGS(PLGSData { peptide, .. }) => peptide.as_unambiguous(),
IdentifiedPeptidoformData::MetaMorpheus(MetaMorpheusData { peptide, .. })
| IdentifiedPeptidoformData::BasicCSV(BasicCSVData {
sequence: peptide, ..
}) => peptide
.singular_peptidoform_ref()
.and_then(|p| p.as_unambiguous()),
IdentifiedPeptidoformData::PLink(PLinkData { peptidoform, .. }) => {
peptidoform.singular_ref().and_then(|p| p.as_unambiguous())
}
#[cfg(feature = "mzannotate")]
IdentifiedPeptidoformData::AnnotatedSpectrum(spectrum) => {
use itertools::Itertools;
let ion = spectrum
.analytes
.iter()
.filter_map(|a| match &a.target {
mzannotate::mzspeclib::AnalyteTarget::PeptidoformIon(pep) => Some(pep),
_ => None,
})
.exactly_one()
.ok()?;
ion.singular_ref().and_then(|p| p.as_unambiguous())
}
}
}
}
impl<Complexity, PeptidoformAvailability>
IdentifiedPeptidoform<Complexity, PeptidoformAvailability>
{
fn check<T>(
self,
f: impl Fn(&Peptidoform<Linked>) -> bool,
) -> Option<IdentifiedPeptidoform<T, PeptidoformPresent>> {
self.compound_peptidoform_ion()
.is_some_and(|p| p.singular_peptidoform_ref().is_some_and(f))
.then(|| self.mark())
}
pub fn into_linear(self) -> Option<IdentifiedPeptidoform<Linear, PeptidoformPresent>> {
self.check(Peptidoform::is_linear)
}
pub fn into_simple_linear(
self,
) -> Option<IdentifiedPeptidoform<SimpleLinear, PeptidoformPresent>> {
self.check(Peptidoform::is_simple_linear)
}
pub fn into_semi_ambiguous(
self,
) -> Option<IdentifiedPeptidoform<SemiAmbiguous, PeptidoformPresent>> {
self.check(Peptidoform::is_semi_ambiguous)
}
pub fn into_unambiguous(
self,
) -> Option<IdentifiedPeptidoform<UnAmbiguous, PeptidoformPresent>> {
self.check(Peptidoform::is_unambiguous)
}
}
impl HasPeptidoformImpl for IdentifiedPeptidoform<Linear, PeptidoformPresent> {
type Complexity = Linear;
fn peptidoform(&self) -> &Peptidoform<Linear> {
self.inner_peptidoform()
.expect("Identified peptidoform incorrectly marked as containing a peptidoform")
}
}
impl HasPeptidoformImpl for &IdentifiedPeptidoform<Linear, PeptidoformPresent> {
type Complexity = Linear;
fn peptidoform(&self) -> &Peptidoform<Linear> {
self.inner_peptidoform()
.expect("Identified peptidoform incorrectly marked as containing a peptidoform")
}
}
impl HasPeptidoformImpl for IdentifiedPeptidoform<SimpleLinear, PeptidoformPresent> {
type Complexity = SimpleLinear;
fn peptidoform(&self) -> &Peptidoform<SimpleLinear> {
self.inner_peptidoform()
.expect("Identified peptidoform incorrectly marked as containing a peptidoform")
}
}
impl HasPeptidoformImpl for &IdentifiedPeptidoform<SimpleLinear, PeptidoformPresent> {
type Complexity = SimpleLinear;
fn peptidoform(&self) -> &Peptidoform<SimpleLinear> {
self.inner_peptidoform()
.expect("Identified peptidoform incorrectly marked as containing a peptidoform")
}
}
impl HasPeptidoformImpl for IdentifiedPeptidoform<SemiAmbiguous, PeptidoformPresent> {
type Complexity = SemiAmbiguous;
fn peptidoform(&self) -> &Peptidoform<SemiAmbiguous> {
self.inner_peptidoform()
.expect("Identified peptidoform incorrectly marked as containing a peptidoform")
}
}
impl HasPeptidoformImpl for &IdentifiedPeptidoform<SemiAmbiguous, PeptidoformPresent> {
type Complexity = SemiAmbiguous;
fn peptidoform(&self) -> &Peptidoform<SemiAmbiguous> {
self.inner_peptidoform()
.expect("Identified peptidoform incorrectly marked as containing a peptidoform")
}
}
impl HasPeptidoformImpl for IdentifiedPeptidoform<UnAmbiguous, PeptidoformPresent> {
type Complexity = UnAmbiguous;
fn peptidoform(&self) -> &Peptidoform<UnAmbiguous> {
self.inner_peptidoform()
.expect("Identified peptidoform incorrectly marked as containing a peptidoform")
}
}
impl HasPeptidoformImpl for &IdentifiedPeptidoform<UnAmbiguous, PeptidoformPresent> {
type Complexity = UnAmbiguous;
fn peptidoform(&self) -> &Peptidoform<UnAmbiguous> {
self.inner_peptidoform()
.expect("Identified peptidoform incorrectly marked as containing a peptidoform")
}
}
impl IdentifiedPeptidoform<Linear, MaybePeptidoform> {
pub fn peptidoform(&self) -> Option<&Peptidoform<Linear>> {
self.inner_peptidoform()
}
}
impl IdentifiedPeptidoform<SimpleLinear, MaybePeptidoform> {
pub fn peptidoform(&self) -> Option<&Peptidoform<SimpleLinear>> {
self.inner_peptidoform()
}
}
impl IdentifiedPeptidoform<SemiAmbiguous, MaybePeptidoform> {
pub fn peptidoform(&self) -> Option<&Peptidoform<SemiAmbiguous>> {
self.inner_peptidoform()
}
}
impl IdentifiedPeptidoform<UnAmbiguous, MaybePeptidoform> {
pub fn peptidoform(&self) -> Option<&Peptidoform<UnAmbiguous>> {
self.inner_peptidoform()
}
}
impl<Complexity, PeptidoformAvailability>
IdentifiedPeptidoform<Complexity, PeptidoformAvailability>
{
fn mark<C, A>(self) -> IdentifiedPeptidoform<C, A> {
IdentifiedPeptidoform {
score: self.score,
local_confidence: self.local_confidence,
data: self.data,
complexity_marker: PhantomData,
peptidoform_availability_marker: PhantomData,
}
}
pub fn cast<
NewComplexity: AtLeast<Complexity>,
NewAvailability: From<PeptidoformAvailability>,
>(
self,
) -> IdentifiedPeptidoform<NewComplexity, NewAvailability> {
self.mark()
}
}
macro_rules! impl_metadata {
(formats: $format:tt; functions: {$($(#[cfg($cfg:expr)])?fn $function:ident(&self) -> $t:ty);+;}) => {
impl<Complexity, PeptidoformAvailability> MetaData for IdentifiedPeptidoform<Complexity, PeptidoformAvailability> {
fn confidence(&self) -> Option<f64> {
self.score
}
fn local_confidence(&self) -> Option<Cow<'_, [f64]>> {
self.local_confidence
.as_ref()
.map(|lc| Cow::Borrowed(lc.as_slice()))
}
$(impl_metadata!(inner: formats: $format; function: $function -> $t);)+
}
};
(inner: formats: {$($format:ident),*}; function: $(#[cfg($cfg:expr)])?$function:ident -> $t:ty) => {
$(#[cfg($cfg)])?
fn $function(&self) -> $t {
match &self.data {
$(IdentifiedPeptidoformData::$format(d) => d.$function()),*
}
}
};
}
#[cfg(not(feature = "mzannotate"))]
impl_metadata!(
formats: {BasicCSV,DeepNovoFamily,Fasta,MaxQuant,MetaMorpheus,InstaNovo,MZTab,NovoB,Novor,Opair,Peaks,PepNet,PiHelixNovo,PiPrimeNovo,PLGS,PLink,PowerNovo,Proteoscape,PUniFind,Sage,MSFragger,SpectrumSequenceList};
functions: {
fn compound_peptidoform_ion(&self) -> Option<Cow<'_, CompoundPeptidoformIon>>;
fn format(&self) -> KnownFileFormat;
fn id(&self) -> String;
fn original_confidence(&self) -> Option<f64>;
fn original_local_confidence(&self) -> Option<&[f64]>;
fn charge(&self) -> Option<Charge>;
fn mode(&self) -> Option<Cow<'_, str>>;
fn retention_time(&self) -> Option<Time>;
fn scans(&self) -> SpectrumIds;
fn experimental_mz(&self) -> Option<MassOverCharge>;
fn experimental_mass(&self) -> Option<Mass>;
fn ppm_error(&self) -> Option<Ratio>;
fn mass_error(&self) -> Option<Mass>;
fn protein_names(&self) -> Option<Cow<'_, [FastaIdentifier<String>]>>;
fn protein_id(&self) -> Option<usize>;
fn protein_location(&self) -> Option<Range<u16>>;
fn flanking_sequences(&self) -> (&FlankingSequence, &FlankingSequence);
fn database(&self) -> Option<(&str, Option<&str>)>;
}
);
#[cfg(feature = "mzannotate")]
impl_metadata!(
formats: {BasicCSV,DeepNovoFamily,Fasta,MaxQuant,MetaMorpheus,InstaNovo,MZTab,NovoB,Novor,Opair,Peaks,PepNet,PiHelixNovo,PiPrimeNovo,PLGS,PLink,PowerNovo,Proteoscape,PUniFind,Sage,MSFragger,SpectrumSequenceList,AnnotatedSpectrum};
functions: {
fn compound_peptidoform_ion(&self) -> Option<Cow<'_, CompoundPeptidoformIon>>;
fn format(&self) -> KnownFileFormat;
fn id(&self) -> String;
fn original_confidence(&self) -> Option<f64>;
fn original_local_confidence(&self) -> Option<&[f64]>;
fn charge(&self) -> Option<Charge>;
fn mode(&self) -> Option<Cow<'_, str>>;
fn fragmentation_model(&self) -> Option<mzannotate::annotation::model::BuiltInFragmentationModel>;
fn retention_time(&self) -> Option<Time>;
fn scans(&self) -> SpectrumIds;
fn experimental_mz(&self) -> Option<MassOverCharge>;
fn experimental_mass(&self) -> Option<Mass>;
fn ppm_error(&self) -> Option<Ratio>;
fn mass_error(&self) -> Option<Mass>;
fn protein_names(&self) -> Option<Cow<'_, [FastaIdentifier<String>]>>;
fn protein_id(&self) -> Option<usize>;
fn protein_location(&self) -> Option<Range<u16>>;
fn flanking_sequences(&self) -> (&FlankingSequence, &FlankingSequence);
fn database(&self) -> Option<(&str, Option<&str>)>;
fn annotated_spectrum(&self) -> Option<Cow<'_, AnnotatedSpectrum>>;
fn has_annotated_spectrum(&self) -> bool;
}
);