Skip to main content

openmassspec_core/cv/
mod.rs

1//! Typed PSI-MS and UO controlled-vocabulary terms used by the mzML writer.
2//!
3//! Every constant here is generated from `psi-ms.obo` by
4//! `scripts/gen-cv.py` (the term list is `scripts/cv-terms.txt`), and the
5//! generated file records the OBO source URL and `data-version`
6//! ([`PSI_MS_VERSION`], [`PSI_MS_SOURCE_URL`]). A [`Term`] can only be built
7//! inside this module, so an accession is always paired with its exact OBO
8//! name.
9//!
10//! Reader crates can turn a [`Term`] into a [`CvTerm`](crate::CvTerm) with
11//! `From`:
12//!
13//! ```
14//! use openmassspec_core::{cv, CvTerm};
15//!
16//! let term: CvTerm = cv::PEAK_PICKING.into();
17//! assert_eq!(term.accession, "MS:1000035");
18//! assert_eq!(term.name, "peak picking");
19//! ```
20
21mod terms;
22
23pub use terms::*;
24
25/// A PSI-MS (`MS:`) or Unit Ontology (`UO:`) term known at compile time.
26///
27/// The fields are private: the only values are the generated constants in
28/// this module, so the accession and name always match the ontology.
29#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
30pub struct Term {
31    accession: &'static str,
32    name: &'static str,
33}
34
35impl Term {
36    /// Accession, e.g. `"MS:1000016"`.
37    pub const fn accession(self) -> &'static str {
38        self.accession
39    }
40
41    /// Exact OBO name, e.g. `"scan start time"`.
42    pub const fn name(self) -> &'static str {
43        self.name
44    }
45
46    /// mzML `cvRef` for this term: `"UO"` for Unit Ontology accessions,
47    /// `"MS"` otherwise.
48    pub fn cv_ref(self) -> &'static str {
49        if self.accession.starts_with("UO:") {
50            "UO"
51        } else {
52            "MS"
53        }
54    }
55}
56
57/// Look up a generated term by accession.
58pub fn lookup(accession: &str) -> Option<Term> {
59    ALL.iter().copied().find(|t| t.accession == accession)
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65
66    #[test]
67    fn lookup_finds_generated_terms() {
68        assert_eq!(lookup("MS:1000016"), Some(SCAN_START_TIME));
69        assert_eq!(lookup("MS:0000000"), None);
70        assert_eq!(MINUTE.cv_ref(), "UO");
71        assert_eq!(MZ.cv_ref(), "MS");
72    }
73
74    #[test]
75    fn accessions_are_unique() {
76        let mut seen = std::collections::HashSet::new();
77        for t in ALL {
78            assert!(seen.insert(t.accession()), "duplicate {}", t.accession());
79        }
80    }
81}