1use std::borrow::Cow;
5use std::convert::TryFrom;
6use std::fmt::Display;
7use std::hash::Hash;
8use std::num;
9use std::str::{self, FromStr};
10
11use thiserror::Error;
12
13pub(crate) mod value;
14
15pub use value::{ParamValue, ParamValueParseError, Value};
16
17pub(crate) mod value_ref;
18
19pub use value_ref::ValueRef;
20
21pub(crate) mod curie_;
22
23pub use curie_::{
24 AccessionCodeParseError, AccessionIntCode, CURIE, CURIEParsingError, ControlledVocabulary,
25 ControlledVocabularyResolutionError, curie_to_num,
26};
27
28#[cfg(feature = "cv")]
29pub(crate) mod cv;
30
31#[cfg(feature = "cv")]
32pub use cv::{CVTraversal, MSTerm, MSVocabulary, VocabularyData};
33
34#[macro_export]
36macro_rules! find_param_method {
37 ($meth:ident, $curie:expr) => {
38 $crate::find_param_method!($meth, $curie, "Find a parameter by its CURIE");
39 };
40 ($meth:ident, $curie:expr, $desc:literal) => {
41 #[doc=$desc]
42 pub fn $meth(&self) -> Option<$crate::ValueRef<'_>> {
43 self.get_param_by_curie($curie)
44 .map(|p| $crate::ParamLike::value(p))
45 }
46 };
47 ($meth:ident, $curie:expr, $conv:expr, $result:ty) => {
48 $crate::find_param_method!(
49 $meth,
50 $curie,
51 $conv,
52 $result,
53 "Find a parameter by its CURIE"
54 );
55 };
56 ($meth:ident, $curie:expr, $conv:expr, $result:ty, $desc:literal) => {
57 #[doc=$desc]
58 pub fn $meth(&self) -> $result {
59 self.get_param_by_curie($curie).map($conv)
60 }
61 };
62}
63
64#[macro_export]
66macro_rules! curie {
67 ($ns:ident:$acc:literal) => {
68 $crate::CURIE {
69 controlled_vocabulary: $crate::ControlledVocabulary::$ns,
70 accession: $acc,
71 }
72 };
73}
74
75pub trait ParamLike {
77 fn name(&self) -> &str;
78 fn value(&self) -> ValueRef<'_>;
79 fn accession(&self) -> Option<AccessionIntCode>;
80 fn controlled_vocabulary(&self) -> Option<ControlledVocabulary>;
81 fn unit(&self) -> Unit;
82 fn is_ms(&self) -> bool {
83 if let Some(cv) = self.controlled_vocabulary() {
84 cv == ControlledVocabulary::MS
85 } else {
86 false
87 }
88 }
89
90 fn parse<T: str::FromStr>(&self) -> Result<T, T::Err> {
91 self.value().parse::<T>()
92 }
93
94 fn is_controlled(&self) -> bool {
95 self.accession().is_some()
96 }
97
98 fn curie(&self) -> Option<CURIE> {
99 if !self.is_controlled() {
100 None
101 } else {
102 let cv = self.controlled_vocabulary().unwrap();
103 let acc = self.accession().unwrap();
104 Some(CURIE::new(cv, acc))
106 }
107 }
108}
109
110pub(crate) mod param_cow;
111pub use param_cow::ParamCow;
112
113pub(crate) mod param;
114
115pub use param::{Param, ParamBuilder};
116
117#[derive(Debug, Clone)]
119pub enum AccessionLike<'a> {
120 Text(Cow<'a, str>),
121 Number(AccessionIntCode),
122 CURIE(CURIE),
123}
124
125impl From<AccessionIntCode> for AccessionLike<'_> {
126 fn from(value: AccessionIntCode) -> Self {
127 Self::Number(value)
128 }
129}
130
131impl<'a> From<&'a str> for AccessionLike<'a> {
132 fn from(value: &'a str) -> Self {
133 Self::Text(Cow::Borrowed(value))
134 }
135}
136
137impl From<String> for AccessionLike<'_> {
138 fn from(value: String) -> Self {
139 Self::Text(Cow::Owned(value))
140 }
141}
142
143pub type ParamList = Vec<Param>;
144
145pub trait ParamDescribedRead {
147 fn params(&self) -> &[Param];
149
150 fn get_param_by_name(&self, name: &str) -> Option<&Param> {
152 self.params().iter().find(|¶m| param.name == name)
153 }
154
155 fn get_param_by_curie(&self, curie: &CURIE) -> Option<&Param> {
157 self.params().iter().find(|¶m| curie == param)
158 }
159
160 fn get_param_by_accession(&self, accession: &str) -> Option<&Param> {
164 let (cv, acc_num) = curie_to_num(accession);
165 self.params()
166 .iter()
167 .find(|¶m| param.accession == acc_num && param.controlled_vocabulary == cv)
168 }
169
170 fn iter_params(&self) -> std::slice::Iter<'_, Param> {
172 self.params().iter()
173 }
174}
175
176impl ParamDescribedRead for &[Param] {
177 fn params(&self) -> &[Param] {
178 self
179 }
180}
181
182
183pub trait ParamDescribed {
186 fn params(&self) -> &[Param];
188
189 fn params_mut(&mut self) -> &mut ParamList;
191
192 fn add_param(&mut self, param: Param) {
194 self.params_mut().push(param);
195 }
196
197 fn extend_params(&mut self, it: impl IntoIterator<Item = Param>) {
199 self.params_mut().extend(it)
200 }
201
202 fn remove_param(&mut self, index: usize) -> Param {
204 self.params_mut().remove(index)
205 }
206
207 fn get_param_by_name(&self, name: &str) -> Option<&Param> {
209 self.params().iter().find(|¶m| param.name == name)
210 }
211
212 fn get_param_by_curie(&self, curie: &CURIE) -> Option<&Param> {
214 self.params().iter().find(|¶m| curie == param)
215 }
216
217 fn get_param_by_accession(&self, accession: &str) -> Option<&Param> {
221 let (cv, acc_num) = curie_to_num(accession);
222 self.params()
223 .iter()
224 .find(|¶m| param.accession == acc_num && param.controlled_vocabulary == cv)
225 }
226
227 fn iter_params(&self) -> std::slice::Iter<'_, Param> {
229 self.params().iter()
230 }
231
232 fn iter_params_mut(&mut self) -> std::slice::IterMut<'_, Param> {
234 self.params_mut().iter_mut()
235 }
236}
237
238impl ParamDescribed for ParamList {
239 fn params(&self) -> &[Param] {
240 self
241 }
242
243 fn params_mut(&mut self) -> &mut ParamList {
244 self
245 }
246}
247
248
249#[macro_export]
252macro_rules! impl_param_described {
253 ($($t:ty), +) => {$(
254
255 impl $crate::ParamDescribed for $t {
256 fn params(&self) -> &[$crate::Param] {
257 return &self.params
258 }
259
260 fn params_mut(&mut self) -> &mut $crate::ParamList {
261 return &mut self.params
262 }
263 }
264 )+};
265}
266
267#[doc(hidden)]
268pub const _EMPTY_PARAM: &[Param] = &[];
269
270#[macro_export]
274macro_rules! impl_param_described_deferred {
275 ($($t:ty), +) => {$(
276 impl $crate::ParamDescribed for $t {
277 fn params(&self) -> &[$crate::Param] {
278 match &self.params {
279 Some(val) => &val,
280 None => {
281 $crate::_EMPTY_PARAM
282 }
283 }
284 }
285
286 fn params_mut(&mut self) -> &mut $crate::ParamList {
287 let val = &mut self.params;
288 if val.is_some() {
289 return val.as_deref_mut().unwrap()
290 } else {
291 *val = Some(Box::default());
292 return val.as_deref_mut().unwrap()
293 }
294 }
295 }
296 )+};
297}
298
299pub(crate) mod units;
300
301pub use units::Unit;
302
303#[cfg(test)]
304mod test {
305 use super::*;
306
307 #[test]
308 fn test_build_param() {
309 assert_eq!(
310 ParamBuilder::default()
311 .name("dalton")
312 .curie(curie!(UO:221))
313 .build(),
314 ControlledVocabulary::UO.param("UO:000221", "dalton")
315 );
316 let p = ParamBuilder::default()
318 .controlled_vocabulary(ControlledVocabulary::MS)
319 .accession(1000529)
320 .name("instrument serial number")
321 .value("FSN10375")
322 .unit(Unit::Unknown)
323 .build();
324 assert_eq!(p.value(), "FSN10375");
325 assert_eq!(p.unit(), Unit::Unknown);
326 }
327
328 #[test]
329 fn test_value() {
330 let x = 42;
331 let mut val: Value = x.into();
332 let mut val_ref: ValueRef = x.into();
333 let mut val_ref2: ValueRef = (&x).into();
334 assert_eq!(val, x);
335 assert_eq!(val_ref, x);
336 assert_eq!(val_ref, val);
337 assert_eq!(val_ref2, val_ref);
338 assert!(val.to_bool().unwrap());
339 assert!(val_ref.to_bool().unwrap());
340 assert_eq!(val.to_str(), x.to_string());
341 assert_eq!(val_ref.to_str(), x.to_string());
342 val = x.to_string().parse().unwrap();
343 val_ref = x.to_string().parse().unwrap();
344 assert_eq!(val, x);
345 assert_eq!(val_ref, x);
346 assert_eq!(val_ref, val);
347
348 let x2 = Some(x);
349 val = x2.into();
350 val_ref = x2.into();
351 val_ref2 = (&x).into();
352 assert_eq!(val, x);
353 assert_eq!(val_ref, x);
354 assert_eq!(val_ref, val);
355 assert_eq!(val_ref2, val_ref);
356 assert!(val.to_bool().unwrap());
357 assert!(val_ref.to_bool().unwrap());
358 assert_eq!(val.to_str(), x.to_string());
359 assert_eq!(val_ref.to_str(), x.to_string());
360 val = x.to_string().parse().unwrap();
361 val_ref = x.to_string().parse().unwrap();
362 assert_eq!(val, x);
363 assert_eq!(val_ref, x);
364 assert_eq!(val_ref, val);
365
366 let x = 42.01;
367 val = x.into();
368 val_ref = x.into();
369 val_ref2 = (&x).into();
370 assert_eq!(val, x);
371 assert_eq!(val_ref, x);
372 assert_eq!(val_ref, val);
373 assert_eq!(val_ref2, val_ref);
374 assert!(val.to_bool().unwrap());
375 assert!(val_ref.to_bool().unwrap());
376 assert_eq!(val.to_str(), x.to_string());
377 assert_eq!(val_ref.to_str(), x.to_string());
378 val = x.to_string().parse().unwrap();
379 val_ref = x.to_string().parse().unwrap();
380 assert_eq!(val, x);
381 assert_eq!(val_ref, x);
382 assert_eq!(val_ref, val);
383
384 let x2 = Some(x);
385 val = x2.into();
386 val_ref = x2.into();
387 assert_eq!(val, x);
388 assert_eq!(val_ref, x);
389 assert_eq!(val_ref, val);
390 assert!(val.to_bool().unwrap());
391 assert!(val_ref.to_bool().unwrap());
392 assert_eq!(val.to_str(), x.to_string());
393 assert_eq!(val_ref.to_str(), x.to_string());
394 val = x.to_string().parse().unwrap();
395 val_ref = x.to_string().parse().unwrap();
396 assert_eq!(val, x);
397 assert_eq!(val_ref, x);
398 assert_eq!(val_ref, val);
399
400 let x = true;
401 val = x.into();
402 val_ref = x.into();
403 assert_eq!(val, x);
404 assert_eq!(val_ref, x);
405 assert_eq!(val_ref, val);
406 assert!(val.to_bool().unwrap());
407 assert!(val_ref.to_bool().unwrap());
408 assert_eq!(val.to_str(), x.to_string());
409 assert_eq!(val_ref.to_str(), x.to_string());
410 val = x.to_string().parse().unwrap();
411 val_ref = x.to_string().parse().unwrap();
412 assert_eq!(val, x);
413 assert_eq!(val_ref, x);
414 assert_eq!(val_ref, val);
415
416 let x = "Foobar".to_string();
417 val = x.clone().into();
418 val_ref = x.clone().into();
419 val_ref2 = x.as_str().into();
420 assert_eq!(val, x);
421 assert_eq!(val_ref, x);
422 assert_eq!(val_ref, val);
423 assert_eq!(val_ref2, val_ref);
424 assert_eq!(val.to_str(), x.to_string());
425 assert_eq!(val_ref.to_str(), x.to_string());
426 val = x.to_string().parse().unwrap();
427 val_ref = x.to_string().parse().unwrap();
428 assert_eq!(val, x);
429 assert_eq!(val_ref, x);
430 assert_eq!(val_ref, val);
431 assert_eq!(val.to_buffer().unwrap(), x.as_bytes());
432 assert_eq!(val_ref.to_buffer().unwrap(), x.as_bytes());
433 assert_eq!(val_ref.to_buffer().unwrap(), val.to_buffer().unwrap());
434 }
435
436 #[cfg(feature = "static_data")]
437 #[test]
438 fn test_mzcv_ms() {
439 let cv = MSVocabulary::init();
440 let term = cv.get_by_name("ms level").unwrap();
441 assert_eq!(term.name.as_ref(), "ms level");
442 let parents_of = CVTraversal::parents_of(cv, term.curie()).unwrap();
443 let parent = cv
444 .get_by_index(&parents_of.iter().next().unwrap().0)
445 .unwrap();
446 assert_eq!(parent.name.as_ref(), "spectrum attribute");
447 }
448}