1use std::{fmt::Display, ops::Deref, str::FromStr};
4
5#[cfg(feature = "serde")]
7pub fn deserialize_optional_f64_from_string<'de, D>(
8 deserializer: D,
9) -> Result<Option<f64>, D::Error>
10where
11 D: serde::Deserializer<'de>,
12{
13 use serde::Deserialize;
14 use serde::de::Error;
15
16 #[derive(Deserialize)]
17 #[serde(untagged)]
18 enum StringOrF64 {
19 String(String),
20 F64(f64),
21 }
22
23 let value = Option::<StringOrF64>::deserialize(deserializer)?;
24
25 match value {
26 Some(StringOrF64::String(s)) => s
27 .parse::<f64>()
28 .map(Some)
29 .map_err(|_| D::Error::custom(format!("Invalid number format: '{}'", s))),
30 Some(StringOrF64::F64(f)) => Ok(Some(f)),
31 None => Ok(None),
32 }
33}
34
35#[derive(PartialEq, Debug)]
37pub struct AttrList<T>(pub Vec<T>);
38
39impl<T> Deref for AttrList<T> {
40 type Target = [T];
41
42 fn deref(&self) -> &Self::Target {
43 self.0.deref()
44 }
45}
46
47impl<T: FromStr> FromStr for AttrList<T> {
48 type Err = T::Err;
49
50 fn from_str(s: &str) -> Result<Self, Self::Err> {
51 let items = s
52 .split_whitespace()
53 .map(|item| item.parse())
54 .collect::<Result<Vec<T>, T::Err>>()?;
55 Ok(AttrList(items))
56 }
57}
58
59impl<T: Display> Display for AttrList<T> {
60 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61 use itertools::Itertools;
62 write!(f, "{}", self.0.iter().join(" "))
63 }
64}