qubit_config/from/
from_config.rs1use std::collections::HashMap;
12use std::time::Duration;
13
14use bigdecimal::BigDecimal;
15use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime, Utc};
16use num_bigint::BigInt;
17use qubit_datatype::{DataConvertTo, DataConverter};
18use qubit_value::{MultiValues, Value as QubitValue};
19use serde_json::Value as JsonValue;
20use url::Url;
21
22use crate::{ConfigResult, Property, utils};
23
24use super::config_parse_context::ConfigParseContext;
25use super::helpers::first_scalar_string;
26
27pub trait FromConfig: Sized {
30 fn from_config(property: &Property, ctx: &ConfigParseContext<'_>) -> ConfigResult<Self>;
41}
42
43fn convert_first<T>(property: &Property, ctx: &ConfigParseContext<'_>) -> ConfigResult<T>
55where
56 for<'a> DataConverter<'a>: DataConvertTo<T>,
57{
58 if let Some(value) = first_scalar_string(property) {
59 let value = ctx.substitute_string(value)?;
60 QubitValue::String(value)
61 .to_with::<T>(ctx.options().conversion_options())
62 .map_err(|e| utils::map_value_error(ctx.key(), e))
63 } else {
64 property
65 .value()
66 .to_with::<T>(ctx.options().conversion_options())
67 .map_err(|e| utils::map_value_error(ctx.key(), e))
68 }
69}
70
71fn substituted_values(
87 property: &Property,
88 ctx: &ConfigParseContext<'_>,
89) -> ConfigResult<MultiValues> {
90 match property.value() {
91 MultiValues::String(values) => values
92 .iter()
93 .map(|value| ctx.substitute_string(value))
94 .collect::<ConfigResult<Vec<_>>>()
95 .map(MultiValues::String),
96 values => Ok(values.clone()),
97 }
98}
99
100macro_rules! impl_from_config_via_value {
107 ($($ty:ty),+ $(,)?) => {
108 $(
109 impl FromConfig for $ty {
110 fn from_config(
111 property: &Property,
112 ctx: &ConfigParseContext<'_>,
113 ) -> ConfigResult<Self> {
114 convert_first::<$ty>(property, ctx)
115 }
116 }
117 )+
118 };
119}
120
121impl_from_config_via_value!(
122 bool,
123 i8,
124 i16,
125 i32,
126 i64,
127 i128,
128 isize,
129 u8,
130 u16,
131 u32,
132 u64,
133 u128,
134 usize,
135 f32,
136 f64,
137 char,
138 NaiveDate,
139 NaiveTime,
140 NaiveDateTime,
141 DateTime<Utc>,
142 Duration,
143 Url,
144 BigInt,
145 BigDecimal,
146 JsonValue,
147 HashMap<String, String>,
148);
149
150impl FromConfig for String {
151 fn from_config(property: &Property, ctx: &ConfigParseContext<'_>) -> ConfigResult<Self> {
162 if let Some(value) = first_scalar_string(property) {
163 let value = ctx.substitute_string(value)?;
164 QubitValue::String(value)
165 .to_with::<String>(ctx.options().conversion_options())
166 .map_err(|e| utils::map_value_error(ctx.key(), e))
167 } else {
168 property
169 .value()
170 .to_with::<String>(ctx.options().conversion_options())
171 .map_err(|e| utils::map_value_error(ctx.key(), e))
172 }
173 }
174}
175
176impl<T> FromConfig for Vec<T>
177where
178 T: FromConfig,
179{
180 fn from_config(property: &Property, ctx: &ConfigParseContext<'_>) -> ConfigResult<Self> {
191 let values = substituted_values(property, ctx)?
192 .to_list_with::<String>(ctx.options().conversion_options())
193 .map_err(|e| utils::map_value_error(ctx.key(), e))?;
194
195 let mut result = Vec::new();
196 for item in values {
197 let item_property =
198 Property::with_value(ctx.key().to_string(), MultiValues::String(vec![item]));
199 result.push(T::from_config(&item_property, ctx)?);
200 }
201 Ok(result)
202 }
203}