bdb/traits/
mgf.rs

1use std::convert::AsRef;
2use std::fs::File;
3use std::io::{BufRead, BufReader, BufWriter, Cursor, Write};
4use std::path::Path;
5
6use util::ResultType;
7
8/// Identifier for the MGF file format type.
9///
10/// MGF files are superficially similar text files, with a start and end
11/// delimiter for each scan (usually "BEGIN IONS" and "END IONS"). The
12/// scan metadata is encoded in a header, and each peak in the scan
13/// is encoded on a separate line.
14#[repr(u8)]
15#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
16pub enum MgfKind {
17    /// MSConvert MGF file format.
18    MsConvert = 1,
19    /// Pava MGF file format.
20    Pava = 2,
21    /// ProteoWizard MGF file format.
22    Pwiz = 3,
23    /// Pava MS1 (FullMs) MGF file format.
24    FullMs = 4,
25}
26
27
28/// Serialize to and from MGF.
29///
30/// MGF, or Mascot General Format, is generic format with a start and
31/// end scan delimiter, along with metadata along 1 or multiple header
32/// lines, followed by individual scans (usually with tab-delimited data).
33/// There are many MGF flavors, however, a sample (MSConvert) format
34/// is shown below.
35///
36/// # Serialized Format
37///
38/// ```text
39/// BEGIN IONS
40/// TITLE=Sample.33450.33450.4 File:"Sample.raw", NativeID:"controllerType=0 controllerNumber=1 scan=33450"
41/// RTINSECONDS=8692.657303
42/// PEPMASS=775.15625 170643.953125
43/// CHARGE=4+
44/// 205.9304178 0.0
45/// 205.9320046 0.0
46/// 205.9335913 0.0
47/// 205.9351781 0.0
48/// END IONS
49/// ```
50pub trait Mgf: Sized {
51    /// Estimate the size of the resulting MGF output to avoid reallocations.
52    #[inline(always)]
53    fn estimate_mgf_size(&self, _: MgfKind) -> usize {
54        0
55    }
56
57    /// Export model to MGF.
58    ///
59    /// Note that many small writers are made to the writer, so the writer
60    /// should be buffered.
61    fn to_mgf<T: Write>(&self, writer: &mut T, kind: MgfKind) -> ResultType<()>;
62
63    /// Export model to MGF string.
64    fn to_mgf_string(&self, kind: MgfKind) -> ResultType<String> {
65        let capacity = self.estimate_mgf_size(kind);
66        let mut writer = Cursor::new(Vec::with_capacity(capacity));
67
68        self.to_mgf(&mut writer, kind)?;
69        match String::from_utf8(writer.into_inner()) {
70            Err(e)  => Err(Box::new(e)),
71            Ok(v)   => Ok(v),
72        }
73    }
74
75    /// Export model to MGF output file.
76    #[inline]
77    fn to_mgf_file<P: AsRef<Path>>(&self, path: P, kind: MgfKind) -> ResultType<()> {
78        let file = File::create(path)?;
79        let mut writer = BufWriter::new(file);
80        self.to_mgf(&mut writer, kind)
81    }
82
83    /// Import model from MGF.
84    fn from_mgf<T: BufRead>(reader: &mut T, kind: MgfKind) -> ResultType<Self>;
85
86    /// Import model from MGF string.
87    #[inline]
88    fn from_mgf_string(text: &str, kind: MgfKind) -> ResultType<Self> {
89        // Rust uses the contents of the immutable &str as the buffer
90        // Cursor is then immutable.
91        let mut reader = Cursor::new(text);
92        Self::from_mgf(&mut reader, kind)
93    }
94
95    /// Import model from MGF file.
96    #[inline]
97    fn from_mgf_file<P: AsRef<Path>>(path: P, kind: MgfKind) -> ResultType<Self> {
98        let file = File::open(path)?;
99        let mut reader = BufReader::new(file);
100        Self::from_mgf(&mut reader, kind)
101    }
102}
103
104/// Specialization of the `Mgf` trait for collections.
105pub trait MgfCollection: Mgf {
106    /// Export collection to MGF.
107    ///
108    /// Returns an error if any of the items within the collection
109    /// are invalid.
110    ///
111    /// Note that many small writers are made to the writer, so the writer
112    /// should be buffered.
113    fn to_mgf_strict<T: Write>(&self, writer: &mut T, kind: MgfKind) -> ResultType<()>;
114
115    /// Export collection to MGF.
116    ///
117    /// Returns only errors due to serialization issues, otherwise,
118    /// exports as many items as possible.
119    ///
120    /// Note that many small writers are made to the writer, so the writer
121    /// should be buffered.
122    fn to_mgf_lenient<T: Write>(&self, writer: &mut T, kind: MgfKind) -> ResultType<()>;
123
124    /// Import collection from MGF.
125    ///
126    /// Returns an error if any of the items within the MGF document
127    /// are invalid.
128    fn from_mgf_strict<T: BufRead>(reader: &mut T, kind: MgfKind) -> ResultType<Self>;
129
130    /// Import collection from MGF.
131    ///
132    /// Returns only errors due to deserialization errors, otherwise,
133    /// imports as many items as possible.
134    fn from_mgf_lenient<T: BufRead>(reader: &mut T, kind: MgfKind) -> ResultType<Self>;
135}