Skip to main content

saluki_config/
space_separated.rs

1//! Serde deserializer for space-separated string lists.
2//!
3//! The Datadog Agent passes some list-typed configuration values as space-separated strings when
4//! using environment variables (e.g. `DD_PROXY_NO_PROXY="host1 host2"`), while the same keys
5//! appear as YAML sequences in config files. This module provides a deserializer that accepts
6//! both representations.
7
8use std::fmt;
9
10use serde::de::{self, Deserializer, SeqAccess, Visitor};
11
12/// Deserializes a `Vec<String>` from either a sequence or a space-separated string.
13pub fn deserialize_space_separated_or_seq<'de, D>(deserializer: D) -> Result<Vec<String>, D::Error>
14where
15    D: Deserializer<'de>,
16{
17    struct SpaceSeparatedOrSeq;
18
19    impl<'de> Visitor<'de> for SpaceSeparatedOrSeq {
20        type Value = Vec<String>;
21
22        fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
23            formatter.write_str("a sequence or a space-separated string")
24        }
25
26        fn visit_str<E: de::Error>(self, v: &str) -> Result<Vec<String>, E> {
27            Ok(v.split_whitespace().map(str::to_owned).collect())
28        }
29
30        fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Vec<String>, A::Error> {
31            let mut values = Vec::new();
32            while let Some(v) = seq.next_element()? {
33                values.push(v);
34            }
35            Ok(values)
36        }
37    }
38
39    deserializer.deserialize_any(SpaceSeparatedOrSeq)
40}
41
42/// Deserializes an `Option<Vec<String>>` from either a sequence or a space-separated string.
43///
44/// Pair with `#[serde(default)]` so that absent fields deserialize to `None`.
45pub fn deserialize_opt_space_separated_or_seq<'de, D>(deserializer: D) -> Result<Option<Vec<String>>, D::Error>
46where
47    D: Deserializer<'de>,
48{
49    deserialize_space_separated_or_seq(deserializer).map(Some)
50}