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!("Property holds no value to convert to ", stringify!($ty)))),
51 1 => {
52 let value = values.iter().next().expect("one value");
53 value.parse::<$ty>()
54 .map_err(|e| Error::new(ErrorKind::InvalidProp)
55 .with_description(format!(concat!("Failed to parse property value {:?} as ", stringify!($ty)), value))
56 .with_source(Box::new(e)))
57 }
58 n @ 2.. => Err(Error::new(ErrorKind::InvalidProp)
59 .with_description(format!(concat!("Property holds {} values where one ", stringify!($ty), " was expected"), n))),
60 }
61 }
62 }
63
64 impl FromProp for Vec<$ty> {
65 fn from_prop(values: &Spectrum<str>) -> Result<Self> {
66 let mut ret = Vec::with_capacity(values.len());
67 for val in values.iter() {
68 ret.push(val.parse::<$ty>()
69 .map_err(|e| Error::new(ErrorKind::InvalidProp)
70 .with_description(format!(concat!("Failed to parse property value {:?} as ", stringify!($ty)), val))
71 .with_source(Box::new(e)))?);
72 }
73 Ok(ret)
74 }
75 }
76
77 };
78}
79
80impl_prop_for_parse!(bool);
81impl_prop_for_parse!(u8);
82impl_prop_for_parse!(i8);
83impl_prop_for_parse!(u16);
84impl_prop_for_parse!(i16);
85impl_prop_for_parse!(u32);
86impl_prop_for_parse!(i32);
87impl_prop_for_parse!(u64);
88impl_prop_for_parse!(i64);
89impl_prop_for_parse!(f32);
90impl_prop_for_parse!(f64);
91
92impl<'d> IntoProp<'d> for Cow<'d, str> {
97 fn into_prop(self) -> impl IntoIterator<Item = Cow<'d, str>> {
98 Some(self)
99 }
100}
101
102impl<'d> IntoProp<'d> for &'d str {
103 fn into_prop(self) -> impl IntoIterator<Item = Cow<'d, str>> {
104 Cow::<str>::Borrowed(self).into_prop()
105 }
106}
107
108impl<'d> IntoProp<'d> for String {
109 fn into_prop(self) -> impl IntoIterator<Item = Cow<'d, str>> {
110 Cow::<str>::Owned(self).into_prop()
111 }
112}
113
114impl<'d> IntoProp<'d> for Vec<String> {
115 fn into_prop(self) -> impl IntoIterator<Item = Cow<'d, str>> {
116 self.into_iter().map(Cow::Owned)
117 }
118}
119
120impl<'d> IntoProp<'d> for &'d String {
121 fn into_prop(self) -> impl IntoIterator<Item = Cow<'d, str>> {
122 Cow::<str>::Borrowed(self).into_prop()
123 }
124}
125
126impl FromProp for String {
127 fn from_prop(values: &Spectrum<str>) -> Result<Self> {
128 let mut buf = String::new();
129 for val in values.iter() {
130 if !buf.is_empty() {
131 buf.push('\n');
132 }
133 buf.push_str(val);
134 }
135 Ok(buf)
136 }
137}
138
139impl FromProp for Vec<String> {
140 fn from_prop(values: &Spectrum<str>) -> Result<Self> {
141 Ok(values.iter().map(str::to_string).collect())
142 }
143}
144
145impl FromProp for Spectrum<str> {
147 fn from_prop(values: &Spectrum<str>) -> Result<Self> {
148 Ok(values.clone())
149 }
150}