mzdata/meta/
traits.rs

1use std::collections::HashMap;
2
3use super::{
4    DataProcessing, FileDescription, InstrumentConfiguration, MassSpectrometryRun, Sample, Software,
5};
6
7/// Mass spectrometry data files have several facets of descriptive metadata
8pub trait MSDataFileMetadata {
9    /// The series of [`DataProcessing`] workflows applied to spectra in
10    /// this data file.
11    fn data_processings(&self) -> &Vec<DataProcessing>;
12    /// A mapping over different [`InstrumentConfiguration`] modes that spectra
13    /// were acquired under.
14    fn instrument_configurations(&self) -> &HashMap<u32, InstrumentConfiguration>;
15    /// A description of the contents and the sources for this mass spectrometry
16    /// data file.
17    fn file_description(&self) -> &FileDescription;
18    /// The series of [`Software`] applied to the data file to apply different
19    /// [`DataProcessing`] methods.
20    fn softwares(&self) -> &Vec<Software>;
21
22    /// A list of sample descriptions that were measured in this data file if
23    /// available.
24    fn samples(&self) -> &Vec<Sample>;
25
26    /// Mutably access the [`DataProcessing`] list for this data file
27    fn data_processings_mut(&mut self) -> &mut Vec<DataProcessing>;
28    /// Mutably access the [`InstrumentConfiguration`] mapping for this data file
29    fn instrument_configurations_mut(&mut self) -> &mut HashMap<u32, InstrumentConfiguration>;
30    /// Mutably access the [`FileDescription`] description of the contents and the
31    /// sources for this mass spectrometry data file.
32    fn file_description_mut(&mut self) -> &mut FileDescription;
33    /// Mutably access the list of [`Software`] of this data file.
34    fn softwares_mut(&mut self) -> &mut Vec<Software>;
35    fn samples_mut(&mut self) -> &mut Vec<Sample>;
36
37    /// Copy the metadata from another [`MSDataFileMetadata`] implementation into
38    /// this one.
39    fn copy_metadata_from(&mut self, source: &impl MSDataFileMetadata)
40    where
41        Self: Sized,
42    {
43        *self.data_processings_mut() = source.data_processings().clone();
44        *self.instrument_configurations_mut() = source.instrument_configurations().clone();
45        *self.file_description_mut() = source.file_description().clone();
46        *self.softwares_mut() = source.softwares().clone();
47        *self.samples_mut() = source.samples().clone();
48        self.set_spectrum_count_hint(source.spectrum_count_hint());
49
50        match source.run_description() {
51            Some(run) => {
52                let desc = self.run_description_mut();
53                if let Some(r) = desc {
54                    *r = run.clone();
55                };
56            }
57            None => {
58                let mut desc = self.run_description_mut();
59                desc.take();
60            }
61        }
62    }
63
64    /// A hint about how many spectra are in this data file
65    fn spectrum_count_hint(&self) -> Option<u64> {
66        None
67    }
68
69    fn set_spectrum_count_hint(&mut self, _value: Option<u64>) {}
70
71    /// Access the [`MassSpectrometryRun`] metadata record if it is available
72    fn run_description(&self) -> Option<&MassSpectrometryRun> {
73        None
74    }
75
76    /// Mutably access the [`MassSpectrometryRun`] metadata record if it is available
77    fn run_description_mut(&mut self) -> Option<&mut MassSpectrometryRun> {
78        None
79    }
80
81    /// Get the name of the primary source file, if available
82    fn source_file_name(&self) -> Option<&str> {
83        self.file_description()
84            .source_files
85            .first()
86            .map(|s| s.name.as_str())
87    }
88}
89
90/// A helper data structure for implementing [`MSDataFileMetadata`] in a single common
91/// implementation.
92#[derive(Debug, Default, Clone)]
93pub struct FileMetadataConfig {
94    /// The description of the file's contents and the previous data files that were
95    /// consumed to produce it.
96    pub(crate) file_description: FileDescription,
97
98    /// A mapping of different instrument configurations (source, analyzer, detector) components
99    /// by ID string.
100    pub(crate) instrument_configurations: HashMap<u32, InstrumentConfiguration>,
101
102    /// The different software components that were involved in the processing and creation of this
103    /// file.
104    pub(crate) softwares: Vec<Software>,
105
106    pub(crate) samples: Vec<Sample>,
107
108    /// The data processing and signal transformation operations performed on the raw data in previous
109    /// source files to produce this file's contents.
110    pub(crate) data_processings: Vec<DataProcessing>,
111
112    // MS run attributes
113    pub(crate) run: MassSpectrometryRun,
114    pub(crate) num_spectra: Option<u64>,
115}
116
117impl FileMetadataConfig {
118    pub fn new(
119        file_description: FileDescription,
120        instrument_configurations: HashMap<u32, InstrumentConfiguration>,
121        softwares: Vec<Software>,
122        samples: Vec<Sample>,
123        data_processings: Vec<DataProcessing>,
124        run: MassSpectrometryRun,
125        num_spectra: Option<u64>,
126    ) -> Self {
127        Self {
128            file_description,
129            instrument_configurations,
130            softwares,
131            samples,
132            data_processings,
133            run,
134            num_spectra,
135        }
136    }
137}
138
139impl<T> From<&T> for FileMetadataConfig where T: MSDataFileMetadata {
140    fn from(value: &T) -> Self {
141        let mut this = Self::default();
142        this.copy_metadata_from(value);
143        this
144    }
145}
146
147impl MSDataFileMetadata for FileMetadataConfig {
148    crate::impl_metadata_trait!();
149
150    fn run_description(&self) -> Option<&MassSpectrometryRun> {
151        Some(&self.run)
152    }
153
154    fn run_description_mut(&mut self) -> Option<&mut MassSpectrometryRun> {
155        Some(&mut self.run)
156    }
157
158    fn set_spectrum_count_hint(&mut self, _value: Option<u64>) {
159        self.num_spectra = _value
160    }
161
162    fn spectrum_count_hint(&self) -> Option<u64> {
163        self.num_spectra
164    }
165}
166
167#[macro_export]
168/// Assumes a field for the non-`Option` facets of the [`MSDataFileMetadata`]
169/// implementation are present. Passing an extra level `extended` token implements
170/// the optional methods.
171macro_rules! impl_metadata_trait {
172    (extended) => {
173        $crate::impl_metadata_trait();
174
175        fn spectrum_count_hint(&self) -> Option<u64> {
176            self.num_spectra
177        }
178
179        fn run_description(&self) -> Option<&$crate::meta::MassSpectrometryRun> {
180            Some(&self.run)
181        }
182
183        fn run_description_mut(&mut self) -> Option<&mut $crate::meta::MassSpectrometryRun> {
184            Some(&mut self.run)
185        }
186    };
187    () => {
188        fn data_processings(&self) -> &Vec<$crate::meta::DataProcessing> {
189            &self.data_processings
190        }
191
192        fn instrument_configurations(
193            &self,
194        ) -> &std::collections::HashMap<u32, $crate::meta::InstrumentConfiguration> {
195            &self.instrument_configurations
196        }
197        fn file_description(&self) -> &$crate::meta::FileDescription {
198            &self.file_description
199        }
200        fn softwares(&self) -> &Vec<$crate::meta::Software> {
201            &self.softwares
202        }
203
204        fn data_processings_mut(&mut self) -> &mut Vec<$crate::meta::DataProcessing> {
205            &mut self.data_processings
206        }
207
208        fn instrument_configurations_mut(
209            &mut self,
210        ) -> &mut std::collections::HashMap<u32, $crate::meta::InstrumentConfiguration> {
211            &mut self.instrument_configurations
212        }
213
214        fn file_description_mut(&mut self) -> &mut $crate::meta::FileDescription {
215            &mut self.file_description
216        }
217
218        fn softwares_mut(&mut self) -> &mut Vec<$crate::meta::Software> {
219            &mut self.softwares
220        }
221
222        fn samples(&self) -> &Vec<$crate::meta::Sample> {
223            &self.samples
224        }
225
226        fn samples_mut(&mut self) -> &mut Vec<$crate::meta::Sample> {
227            &mut self.samples
228        }
229    };
230}
231
232#[macro_export]
233/// Delegates the implementation of [`MSDataFileMetadata`] to a member. Passing an extra
234/// level `extended` token implements the optional methods.
235macro_rules! delegate_impl_metadata_trait {
236
237    (expr, $self:ident => $impl:tt, &mut => $mut_impl:tt) => {
238
239        fn data_processings(&self) -> &Vec<$crate::meta::DataProcessing> {
240            let $self = self;
241            let step = $impl;
242            step.data_processings()
243        }
244
245        fn instrument_configurations(&self) -> &std::collections::HashMap<u32, $crate::meta::InstrumentConfiguration> {
246            let $self = self;
247            let step = $impl;
248            step.instrument_configurations()
249        }
250
251        fn file_description(&self) -> &$crate::meta::FileDescription {
252            let $self = self;
253            let step = $impl;
254            step.file_description()
255        }
256
257        fn softwares(&self) -> &Vec<$crate::meta::Software> {
258            let $self = self;
259            let step = $impl;
260            step.softwares()
261        }
262
263        fn samples(&self) -> &Vec<$crate::meta::Sample> {
264            let $self = self;
265            let step = $impl;
266            step.samples()
267        }
268
269        fn data_processings_mut(&mut self) -> &mut Vec<$crate::meta::DataProcessing> {
270            let $self = self;
271            let step = $mut_impl;
272            step.data_processings_mut()
273        }
274
275        fn instrument_configurations_mut(&mut self) -> &mut std::collections::HashMap<u32, $crate::meta::InstrumentConfiguration> {
276            let $self = self;
277            let step = $mut_impl;
278            step.instrument_configurations_mut()
279        }
280
281        fn file_description_mut(&mut self) -> &mut $crate::meta::FileDescription {
282            let $self = self;
283            let step = $mut_impl;
284            step.file_description_mut()
285        }
286
287        fn softwares_mut(&mut self) -> &mut Vec<$crate::meta::Software> {
288            let $self = self;
289            let step = $mut_impl;
290            step.softwares_mut()
291        }
292
293        fn samples_mut(&mut self) -> &mut Vec<$crate::meta::Sample> {
294            let $self = self;
295            let step = $mut_impl;
296            step.samples_mut()
297        }
298
299        fn spectrum_count_hint(&self) -> Option<u64> {
300            let $self = self;
301            let step = $impl;
302            step.spectrum_count_hint()
303        }
304
305        fn run_description(&self) -> Option<&$crate::meta::MassSpectrometryRun> {
306            let $self = self;
307            let step = $impl;
308            step.run_description()
309        }
310
311        fn run_description_mut(&mut self) -> Option<&mut $crate::meta::MassSpectrometryRun> {
312            let $self = self;
313            let step = $mut_impl;
314            step.run_description_mut()
315        }
316
317        fn source_file_name(&self) -> Option<&str> {
318            let $self = self;
319            let step = $impl;
320            step.source_file_name()
321        }
322    };
323    ($src:tt, extended) => {
324        $crate::delegate_impl_metadata_trait($src);
325    };
326    ($src:tt) => {
327        $crate::delegate_impl_metadata_trait!(expr, this => { &this.$src }, &mut => { &mut this.$src });
328    };
329}