Skip to main content

tanzim_source/
impls.rs

1//! [`From`] and [`TryFrom`] conversions for [`Source`], [`SourceBuilder`], and [`OptionValue`].
2
3use crate::{Error, OptionValue, Options, ParseError, Source, SourceBuilder};
4use std::borrow::Cow;
5use std::collections::HashMap;
6
7impl From<Source> for SourceBuilder {
8    fn from(value: Source) -> Self {
9        Self {
10            source: Some(value.source().to_string()),
11            options: value.options().clone(),
12            resource: value.resource().to_string(),
13            ignore_errors: value.ignore_errors(),
14            resource_colon: value.resource_colon(),
15        }
16    }
17}
18
19impl TryFrom<&str> for SourceBuilder {
20    type Error = Error;
21
22    fn try_from(value: &str) -> Result<Self, Self::Error> {
23        Ok(Source::parse(value)?.into())
24    }
25}
26
27impl TryFrom<String> for SourceBuilder {
28    type Error = Error;
29
30    fn try_from(value: String) -> Result<Self, Self::Error> {
31        Self::try_from(value.as_str())
32    }
33}
34
35impl TryFrom<&String> for SourceBuilder {
36    type Error = Error;
37
38    fn try_from(value: &String) -> Result<Self, Self::Error> {
39        Self::try_from(value.as_str())
40    }
41}
42
43impl TryFrom<Cow<'_, str>> for SourceBuilder {
44    type Error = Error;
45
46    fn try_from(value: Cow<'_, str>) -> Result<Self, Self::Error> {
47        Self::try_from(value.as_ref())
48    }
49}
50
51impl From<bool> for OptionValue {
52    fn from(value: bool) -> Self {
53        Self::Bool(value)
54    }
55}
56
57impl From<i64> for OptionValue {
58    fn from(value: i64) -> Self {
59        Self::Integer(value)
60    }
61}
62
63impl From<i32> for OptionValue {
64    fn from(value: i32) -> Self {
65        Self::Integer(value as i64)
66    }
67}
68
69impl From<i16> for OptionValue {
70    fn from(value: i16) -> Self {
71        Self::Integer(value as i64)
72    }
73}
74
75impl From<i8> for OptionValue {
76    fn from(value: i8) -> Self {
77        Self::Integer(value as i64)
78    }
79}
80
81impl From<u64> for OptionValue {
82    fn from(value: u64) -> Self {
83        Self::Integer(value as i64)
84    }
85}
86
87impl From<u32> for OptionValue {
88    fn from(value: u32) -> Self {
89        Self::Integer(value as i64)
90    }
91}
92
93impl From<u16> for OptionValue {
94    fn from(value: u16) -> Self {
95        Self::Integer(value as i64)
96    }
97}
98
99impl From<u8> for OptionValue {
100    fn from(value: u8) -> Self {
101        Self::Integer(value as i64)
102    }
103}
104
105impl From<isize> for OptionValue {
106    fn from(value: isize) -> Self {
107        Self::Integer(value as i64)
108    }
109}
110
111impl From<usize> for OptionValue {
112    fn from(value: usize) -> Self {
113        Self::Integer(value as i64)
114    }
115}
116
117impl From<f64> for OptionValue {
118    fn from(value: f64) -> Self {
119        Self::Float(value)
120    }
121}
122
123impl From<f32> for OptionValue {
124    fn from(value: f32) -> Self {
125        Self::Float(value as f64)
126    }
127}
128
129impl From<&str> for OptionValue {
130    fn from(value: &str) -> Self {
131        Self::String(value.to_string())
132    }
133}
134
135impl From<String> for OptionValue {
136    fn from(value: String) -> Self {
137        Self::String(value)
138    }
139}
140
141impl From<&String> for OptionValue {
142    fn from(value: &String) -> Self {
143        Self::String(value.clone())
144    }
145}
146
147impl<T: Into<OptionValue>> From<Vec<T>> for OptionValue {
148    fn from(value: Vec<T>) -> Self {
149        Self::List(value.into_iter().map(Into::into).collect())
150    }
151}
152
153impl<T: Into<OptionValue> + Clone> From<&[T]> for OptionValue {
154    fn from(value: &[T]) -> Self {
155        Self::List(value.iter().cloned().map(Into::into).collect())
156    }
157}
158
159impl From<Options> for OptionValue {
160    fn from(value: Options) -> Self {
161        Self::Map(value)
162    }
163}
164
165impl<K: Into<String>, V: Into<OptionValue>> From<HashMap<K, V>> for OptionValue {
166    fn from(value: HashMap<K, V>) -> Self {
167        let mut options = Options::default();
168        for (key, value) in value {
169            options.insert(key, value);
170        }
171        Self::Map(options)
172    }
173}
174
175impl std::str::FromStr for Source {
176    type Err = ParseError;
177
178    fn from_str(value: &str) -> Result<Self, Self::Err> {
179        Self::parse(value)
180    }
181}
182
183impl TryFrom<&str> for Source {
184    type Error = ParseError;
185
186    fn try_from(value: &str) -> Result<Self, Self::Error> {
187        Self::parse(value)
188    }
189}
190
191impl TryFrom<String> for Source {
192    type Error = ParseError;
193
194    fn try_from(value: String) -> Result<Self, Self::Error> {
195        Self::parse(&value)
196    }
197}
198
199impl TryFrom<&String> for Source {
200    type Error = ParseError;
201
202    fn try_from(value: &String) -> Result<Self, Self::Error> {
203        Self::parse(value)
204    }
205}
206
207impl TryFrom<Cow<'_, str>> for Source {
208    type Error = ParseError;
209
210    fn try_from(value: Cow<'_, str>) -> Result<Self, Self::Error> {
211        Self::parse(&value)
212    }
213}
214
215#[cfg(test)]
216mod tests {
217    use super::*;
218    use std::convert::TryFrom;
219
220    #[test]
221    fn try_from_str() {
222        let source = Source::try_from("file:/tmp/x").unwrap();
223        assert_eq!(source.resource(), "/tmp/x");
224    }
225
226    #[test]
227    fn builder_try_from_str() {
228        let builder = SourceBuilder::try_from("env(prefix=APP_)").unwrap();
229        let source = builder.build().unwrap();
230        assert_eq!(source.source(), "env");
231        assert_eq!(
232            source.options().get("prefix"),
233            Some(&OptionValue::String("APP_".into()))
234        );
235    }
236
237    #[test]
238    fn builder_try_from_invalid_is_parse_error() {
239        let error = SourceBuilder::try_from("env(prefix=)").unwrap_err();
240        assert!(matches!(error, Error::Parse(ParseError::EmptyValue { .. })));
241    }
242}