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,
17 pub value: Value,
18 pub accession: Option<AccessionIntCode>,
19 pub controlled_vocabulary: Option<ControlledVocabulary>,
20 pub unit: Unit,
21}
22
23impl AsRef<Value> for Param {
24 fn as_ref(&self) -> &Value {
25 &self.value
26 }
27}
28
29impl ParamValue for Param {
30 fn is_empty(&self) -> bool {
31 <Value as ParamValue>::is_empty(&self.value)
32 }
33
34 fn is_i64(&self) -> bool {
35 <Value as ParamValue>::is_i64(&self.value)
36 }
37
38 fn is_f64(&self) -> bool {
39 <Value as ParamValue>::is_f64(&self.value)
40 }
41
42 fn is_buffer(&self) -> bool {
43 <Value as ParamValue>::is_buffer(&self.value)
44 }
45
46 fn is_str(&self) -> bool {
47 <Value as ParamValue>::is_str(&self.value)
48 }
49
50 fn to_f64(&self) -> Result<f64, ParamValueParseError> {
51 <Value as ParamValue>::to_f64(&self.value)
52 }
53
54 fn to_i64(&self) -> Result<i64, ParamValueParseError> {
55 <Value as ParamValue>::to_i64(&self.value)
56 }
57
58 fn to_str(&self) -> Cow<'_, str> {
59 <Value as ParamValue>::to_str(&self.value)
60 }
61
62 fn to_buffer(&self) -> Result<Cow<'_, [u8]>, ParamValueParseError> {
63 <Value as ParamValue>::to_buffer(&self.value)
64 }
65
66 fn parse<T: FromStr>(&self) -> Result<T, T::Err> {
67 <Value as ParamValue>::parse(&self.value)
68 }
69
70 fn as_bytes(&self) -> Cow<'_, [u8]> {
71 <Value as ParamValue>::as_bytes(&self.value)
72 }
73
74 fn as_ref(&self) -> ValueRef<'_> {
75 <Value as ParamValue>::as_ref(&self.value)
76 }
77
78 fn data_len(&self) -> usize {
79 <Value as ParamValue>::data_len(&self.value)
80 }
81
82 fn is_boolean(&self) -> bool {
83 <Value as ParamValue>::is_boolean(&self.value)
84 }
85
86 fn to_bool(&self) -> Result<bool, ParamValueParseError> {
87 <Value as ParamValue>::to_bool(&self.value)
88 }
89
90 fn is_list(&self) -> bool {
91 <Value as ParamValue>::is_list(&self.value)
92 }
93
94 fn as_slice(&self) -> Cow<'_, [Value]> {
95 <Value as ParamValue>::as_slice(&self.value)
96 }
97}
98
99impl Display for Param {
100 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
101 let mut body = if self.is_controlled() {
102 format!(
103 "{}:{}|{}={}",
104 String::from_utf8_lossy(self.controlled_vocabulary.unwrap().as_bytes()),
105 self.accession.unwrap(),
106 self.name,
107 self.value
108 )
109 } else {
110 format!("{}={}", self.name, self.value)
111 };
112 if self.unit != Unit::Unknown {
113 body.extend(format!(" {}", self.unit).chars());
114 };
115 f.write_str(body.as_str())
116 }
117}
118
119#[derive(Default, Debug, Clone)]
121pub struct ParamBuilder {
122 name: String,
123 value: Value,
124 accession: Option<AccessionIntCode>,
125 controlled_vocabulary: Option<ControlledVocabulary>,
126 unit: Unit,
127}
128
129impl ParamBuilder {
130 pub fn name<S: ToString>(mut self, name: S) -> Self {
131 self.name = name.to_string();
132 self
133 }
134
135 pub fn value<V: Into<Value>>(mut self, value: V) -> Self {
136 self.value = value.into();
137 self
138 }
139
140 pub fn controlled_vocabulary(mut self, cv: ControlledVocabulary) -> Self {
141 self.controlled_vocabulary = Some(cv);
142 self
143 }
144
145 pub fn accession(mut self, accession: AccessionIntCode) -> Self {
146 self.accession = Some(accession);
147 self
148 }
149
150 pub fn curie(mut self, curie: CURIE) -> Self {
153 self.controlled_vocabulary = Some(curie.controlled_vocabulary);
154 self.accession = Some(curie.accession);
155 self
156 }
157
158 pub fn unit(mut self, unit: Unit) -> Self {
159 self.unit = unit;
160 self
161 }
162
163 pub fn build(self) -> Param {
165 let mut this = Param::new();
166 this.name = self.name;
167 this.value = self.value;
168 this.controlled_vocabulary = self.controlled_vocabulary;
169 this.accession = self.accession;
170 this.unit = self.unit;
171 this
172 }
173}
174
175impl Param {
176 pub fn new() -> Param {
184 Param {
185 ..Default::default()
186 }
187 }
188
189 pub fn builder() -> ParamBuilder {
191 ParamBuilder::default()
192 }
193
194 pub fn new_key_value<K: Into<String>, V: Into<Value>>(name: K, value: V) -> Param {
197 let mut inst = Self::new();
198 inst.name = name.into();
199 inst.value = value.into();
200 inst
201 }
202
203 pub fn parse<T: str::FromStr>(&self) -> Result<T, T::Err> {
207 self.value.parse::<T>()
208 }
209
210 pub const fn is_controlled(&self) -> bool {
212 self.accession.is_some()
213 }
214
215 pub const fn curie(&self) -> Option<CURIE> {
217 match (self.controlled_vocabulary, self.accession) {
218 (Some(cv), Some(acc)) => Some(CURIE::new(cv, acc)),
219 _ => None,
220 }
221 }
222
223 pub fn curie_str(&self) -> Option<String> {
225 self.curie().map(|c| c.to_string())
226 }
227
228 pub fn with_unit<S: AsRef<str>, A: AsRef<str>>(mut self, accession: S, name: A) -> Param {
230 self.unit = Unit::from_accession(accession.as_ref());
231 if matches!(self.unit, Unit::Unknown) {
232 self.unit = Unit::from_name(name.as_ref());
233 }
234 self
235 }
236
237 pub fn with_unit_t(mut self, unit: &Unit) -> Param {
239 self.unit = *unit;
240 self
241 }
242}
243
244impl ParamLike for Param {
245 fn name(&self) -> &str {
246 &self.name
247 }
248
249 fn value(&self) -> ValueRef<'_> {
250 self.value.as_ref()
251 }
252
253 fn accession(&self) -> Option<AccessionIntCode> {
254 self.accession
255 }
256
257 fn controlled_vocabulary(&self) -> Option<ControlledVocabulary> {
258 self.controlled_vocabulary
259 }
260
261 fn unit(&self) -> Unit {
262 self.unit
263 }
264}
265
266impl PartialEq<CURIE> for Param {
267 fn eq(&self, other: &CURIE) -> bool {
268 other.eq(self)
269 }
270}
271
272impl<'a> PartialEq<ParamCow<'a>> for Param {
273 fn eq(&self, other: &ParamCow<'a>) -> bool {
274 self.controlled_vocabulary == other.controlled_vocabulary
275 && self.accession == other.accession
276 && self.name == other.name
277 && self.value == other.value
278 && self.unit == other.unit
279 }
280}
281
282impl PartialEq<Param> for ParamCow<'_> {
283 fn eq(&self, other: &Param) -> bool {
284 self.controlled_vocabulary == other.controlled_vocabulary
285 && self.accession == other.accession
286 && self.name == other.name
287 && self.value == other.value
288 && self.unit == other.unit
289 }
290}
291
292impl Hash for Param {
293 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
294 self.name.hash(state);
295 self.value.hash(state);
296 self.accession.hash(state);
297 self.controlled_vocabulary.hash(state);
298 self.unit.hash(state);
299 }
300}