1use std::borrow::Cow;
7
8use crate::error::{Result, Error, ErrorKind};
9use crate::value::Spectrum;
10
11
12pub trait IntoProp<'d> {
14 fn into_prop(self) -> impl IntoIterator<Item = Cow<'d, str>>;
17}
18
19pub trait FromProp: Sized {
21 fn from_prop(values: &Spectrum<str>) -> Result<Self>;
23}
24
25macro_rules! impl_prop_for_parse {
30 ( $ty:ty ) => {
31
32 impl<'d> IntoProp<'d> for $ty {
33 #[inline]
34 fn into_prop(self) -> impl IntoIterator<Item = Cow<'d, str>> {
35 Some(Cow::<str>::Owned(format!("{self}")))
36 }
37 }
38
39 impl<'d> IntoProp<'d> for &'_ $ty {
40 #[inline]
41 fn into_prop(self) -> impl IntoIterator<Item = Cow<'d, str>> {
42 (*self).into_prop()
43 }
44 }
45
46 impl FromProp for $ty {
47 fn from_prop(values: &Spectrum<str>) -> Result<Self> {
48 match values.len() {
49 0 => Err(Error::new(ErrorKind::InvalidProp)
50 .with_description(concat!("No value in the property, could not convert it to ", stringify!($ty)))),
51 1 => values.iter().next().expect("one value").parse::<$ty>()
52 .map_err(|e| Error::new(ErrorKind::InvalidProp)
53 .with_description(concat!("Failed to parse property value to ", stringify!($ty)))
54 .with_source(Box::new(e))),
55 2.. => Err(Error::new(ErrorKind::InvalidProp)
56 .with_description(concat!("More than one value in the property, could not convert it to ", stringify!($ty)))),
57 }
58 }
59 }
60
61 impl FromProp for Vec<$ty> {
62 fn from_prop(values: &Spectrum<str>) -> Result<Self> {
63 let mut ret = Vec::with_capacity(values.len());
64 for val in values.iter() {
65 ret.push(val.parse::<$ty>()
66 .map_err(|e| Error::new(ErrorKind::InvalidProp)
67 .with_description(concat!("Failed to parse property value to ", stringify!($ty)))
68 .with_source(Box::new(e)))?);
69 }
70 Ok(ret)
71 }
72 }
73
74 };
75}
76
77impl_prop_for_parse!(bool);
78impl_prop_for_parse!(u8);
79impl_prop_for_parse!(i8);
80impl_prop_for_parse!(u16);
81impl_prop_for_parse!(i16);
82impl_prop_for_parse!(u32);
83impl_prop_for_parse!(i32);
84impl_prop_for_parse!(u64);
85impl_prop_for_parse!(i64);
86impl_prop_for_parse!(f32);
87impl_prop_for_parse!(f64);
88
89impl<'d> IntoProp<'d> for Cow<'d, str> {
94 fn into_prop(self) -> impl IntoIterator<Item = Cow<'d, str>> {
95 Some(self)
96 }
97}
98
99impl<'d> IntoProp<'d> for &'d str {
100 fn into_prop(self) -> impl IntoIterator<Item = Cow<'d, str>> {
101 Cow::<str>::Borrowed(self).into_prop()
102 }
103}
104
105impl<'d> IntoProp<'d> for String {
106 fn into_prop(self) -> impl IntoIterator<Item = Cow<'d, str>> {
107 Cow::<str>::Owned(self).into_prop()
108 }
109}
110
111impl<'d> IntoProp<'d> for Vec<String> {
112 fn into_prop(self) -> impl IntoIterator<Item = Cow<'d, str>> {
113 self.into_iter().map(Cow::Owned)
114 }
115}
116
117impl<'d> IntoProp<'d> for &'d String {
118 fn into_prop(self) -> impl IntoIterator<Item = Cow<'d, str>> {
119 Cow::<str>::Borrowed(self).into_prop()
120 }
121}
122
123impl FromProp for String {
124 fn from_prop(values: &Spectrum<str>) -> Result<Self> {
125 let mut buf = String::new();
126 for val in values.iter() {
127 if !buf.is_empty() {
128 buf.push('\n');
129 }
130 buf.push_str(val);
131 }
132 Ok(buf)
133 }
134}
135
136impl FromProp for Vec<String> {
137 fn from_prop(values: &Spectrum<str>) -> Result<Self> {
138 Ok(values.iter().map(str::to_string).collect())
139 }
140}
141
142impl FromProp for Spectrum<str> {
144 fn from_prop(values: &Spectrum<str>) -> Result<Self> {
145 Ok(values.clone())
146 }
147}