i3status_rs/formatting/
config.rs1use super::{Format, template::FormatTemplate};
2use crate::errors::*;
3use itertools::Itertools as _;
4use serde::de::{MapAccess, Visitor};
5use serde::{Deserialize, Deserializer, de};
6use smart_default::SmartDefault;
7use std::fmt;
8use std::str::FromStr;
9
10#[derive(Debug, Default, Clone)]
11pub struct Config {
12 pub full: Option<FormatTemplate>,
13 pub short: Option<FormatTemplate>,
14}
15
16impl Config {
17 pub fn with_default(&self, default_full: &str) -> Result<Format> {
18 self.with_defaults(default_full, "")
19 }
20
21 pub fn with_defaults(&self, default_full: &str, default_short: &str) -> Result<Format> {
22 let full = match self.full.clone() {
23 Some(full) => full,
24 None => default_full.parse()?,
25 };
26
27 let short = match self.short.clone() {
28 Some(short) => short,
29 None => default_short.parse()?,
30 };
31
32 Ok(Format::new(full, short))
33 }
34
35 pub fn with_default_config(&self, default_config: &Self) -> Format {
36 let full = self
37 .full
38 .clone()
39 .or_else(|| default_config.full.clone())
40 .unwrap_or_default();
41 let short = self
42 .short
43 .clone()
44 .or_else(|| default_config.short.clone())
45 .unwrap_or_default();
46
47 Format::new(full, short)
48 }
49
50 pub fn with_default_format(&self, default_format: &Format) -> Format {
51 let full = self
52 .full
53 .clone()
54 .unwrap_or_else(|| default_format.full.clone());
55 let short = self
56 .short
57 .clone()
58 .unwrap_or_else(|| default_format.short.clone());
59
60 Format::new(full, short)
61 }
62}
63
64impl From<Config> for Format {
65 fn from(config: Config) -> Self {
66 let full = config.full.unwrap_or_default();
67 let short = config.short.unwrap_or_default();
68
69 Format::new(full, short)
70 }
71}
72
73#[derive(Debug, Clone, SmartDefault)]
133pub enum MaybeMultiConfig {
134 #[default]
135 Split {
136 config: Option<Config>,
137 config_alt: Option<Config>,
138 },
139 Multiple {
140 configs: Vec<Config>,
141 },
142}
143
144impl MaybeMultiConfig {
145 pub fn with_default(&self, default_full: &str) -> Result<Vec<Format>> {
146 self.with_defaults(default_full, "")
147 }
148
149 pub fn with_defaults(&self, default_full: &str, default_short: &str) -> Result<Vec<Format>> {
150 Ok(match self.clone() {
151 MaybeMultiConfig::Multiple { configs } => configs
152 .into_iter()
153 .enumerate()
154 .map(|(i, config)| {
155 if i == 0 {
156 config.with_defaults(default_full, default_short)
157 } else {
158 Ok(config.into())
159 }
160 })
161 .collect::<Result<Vec<_>>>()?,
162 MaybeMultiConfig::Split { config, config_alt } => {
163 let mut formats = vec![
164 config
165 .unwrap_or_default()
166 .with_defaults(default_full, default_short)?,
167 ];
168
169 if let Some(config_alt) = config_alt {
170 formats.push(config_alt.into());
171 }
172 formats
173 }
174 })
175 }
176
177 pub fn with_default_formats(&self, default_formats: &[Format]) -> Vec<Format> {
178 match self.clone() {
179 MaybeMultiConfig::Multiple { configs } => configs,
180 MaybeMultiConfig::Split { config, config_alt } => {
181 vec![config.unwrap_or_default(), config_alt.unwrap_or_default()]
182 }
183 }
184 .into_iter()
185 .zip_longest(default_formats)
186 .filter_map(|pair| match pair {
187 itertools::EitherOrBoth::Both(config, default_format) => {
188 Some(config.with_default_format(default_format))
189 }
190 itertools::EitherOrBoth::Left(config) => Some(config.into()),
191 itertools::EitherOrBoth::Right(_) => None,
192 })
193 .collect()
194 }
195}
196
197impl FromStr for Config {
198 type Err = Error;
199
200 fn from_str(s: &str) -> Result<Self, Self::Err> {
201 Ok(Self {
202 full: Some(s.parse()?),
203 short: None,
204 })
205 }
206}
207
208impl<'de> Deserialize<'de> for Config {
209 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
210 where
211 D: Deserializer<'de>,
212 {
213 #[derive(Deserialize)]
214 #[serde(field_identifier, rename_all = "lowercase")]
215 enum Field {
216 Full,
217 Short,
218 }
219
220 struct FormatTemplateVisitor;
221
222 impl<'de> Visitor<'de> for FormatTemplateVisitor {
223 type Value = Config;
224
225 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
226 formatter.write_str("format structure")
227 }
228
229 fn visit_str<E>(self, full: &str) -> Result<Config, E>
235 where
236 E: de::Error,
237 {
238 full.parse().serde_error()
239 }
240
241 fn visit_map<V>(self, mut map: V) -> Result<Config, V::Error>
249 where
250 V: MapAccess<'de>,
251 {
252 let mut full: Option<FormatTemplate> = None;
253 let mut short: Option<FormatTemplate> = None;
254 while let Some(key) = map.next_key()? {
255 match key {
256 Field::Full => {
257 if full.is_some() {
258 return Err(de::Error::duplicate_field("full"));
259 }
260 full = Some(map.next_value::<String>()?.parse().serde_error()?);
261 }
262 Field::Short => {
263 if short.is_some() {
264 return Err(de::Error::duplicate_field("short"));
265 }
266 short = Some(map.next_value::<String>()?.parse().serde_error()?);
267 }
268 }
269 }
270 Ok(Config { full, short })
271 }
272 }
273
274 deserializer.deserialize_any(FormatTemplateVisitor)
275 }
276}
277
278impl<'de> Deserialize<'de> for MaybeMultiConfig {
279 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
280 where
281 D: Deserializer<'de>,
282 {
283 #[derive(Deserialize)]
284 #[serde(untagged)]
285 enum MaybeVecConfig {
286 Multiple(Vec<Config>),
287 Single(Config),
288 }
289
290 struct MaybeMultiConfigVisitor;
291
292 impl<'de> Visitor<'de> for MaybeMultiConfigVisitor {
293 type Value = MaybeMultiConfig;
294
295 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
296 f.write_str("multiformat structure")
297 }
298
299 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
300 where
301 A: MapAccess<'de>,
302 {
303 let mut format: Option<MaybeVecConfig> = None;
304 let mut format_alt: Option<Config> = None;
305
306 while let Some(key) = map.next_key::<String>()? {
307 match key.as_str() {
308 "format" => {
309 if format.is_some() {
310 return Err(de::Error::duplicate_field("format"));
311 }
312
313 let maybe_vec_config = match map.next_value()? {
315 serde_json::Value::Array(arr) => MaybeVecConfig::Multiple(
316 serde_json::from_value(serde_json::Value::Array(arr))
317 .serde_error()?,
318 ),
319 value => MaybeVecConfig::Single(
320 serde_json::from_value(value).serde_error()?,
321 ),
322 };
323 format = Some(maybe_vec_config);
324 }
325 "format_alt" => {
326 if format_alt.is_some() {
327 return Err(de::Error::duplicate_field("format_alt"));
328 }
329 format_alt = Some(map.next_value()?);
330 }
331 unknown => {
332 return Err(de::Error::unknown_field(
333 unknown,
334 &["format", "format_alt"],
335 ));
336 }
337 }
338 }
339
340 match format {
341 Some(MaybeVecConfig::Multiple(configs)) => {
342 if format_alt.is_some() {
343 return Err(de::Error::custom(
344 "data did not match any variant of untagged enum MaybeMultiConfig",
345 ));
346 }
347 if configs.is_empty() {
348 return Err(de::Error::custom(
349 "An empty list of configs is not allowed",
350 ));
351 }
352 Ok(MaybeMultiConfig::Multiple { configs })
353 }
354 Some(MaybeVecConfig::Single(config)) => Ok(MaybeMultiConfig::Split {
355 config: Some(config),
356 config_alt: format_alt,
357 }),
358 None => Ok(MaybeMultiConfig::Split {
359 config: None,
360 config_alt: format_alt,
361 }),
362 }
363 }
364 }
365
366 deserializer.deserialize_map(MaybeMultiConfigVisitor)
367 }
368}