Closed duncanista closed 5 months ago
I ended up doing the following and it worked, but I'm not sure if this is the recommended solution:
// ... omitted code
fn deserialize_array<'de, D>(deserializer: D) -> Result<Option<Vec<Item>>, D::Error>
where
D: Deserializer<'de>,
{
// Deserialize the JSON value using serde_json::Value
let value: JsonValue = Deserialize::deserialize(deserializer)?;
match value {
JsonValue::String(s) => {
let values: Vec<Item> = serde_json::from_str(&s).expect("should have been serialized");
return Ok(Some(values));
}
JsonValue::Array(a) => {
let mut values = Vec::new();
for v in a {
let item: Item = serde_json::from_value(v).expect("should have been serialized");
values.push(item);
}
return Ok(Some(values));
}
_ => {
return Ok(None);
}
}
}
#[derive(Debug, PartialEq, Deserialize)]
pub struct Config {
#[serde(deserialize_with = "deserialize_array")]
pub array: Option<Vec<Item>>,
}
// This now works for both
let path = config_directory.join("config.yaml");
let figment = Figment::new()
.merge(Yaml::file(path))
.merge(Env::prefixed("APP_"));
The syntax is documented here: https://docs.rs/figment/latest/figment/providers/struct.Env.html
Dict: in the form
{key=value}
(e.g,APP_VAR={key="value",num=10}
) Array: delimited by[]
(e.g,APP_VAR=[true, 1.0, -1]
)
Combine these to get: APP_ARRAY='[{name=foo,inner_enum=First},{name=bar,inner_enum=Second}]'
Question
I'm trying to read config with both the
Yaml
andEnv
provider. I allow users to provide me a json string (which should be an array) in the environment variables. Yet, it doesn't work, because a string is received and it's not detected as a sequence.Env
provider useserde_json
when reading a custom type?This works for simpler types.
While
Would fail when loading it: