Skip to main content

mzdata_param/
param_cow.rs

1use std::borrow::Cow;
2use std::str::{self, FromStr};
3
4
5use crate::{
6    AccessionIntCode, CURIE, ControlledVocabulary, Param, ParamLike, ParamValue, ParamValueParseError, Unit, Value, ValueRef
7};
8
9
10/// A statically allocate-able or non-owned data version of [`Param`]
11#[derive(Debug, Clone, Default, PartialEq, Eq)]
12#[cfg_attr(feature = "serde", derive(serde::Serialize))]
13pub struct ParamCow<'a> {
14    /// The human-readable name of the parameter.
15    pub name: Cow<'a, str>,
16    /// The parameter's value.
17    pub value: ValueRef<'a>,
18    /// The numeric accession code within `controlled_vocabulary`, if this parameter is
19    /// drawn from a controlled vocabulary.
20    pub accession: Option<AccessionIntCode>,
21    /// The controlled vocabulary this parameter's term belongs to. `None` for a
22    /// free-text, user-defined parameter.
23    pub controlled_vocabulary: Option<ControlledVocabulary>,
24    /// The unit the value is expressed in, if known.
25    pub unit: Unit,
26}
27
28impl<'a> ParamValue for ParamCow<'a> {
29    fn is_empty(&self) -> bool {
30        <ValueRef<'a> as ParamValue>::is_empty(&self.value)
31    }
32
33    fn is_i64(&self) -> bool {
34        <ValueRef<'a> as ParamValue>::is_i64(&self.value)
35    }
36
37    fn is_f64(&self) -> bool {
38        <ValueRef<'a> as ParamValue>::is_f64(&self.value)
39    }
40
41    fn is_buffer(&self) -> bool {
42        <ValueRef<'a> as ParamValue>::is_buffer(&self.value)
43    }
44
45    fn is_str(&self) -> bool {
46        <ValueRef<'a> as ParamValue>::is_str(&self.value)
47    }
48
49    fn to_f64(&self) -> Result<f64, ParamValueParseError> {
50        <ValueRef<'a> as ParamValue>::to_f64(&self.value)
51    }
52
53    fn to_i64(&self) -> Result<i64, ParamValueParseError> {
54        <ValueRef<'a> as ParamValue>::to_i64(&self.value)
55    }
56
57    fn to_str(&self) -> Cow<'_, str> {
58        <ValueRef<'a> as ParamValue>::to_str(&self.value)
59    }
60
61    fn to_buffer(&self) -> Result<Cow<'_, [u8]>, ParamValueParseError> {
62        <ValueRef<'a> as ParamValue>::to_buffer(&self.value)
63    }
64
65    fn parse<T: FromStr>(&self) -> Result<T, T::Err> {
66        <ValueRef<'a> as ParamValue>::parse(&self.value)
67    }
68
69    fn as_bytes(&self) -> Cow<'_, [u8]> {
70        <ValueRef<'a> as ParamValue>::as_bytes(&self.value)
71    }
72
73    fn as_ref(&self) -> ValueRef<'_> {
74        <ValueRef<'a> as ParamValue>::as_ref(&self.value)
75    }
76
77    fn data_len(&self) -> usize {
78        <ValueRef<'a> as ParamValue>::data_len(&self.value)
79    }
80
81    fn is_boolean(&self) -> bool {
82        <ValueRef<'a> as ParamValue>::is_boolean(&self.value)
83    }
84
85    fn to_bool(&self) -> Result<bool, ParamValueParseError> {
86        <ValueRef<'a> as ParamValue>::to_bool(&self.value)
87    }
88
89    fn is_list(&self) -> bool {
90        <ValueRef<'a> as ParamValue>::is_list(&self.value)
91    }
92
93    fn as_slice(&self) -> Cow<'_, [Value]> {
94        <ValueRef<'a> as ParamValue>::as_slice(&self.value)
95    }
96}
97
98impl ParamCow<'static> {
99    /// Build a [`ParamCow<'static>`] in a `const` context. Prefer
100    /// [`ControlledVocabulary::const_param`] and its siblings, which fill in the namespace
101    /// for you.
102    pub const fn const_new(
103        name: &'static str,
104        value: ValueRef<'static>,
105        accession: Option<AccessionIntCode>,
106        controlled_vocabulary: Option<ControlledVocabulary>,
107        unit: Unit,
108    ) -> Self {
109        Self {
110            name: Cow::Borrowed(name),
111            value,
112            accession,
113            controlled_vocabulary,
114            unit,
115        }
116    }
117}
118
119impl<'a> ParamCow<'a> {
120    /// Build a [`ParamCow`] from its parts directly.
121    pub fn new(
122        name: Cow<'a, str>,
123        value: ValueRef<'a>,
124        accession: Option<AccessionIntCode>,
125        controlled_vocabulary: Option<ControlledVocabulary>,
126        unit: Unit,
127    ) -> Self {
128        Self {
129            name,
130            value,
131            accession,
132            controlled_vocabulary,
133            unit,
134        }
135    }
136
137    /// Attempt to parse the value of this parameter into `T`.
138    ///
139    /// See [`Value::parse`]
140    pub fn parse<T: str::FromStr>(&self) -> Result<T, T::Err> {
141        self.value.parse::<T>()
142    }
143
144    /// Check if this parameter is defined in a controlled vocabulary
145    pub const fn is_controlled(&self) -> bool {
146        self.accession.is_some()
147    }
148
149    /// Create a [`CURIE`] from [`ParamCow::controlled_vocabulary`] and [`ParamCow::accession`]
150    pub const fn curie(&self) -> Option<CURIE> {
151        match (self.controlled_vocabulary, self.accession) {
152            (Some(cv), Some(acc)) => Some(CURIE::new(cv, acc)),
153            _ => None,
154        }
155    }
156}
157
158impl<'a> ParamLike for ParamCow<'a> {
159    fn name(&self) -> &str {
160        &self.name
161    }
162
163    fn value(&self) -> ValueRef<'a> {
164        self.value.clone()
165    }
166
167    fn accession(&self) -> Option<AccessionIntCode> {
168        self.accession
169    }
170
171    fn controlled_vocabulary(&self) -> Option<ControlledVocabulary> {
172        self.controlled_vocabulary
173    }
174
175    fn unit(&self) -> Unit {
176        self.unit
177    }
178}
179
180impl<'a> From<ParamCow<'a>> for Param {
181    fn from(value: ParamCow<'a>) -> Self {
182        Param {
183            name: value.name.into_owned(),
184            value: value.value.into(),
185            accession: value.accession,
186            controlled_vocabulary: value.controlled_vocabulary,
187            unit: value.unit,
188        }
189    }
190}
191
192impl PartialEq<CURIE> for ParamCow<'_> {
193    fn eq(&self, other: &CURIE) -> bool {
194        other.eq(self)
195    }
196}
197
198impl<'a> AsRef<ValueRef<'a>> for ParamCow<'a> {
199    fn as_ref(&self) -> &ValueRef<'a> {
200        &self.value
201    }
202}