1use std::borrow::Cow;
2use std::fmt::Display;
3use std::hash::Hash;
4use std::str::{self, FromStr};
5use std::{io, mem};
6
7use thiserror::Error;
8
9use crate::ValueRef;
10
11
12macro_rules! param_value_int {
13 ($val:ty) => {
14 impl From<$val> for Value {
15 fn from(value: $val) -> Self {
16 Self::Int(value as i64)
17 }
18 }
19
20 impl From<&$val> for Value {
21 fn from(value: &$val) -> Self {
22 Self::Int(*value as i64)
23 }
24 }
25
26 impl From<Option<$val>> for Value {
27 fn from(value: Option<$val>) -> Self {
28 if let Some(v) = value {
29 Self::Int(v as i64)
30 } else {
31 Self::Empty
32 }
33 }
34 }
35 };
36}
37
38macro_rules! param_value_float {
39 ($val:ty) => {
40 impl From<$val> for Value {
41 fn from(value: $val) -> Self {
42 Self::Float(value as f64)
43 }
44 }
45
46 impl From<&$val> for Value {
47 fn from(value: &$val) -> Self {
48 Self::Float(*value as f64)
49 }
50 }
51
52 impl From<Option<$val>> for Value {
53 fn from(value: Option<$val>) -> Self {
54 if let Some(v) = value {
55 Self::Float(v as f64)
56 } else {
57 Self::Empty
58 }
59 }
60 }
61 };
62}
63#[derive(Debug, Clone, PartialEq, PartialOrd, Default)]
68#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
69pub enum Value {
70 String(String),
72 Float(f64),
74 Int(i64),
76 Buffer(Box<[u8]>),
78 Boolean(bool),
80 #[default]
82 Empty,
83 List(Box<[Value]>),
85}
86
87impl Eq for Value {}
88
89impl From<String> for Value {
90 fn from(value: String) -> Self {
91 Value::new(value)
92 }
93}
94
95impl From<&str> for Value {
96 fn from(value: &str) -> Self {
97 Value::wrap(value)
98 }
99}
100
101impl From<Cow<'_, str>> for Value {
102 fn from(value: Cow<'_, str>) -> Self {
103 Value::wrap(&value)
104 }
105}
106
107pub trait ParamValue {
110 fn is_empty(&self) -> bool;
112
113 fn is_i64(&self) -> bool;
115
116 fn is_f64(&self) -> bool;
120
121 fn is_buffer(&self) -> bool;
123
124 fn is_str(&self) -> bool;
127
128 fn is_numeric(&self) -> bool {
130 self.is_i64() | self.is_f64()
131 }
132
133 fn is_list(&self) -> bool;
135
136 fn is_boolean(&self) -> bool;
138
139 fn to_f64(&self) -> Result<f64, ParamValueParseError>;
141
142 fn to_f32(&self) -> Result<f32, ParamValueParseError> {
144 let v = self.to_f64()?;
145 Ok(v as f32)
146 }
147
148 fn to_bool(&self) -> Result<bool, ParamValueParseError>;
150
151 fn to_i64(&self) -> Result<i64, ParamValueParseError>;
153
154 fn to_i32(&self) -> Result<i32, ParamValueParseError> {
156 let v = self.to_i64()?;
157 Ok(v as i32)
158 }
159
160 fn to_u64(&self) -> Result<u64, ParamValueParseError> {
162 let v = self.to_i64()?;
163 Ok(v as u64)
164 }
165
166 fn to_str(&self) -> Cow<'_, str>;
168
169 fn as_str(&self) -> Cow<'_, str> {
171 self.to_str()
172 }
173
174 fn to_buffer(&self) -> Result<Cow<'_, [u8]>, ParamValueParseError>;
180
181 fn as_slice(&self) -> Cow<'_, [Value]>;
183
184 fn parse<T: FromStr>(&self) -> Result<T, T::Err>;
186
187 fn as_bytes(&self) -> Cow<'_, [u8]>;
190
191 fn as_ref(&self) -> crate::ValueRef<'_>;
193
194 fn data_len(&self) -> usize;
196}
197
198#[derive(Debug, Clone, Error, PartialEq)]
201pub enum ParamValueParseError {
202 #[error("Failed to extract a float from {0:?}")]
203 FailedToExtractFloat(Option<String>),
204 #[error("Failed to extract a int from {0:?}")]
205 FailedToExtractInt(Option<String>),
206 #[error("Failed to extract a string")]
207 FailedToExtractString,
208 #[error("Failed to extract a buffer")]
209 FailedToExtractBuffer,
210}
211
212impl FromStr for Value {
216 type Err = ParamValueParseError;
217
218 fn from_str(s: &str) -> Result<Self, Self::Err> {
219 if s.is_empty() {
220 return Ok(Self::Empty);
221 }
222 if let Ok(value) = s.parse::<i64>() {
223 Ok(Self::Int(value))
224 } else if let Ok(value) = s.parse::<f64>() {
225 Ok(Self::Float(value))
226 } else if let Ok(value) = s.parse::<bool>() {
227 Ok(Self::Boolean(value))
228 } else {
229 Ok(Self::String(s.to_string()))
230 }
231 }
232}
233
234impl Display for Value {
235 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
236 match self {
237 Value::String(v) => f.write_str(v),
238 Value::Float(v) => v.fmt(f),
239 Value::Int(v) => v.fmt(f),
240 Value::Buffer(v) => f.write_str(&String::from_utf8_lossy(v)),
241 Value::Empty => f.write_str(""),
242 Value::Boolean(v) => v.fmt(f),
243 Value::List(v) => {
244 f.write_str("[ ")?;
245 if let Some(vi) = v.first() {
246 vi.fmt(f)?;
247 }
248 for vi in v.iter().skip(1) {
249 f.write_str(", ")?;
250 vi.fmt(f)?;
251 }
252 f.write_str(" ]")
253 }
254 }
255 }
256}
257
258impl From<ParamValueParseError> for io::Error {
259 fn from(value: ParamValueParseError) -> Self {
260 Self::new(io::ErrorKind::InvalidData, value)
261 }
262}
263
264impl Value {
265 pub fn new(s: String) -> Self {
272 if s.is_empty() {
273 Self::Empty
274 } else if let Ok(value) = s.parse::<i64>() {
275 Self::Int(value)
276 } else if let Ok(value) = s.parse::<f64>() {
277 Self::Float(value)
278 } else if let Ok(value) = s.parse::<bool>() {
279 Self::Boolean(value)
280 } else {
281 Self::String(s)
282 }
283 }
284
285 pub fn wrap(s: &str) -> Self {
292 if s.is_empty() {
293 Self::Empty
294 } else if let Ok(value) = s.parse::<i64>() {
295 Self::Int(value)
296 } else if let Ok(value) = s.parse::<f64>() {
297 Self::Float(value)
298 } else {
299 Self::String(s.to_string())
300 }
301 }
302
303 pub fn is_empty(&self) -> bool {
304 matches!(self, Self::Empty)
305 }
306
307 pub fn is_i64(&self) -> bool {
308 matches!(self, Self::Int(_))
309 }
310
311 pub fn is_f64(&self) -> bool {
312 matches!(self, Self::Float(_))
313 }
314
315 pub fn is_buffer(&self) -> bool {
316 matches!(self, Self::Buffer(_))
317 }
318
319 pub fn is_str(&self) -> bool {
320 matches!(self, Self::String(_))
321 }
322
323 pub fn is_list(&self) -> bool {
324 matches!(self, Self::List(_))
325 }
326
327 pub fn coerce_f64(&mut self) -> Result<(), ParamValueParseError> {
329 let value = self.to_f64()?;
330 *self = Self::Float(value);
331 Ok(())
332 }
333
334 pub fn coerce_i64(&mut self) -> Result<(), ParamValueParseError> {
336 let value = self.to_i64()?;
337 *self = Self::Int(value);
338 Ok(())
339 }
340
341 pub fn coerce_str(&mut self) -> Result<(), ParamValueParseError> {
343 let value = self.to_string();
344 *self = Self::String(value);
345 Ok(())
346 }
347
348 pub fn coerce_empty(&mut self) {
350 *self = Self::Empty;
351 }
352
353 pub fn coerce_buffer(&mut self) -> Result<(), ParamValueParseError> {
355 let buffer = self.to_buffer()?;
356 *self = Self::Buffer(buffer.into());
357 Ok(())
358 }
359
360 pub fn coerce_bool(&mut self) -> Result<(), ParamValueParseError> {
362 let value = self.to_bool()?;
363 *self = Self::Boolean(value);
364 Ok(())
365 }
366
367 pub fn coerce_list(&mut self) -> Result<(), ParamValueParseError> {
369 if !self.is_list() {
370 let mut tmp = Self::Empty;
371 core::mem::swap(&mut tmp, self);
372 *self = Self::List([tmp].into());
373 }
374 Ok(())
375 }
376
377 pub fn parse<T: FromStr>(&self) -> Result<T, T::Err> {
381 match self {
382 Value::String(s) => s.parse(),
383 Value::Float(v) => v.to_string().parse(),
384 Value::Int(i) => i.to_string().parse(),
385 Value::Buffer(b) => String::from_utf8_lossy(b).parse(),
386 Value::Empty => "".parse(),
387 Value::Boolean(b) => b.to_string().parse(),
388 Value::List(_) => self.to_string().parse(),
389 }
390 }
391
392 pub fn to_bool(&self) -> Result<bool, ParamValueParseError> {
393 if let Self::Boolean(val) = self {
394 Ok(*val)
395 } else if self.is_numeric() {
396 Ok(self.to_i64()? != 0)
397 } else if let Self::Empty = self {
398 Ok(false)
399 } else if let Ok(v) = self.parse() {
400 Ok(v)
401 } else {
402 Err(ParamValueParseError::FailedToExtractInt(Some(
403 self.to_string(),
404 )))
405 }
406 }
407
408 pub fn to_f64(&self) -> Result<f64, ParamValueParseError> {
409 if let Self::Float(val) = self {
410 return Ok(*val);
411 } else if let Self::Int(val) = self {
412 return Ok(*val as f64);
413 } else if let Self::String(val) = self {
414 if let Ok(v) = val.parse() {
415 return Ok(v);
416 }
417 }
418 Err(ParamValueParseError::FailedToExtractFloat(Some(
419 self.to_string(),
420 )))
421 }
422
423 pub fn to_i64(&self) -> Result<i64, ParamValueParseError> {
424 if let Self::Int(val) = self {
425 return Ok(*val);
426 } else if let Self::Float(val) = self {
427 return Ok(*val as i64);
428 } else if let Self::String(val) = self {
429 if let Ok(v) = val.parse() {
430 return Ok(v);
431 }
432 }
433 Err(ParamValueParseError::FailedToExtractInt(Some(
434 self.to_string(),
435 )))
436 }
437
438 pub fn to_str(&self) -> Cow<'_, str> {
439 if let Self::String(val) = self {
440 Cow::Borrowed(val)
441 } else {
442 Cow::Owned(self.to_string())
443 }
444 }
445
446 pub fn to_buffer(&self) -> Result<Cow<'_, [u8]>, ParamValueParseError> {
447 if let Self::Buffer(val) = self {
448 Ok(Cow::Borrowed(val))
449 } else if let Self::String(val) = self {
450 Ok(Cow::Borrowed(val.as_bytes()))
451 } else {
452 Err(ParamValueParseError::FailedToExtractBuffer)
453 }
454 }
455
456 pub fn as_ref(&self) -> ValueRef<'_> {
457 self.into()
458 }
459
460 pub fn as_slice(&self) -> &[Self] {
462 if let Self::List(val) = self {
463 val.as_ref()
464 } else {
465 core::slice::from_ref(self)
466 }
467 }
468}
469
470impl ParamValue for Value {
471 fn is_empty(&self) -> bool {
472 self.is_empty()
473 }
474
475 fn is_i64(&self) -> bool {
476 self.is_i64()
477 }
478
479 fn is_f64(&self) -> bool {
480 self.is_f64()
481 }
482
483 fn is_buffer(&self) -> bool {
484 self.is_buffer()
485 }
486
487 fn is_str(&self) -> bool {
488 self.is_str()
489 }
490
491 fn to_f64(&self) -> Result<f64, ParamValueParseError> {
492 self.to_f64()
493 }
494
495 fn to_i64(&self) -> Result<i64, ParamValueParseError> {
496 self.to_i64()
497 }
498
499 fn to_str(&self) -> Cow<'_, str> {
500 self.to_str()
501 }
502
503 fn to_buffer(&self) -> Result<Cow<'_, [u8]>, ParamValueParseError> {
504 self.to_buffer()
505 }
506
507 fn parse<T: FromStr>(&self) -> Result<T, T::Err> {
508 self.parse()
509 }
510
511 fn as_bytes(&self) -> Cow<'_, [u8]> {
512 match self {
513 Self::String(v) => Cow::Borrowed(v.as_bytes()),
514 Self::Buffer(v) => Cow::Borrowed(v.as_ref()),
515 Self::Float(v) => Cow::Owned(v.to_string().into_bytes()),
516 Self::Int(v) => Cow::Owned(v.to_string().into_bytes()),
517 Self::Empty => Cow::Borrowed(b""),
518 Self::Boolean(v) => Cow::Owned(v.to_string().into_bytes()),
519 Self::List(_) => Cow::Owned(self.to_string().into_bytes()),
520 }
521 }
522
523 fn as_ref(&self) -> ValueRef<'_> {
524 self.into()
525 }
526
527 fn data_len(&self) -> usize {
528 match self {
529 Self::String(v) => v.len(),
530 Self::Buffer(v) => v.len(),
531 Self::Float(_) => 8,
532 Self::Int(_) => 8,
533 Self::Empty => 0,
534 Self::Boolean(_) => mem::size_of::<bool>(),
535 Self::List(v) => v.iter().map(|vi| vi.data_len()).sum(),
536 }
537 }
538
539 fn is_boolean(&self) -> bool {
540 matches!(self, Self::Boolean(_))
541 }
542
543 fn to_bool(&self) -> Result<bool, ParamValueParseError> {
544 self.to_bool()
545 }
546
547 fn is_list(&self) -> bool {
548 self.is_list()
549 }
550
551 fn as_slice(&self) -> Cow<'_, [Value]> {
552 Cow::Borrowed(self.as_slice())
553 }
554}
555
556impl PartialEq<String> for Value {
557 fn eq(&self, other: &String) -> bool {
558 self.as_str() == other.as_str()
559 }
560}
561
562impl PartialEq<str> for Value {
563 fn eq(&self, other: &str) -> bool {
564 self.as_str() == other
565 }
566}
567
568impl PartialEq<&str> for Value {
569 fn eq(&self, other: &&str) -> bool {
570 self.as_str() == *other
571 }
572}
573
574impl PartialEq<i64> for Value {
575 fn eq(&self, other: &i64) -> bool {
576 if let Self::Int(val) = self {
577 val == other
578 } else {
579 false
580 }
581 }
582}
583
584impl PartialEq<f64> for Value {
585 fn eq(&self, other: &f64) -> bool {
586 if let Self::Float(val) = self {
587 val == other
588 } else {
589 false
590 }
591 }
592}
593
594impl PartialEq<bool> for Value {
595 fn eq(&self, other: &bool) -> bool {
596 if let Self::Boolean(val) = self {
597 val == other
598 } else {
599 false
600 }
601 }
602}
603
604impl Hash for Value {
605 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
606 core::mem::discriminant(self).hash(state);
607 match self {
608 Self::String(s) => s.hash(state),
609 Self::Float(v) => v.to_bits().hash(state),
610 Self::Int(v) => (*v).hash(state),
611 Self::Buffer(v) => v.hash(state),
612 Self::Empty => 0u8.hash(state),
613 Self::Boolean(v) => v.hash(state),
614 Self::List(v) => {
615 v.iter().for_each(|vi| vi.hash(state));
616 }
617 }
618 }
619}
620
621param_value_int!(i8);
622param_value_int!(i16);
623param_value_int!(i32);
624param_value_int!(i64);
625
626param_value_int!(u8);
627param_value_int!(u16);
628param_value_int!(u32);
629param_value_int!(u64);
630param_value_int!(usize);
631
632param_value_float!(f32);
633param_value_float!(f64);
634
635#[cfg(feature = "serde")]
636impl From<Value> for serde_json::Value {
637 fn from(value: Value) -> Self {
638 match value {
639 Value::Boolean(val) => serde_json::Value::Bool(val),
640 Value::Float(val) => {
641 serde_json::Value::Number(serde_json::Number::from_f64(val).unwrap())
642 }
643 Value::Int(val) => {
644 serde_json::Value::Number(serde_json::Number::from_i128(val as i128).unwrap())
645 }
646 Value::String(val) => serde_json::Value::String(val),
647 Value::Buffer(val) => serde_json::to_value(&val).unwrap(),
648 Value::Empty => serde_json::Value::Null,
649 Value::List(val) => {
650 let mut ve = Vec::new();
651 for vi in val {
652 ve.push(vi.into());
653 }
654 serde_json::Value::Array(ve)
655 }
656 }
657 }
658}