zng_ext_config/
toml.rs
1use super::*;
2
3use ::toml as serde_toml;
4
5impl ConfigMap for indexmap::IndexMap<ConfigKey, serde_toml::Value> {
6 fn empty() -> Self {
7 Self::new()
8 }
9
10 fn read(mut file: WatchFile) -> io::Result<Self> {
11 file.toml()
12 }
13
14 fn write(self, file: &mut WriteFile) -> io::Result<()> {
15 if self.is_empty() {
16 file.write_text("#")
19 } else {
20 file.write_toml(&self, true)
21 }
22 }
23
24 fn get_raw(&self, key: &ConfigKey) -> Result<Option<RawConfigValue>, Arc<dyn std::error::Error + Send + Sync>> {
25 match self.get(key) {
26 Some(e) => Ok(Some(RawConfigValue::try_from(e.clone())?)),
27 None => Ok(None),
28 }
29 }
30
31 fn set_raw(map: &mut VarModify<Self>, key: ConfigKey, value: RawConfigValue) -> Result<(), Arc<dyn std::error::Error + Send + Sync>> {
32 let value = value.try_into()?;
33 if map.get(&key) != Some(&value) {
34 map.to_mut().insert(key, value);
35 }
36 Ok(())
37 }
38
39 fn contains_key(&self, key: &ConfigKey) -> bool {
40 self.contains_key(key)
41 }
42
43 fn get<O: ConfigValue>(&self, key: &ConfigKey) -> Result<Option<O>, Arc<dyn std::error::Error + Send + Sync>> {
44 if let Some(value) = self.get(key) {
45 match serde_toml::to_string(&value) {
46 Ok(value) => match serde_toml::from_str(&value) {
47 Ok(value) => Ok(Some(value)),
48 Err(e) => Err(Arc::new(e)),
49 },
50 Err(e) => Err(Arc::new(e)),
51 }
52 } else {
53 Ok(None)
54 }
55 }
56
57 fn set<O: ConfigValue>(map: &mut VarModify<Self>, key: ConfigKey, value: O) -> Result<(), Arc<dyn std::error::Error + Send + Sync>> {
58 match serde_toml::to_string(&value) {
59 Ok(value) => match serde_toml::from_str(&value) {
60 Ok(value) => {
61 if map.get(&key) != Some(&value) {
62 map.to_mut().insert(key, value);
63 }
64 Ok(())
65 }
66 Err(e) => Err(Arc::new(e)),
67 },
68 Err(e) => Err(Arc::new(e)),
69 }
70 }
71
72 fn remove(map: &mut VarModify<Self>, key: &ConfigKey) {
73 if map.contains_key(key) {
74 map.to_mut().shift_remove(key);
75 }
76 }
77}
78
79pub type TomlConfig = SyncConfig<indexmap::IndexMap<ConfigKey, serde_toml::Value>>;
81
82impl TryFrom<serde_toml::Value> for RawConfigValue {
83 type Error = TomlValueRawError;
84
85 fn try_from(value: serde_toml::Value) -> Result<Self, Self::Error> {
86 let ok = match value {
87 serde_toml::Value::String(s) => serde_json::Value::String(s),
88 serde_toml::Value::Integer(n) => serde_json::Value::Number(n.into()),
89 serde_toml::Value::Float(f) => match serde_json::Number::from_f64(f) {
90 Some(f) => serde_json::Value::Number(f),
91 None => return Err(TomlValueRawError::InvalidFloat(f)),
92 },
93 serde_toml::Value::Boolean(b) => serde_json::Value::Bool(b),
94 serde_toml::Value::Datetime(d) => serde_json::Value::String(d.to_string()),
95 serde_toml::Value::Array(a) => serde_json::Value::Array({
96 let mut r = Vec::with_capacity(a.len());
97 for v in a {
98 r.push(RawConfigValue::try_from(v)?.0);
99 }
100 r
101 }),
102 serde_toml::Value::Table(m) => serde_json::Value::Object({
103 let mut r = serde_json::Map::with_capacity(m.len());
104 for (k, v) in m {
105 r.insert(k, RawConfigValue::try_from(v)?.0);
106 }
107 r
108 }),
109 };
110 Ok(Self(ok))
111 }
112}
113impl TryFrom<RawConfigValue> for serde_toml::Value {
114 type Error = TomlValueRawError;
115
116 fn try_from(value: RawConfigValue) -> Result<Self, Self::Error> {
117 let ok = match value.0 {
118 serde_json::Value::Null => return Err(TomlValueRawError::Null),
119 serde_json::Value::Bool(b) => serde_toml::Value::Boolean(b),
120 serde_json::Value::Number(n) => {
121 if let Some(n) = n.as_i64() {
123 serde_toml::Value::Integer(n)
124 } else if let Some(n) = n.as_u64() {
125 if n > i64::MAX as u64 {
126 return Err(TomlValueRawError::InvalidInt(n));
127 }
128 serde_toml::Value::Integer(n as i64)
129 } else if let Some(n) = n.as_f64() {
130 serde_toml::Value::Float(n)
131 } else {
132 unreachable!()
133 }
134 }
135 serde_json::Value::String(s) => serde_toml::Value::String(s),
136 serde_json::Value::Array(a) => serde_toml::Value::Array({
137 let mut r = Vec::with_capacity(a.len());
138 for v in a {
139 match RawConfigValue(v).try_into() {
140 Ok(v) => r.push(v),
141 Err(TomlValueRawError::Null) => continue,
142 e => return e,
143 }
144 }
145 r
146 }),
147 serde_json::Value::Object(m) => serde_toml::Value::Table({
148 let mut r = serde_toml::Table::with_capacity(m.len());
149 for (k, v) in m {
150 match RawConfigValue(v).try_into() {
151 Ok(v) => {
152 r.insert(k, v);
153 }
154 Err(TomlValueRawError::Null) => continue,
155 e => return e,
156 }
157 }
158 r
159 }),
160 };
161 Ok(ok)
162 }
163}
164
165#[derive(Debug, Clone, Copy)]
167pub enum TomlValueRawError {
168 InvalidFloat(f64),
170 Null,
172 InvalidInt(u64),
174}
175impl fmt::Display for TomlValueRawError {
176 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177 match self {
178 TomlValueRawError::InvalidFloat(fl) => write!(f, "json does not support float `{fl}`"),
179 TomlValueRawError::Null => write!(f, "toml does not support `null`"),
180 TomlValueRawError::InvalidInt(i) => write!(f, "toml does not support int > i64::MAX ({i})"),
181 }
182 }
183}
184impl std::error::Error for TomlValueRawError {}
185impl From<TomlValueRawError> for Arc<dyn std::error::Error + Send + Sync> {
186 fn from(value: TomlValueRawError) -> Self {
187 Arc::new(value)
188 }
189}