1use std::borrow::Cow;
2use std::fmt::Display;
3use std::hash::Hash;
4use std::str::{self, FromStr};
5
6
7use crate::{
8 AccessionIntCode, CURIE, ControlledVocabulary, ParamCow, ParamLike, ParamValue, ParamValueParseError, Unit, Value, ValueRef
9};
10
11
12#[derive(Debug, Clone, Default, PartialEq, Eq)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15pub struct Param {
16 pub name: String,
18 pub value: Value,
20 pub accession: Option<AccessionIntCode>,
23 pub controlled_vocabulary: Option<ControlledVocabulary>,
25 pub unit: Unit,
27}
28
29impl AsRef<Value> for Param {
30 fn as_ref(&self) -> &Value {
31 &self.value
32 }
33}
34
35impl ParamValue for Param {
36 fn is_empty(&self) -> bool {
37 <Value as ParamValue>::is_empty(&self.value)
38 }
39
40 fn is_i64(&self) -> bool {
41 <Value as ParamValue>::is_i64(&self.value)
42 }
43
44 fn is_f64(&self) -> bool {
45 <Value as ParamValue>::is_f64(&self.value)
46 }
47
48 fn is_buffer(&self) -> bool {
49 <Value as ParamValue>::is_buffer(&self.value)
50 }
51
52 fn is_str(&self) -> bool {
53 <Value as ParamValue>::is_str(&self.value)
54 }
55
56 fn to_f64(&self) -> Result<f64, ParamValueParseError> {
57 <Value as ParamValue>::to_f64(&self.value)
58 }
59
60 fn to_i64(&self) -> Result<i64, ParamValueParseError> {
61 <Value as ParamValue>::to_i64(&self.value)
62 }
63
64 fn to_str(&self) -> Cow<'_, str> {
65 <Value as ParamValue>::to_str(&self.value)
66 }
67
68 fn to_buffer(&self) -> Result<Cow<'_, [u8]>, ParamValueParseError> {
69 <Value as ParamValue>::to_buffer(&self.value)
70 }
71
72 fn parse<T: FromStr>(&self) -> Result<T, T::Err> {
73 <Value as ParamValue>::parse(&self.value)
74 }
75
76 fn as_bytes(&self) -> Cow<'_, [u8]> {
77 <Value as ParamValue>::as_bytes(&self.value)
78 }
79
80 fn as_ref(&self) -> ValueRef<'_> {
81 <Value as ParamValue>::as_ref(&self.value)
82 }
83
84 fn data_len(&self) -> usize {
85 <Value as ParamValue>::data_len(&self.value)
86 }
87
88 fn is_boolean(&self) -> bool {
89 <Value as ParamValue>::is_boolean(&self.value)
90 }
91
92 fn to_bool(&self) -> Result<bool, ParamValueParseError> {
93 <Value as ParamValue>::to_bool(&self.value)
94 }
95
96 fn is_list(&self) -> bool {
97 <Value as ParamValue>::is_list(&self.value)
98 }
99
100 fn as_slice(&self) -> Cow<'_, [Value]> {
101 <Value as ParamValue>::as_slice(&self.value)
102 }
103}
104
105impl Display for Param {
106 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107 let mut body = if self.is_controlled() {
108 format!(
109 "{}:{}|{}={}",
110 String::from_utf8_lossy(self.controlled_vocabulary.unwrap().as_bytes()),
111 self.accession.unwrap(),
112 self.name,
113 self.value
114 )
115 } else {
116 format!("{}={}", self.name, self.value)
117 };
118 if self.unit != Unit::Unknown {
119 body.extend(format!(" {}", self.unit).chars());
120 };
121 f.write_str(body.as_str())
122 }
123}
124
125#[derive(Default, Debug, Clone)]
127pub struct ParamBuilder {
128 name: String,
129 value: Value,
130 accession: Option<AccessionIntCode>,
131 controlled_vocabulary: Option<ControlledVocabulary>,
132 unit: Unit,
133}
134
135impl ParamBuilder {
136 pub fn name<S: ToString>(mut self, name: S) -> Self {
138 self.name = name.to_string();
139 self
140 }
141
142 pub fn value<V: Into<Value>>(mut self, value: V) -> Self {
144 self.value = value.into();
145 self
146 }
147
148 pub fn controlled_vocabulary(mut self, cv: ControlledVocabulary) -> Self {
153 self.controlled_vocabulary = Some(cv);
154 self
155 }
156
157 pub fn accession(mut self, accession: AccessionIntCode) -> Self {
162 self.accession = Some(accession);
163 self
164 }
165
166 pub fn curie(mut self, curie: CURIE) -> Self {
169 self.controlled_vocabulary = Some(curie.controlled_vocabulary);
170 self.accession = Some(curie.accession);
171 self
172 }
173
174 pub fn unit(mut self, unit: Unit) -> Self {
176 self.unit = unit;
177 self
178 }
179
180 pub fn build(self) -> Param {
182 let mut this = Param::new();
183 this.name = self.name;
184 this.value = self.value;
185 this.controlled_vocabulary = self.controlled_vocabulary;
186 this.accession = self.accession;
187 this.unit = self.unit;
188 this
189 }
190}
191
192impl Param {
193 pub fn new() -> Param {
201 Param {
202 ..Default::default()
203 }
204 }
205
206 pub fn builder() -> ParamBuilder {
209 ParamBuilder::default()
210 }
211
212 pub fn new_key_value<K: Into<String>, V: Into<Value>>(name: K, value: V) -> Param {
215 let mut inst = Self::new();
216 inst.name = name.into();
217 inst.value = value.into();
218 inst
219 }
220
221 pub fn parse<T: str::FromStr>(&self) -> Result<T, T::Err> {
225 self.value.parse::<T>()
226 }
227
228 pub const fn is_controlled(&self) -> bool {
230 self.accession.is_some()
231 }
232
233 pub const fn curie(&self) -> Option<CURIE> {
235 match (self.controlled_vocabulary, self.accession) {
236 (Some(cv), Some(acc)) => Some(CURIE::new(cv, acc)),
237 _ => None,
238 }
239 }
240
241 pub fn curie_str(&self) -> Option<String> {
243 self.curie().map(|c| c.to_string())
244 }
245
246 pub fn with_unit<S: AsRef<str>, A: AsRef<str>>(mut self, accession: S, name: A) -> Param {
251 self.unit = Unit::from_accession(accession.as_ref());
252 if matches!(self.unit, Unit::Unknown) {
253 self.unit = Unit::from_name(name.as_ref());
254 }
255 self
256 }
257
258 pub fn with_unit_t(mut self, unit: &Unit) -> Param {
263 self.unit = *unit;
264 self
265 }
266}
267
268impl ParamLike for Param {
269 fn name(&self) -> &str {
270 &self.name
271 }
272
273 fn value(&self) -> ValueRef<'_> {
274 self.value.as_ref()
275 }
276
277 fn accession(&self) -> Option<AccessionIntCode> {
278 self.accession
279 }
280
281 fn controlled_vocabulary(&self) -> Option<ControlledVocabulary> {
282 self.controlled_vocabulary
283 }
284
285 fn unit(&self) -> Unit {
286 self.unit
287 }
288}
289
290impl PartialEq<CURIE> for Param {
291 fn eq(&self, other: &CURIE) -> bool {
292 other.eq(self)
293 }
294}
295
296impl<'a> PartialEq<ParamCow<'a>> for Param {
297 fn eq(&self, other: &ParamCow<'a>) -> bool {
298 self.controlled_vocabulary == other.controlled_vocabulary
299 && self.accession == other.accession
300 && self.name == other.name
301 && self.value == other.value
302 && self.unit == other.unit
303 }
304}
305
306impl PartialEq<Param> for ParamCow<'_> {
307 fn eq(&self, other: &Param) -> bool {
308 self.controlled_vocabulary == other.controlled_vocabulary
309 && self.accession == other.accession
310 && self.name == other.name
311 && self.value == other.value
312 && self.unit == other.unit
313 }
314}
315
316impl Hash for Param {
317 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
318 self.name.hash(state);
319 self.value.hash(state);
320 self.accession.hash(state);
321 self.controlled_vocabulary.hash(state);
322 self.unit.hash(state);
323 }
324}