Attribute Macro serde_env_field::env_field_wrap
source · #[env_field_wrap]
Expand description
The env_field_wrap
wraps all the fields of a struct or an enum with the EnvField
type.
The Option<T>
fields will remain optional, with only the T
type wrapped with the EnvField
.
Similarly, the Vec<T>
fields will remain vectors, with only the T
type wrapped.
It is possible to skip a field using the #[env_field_wrap(skip)]
attribute.
The fields that already have the EnvField
type skipped automatically.
Also, one can wrap a generic type similarly to an Option
field
using the #[env_field_wrap(generics_only)]
attribute.
NOTE: If you are using the #[derive(Deserialize)]
,
the #[env_field_wrap]
attribute must appear before it.
Otherwise, it won’t work.
Examples
Basic
#[env_field_wrap]
#[derive(Serialize, Deserialize)]
struct Example {
name: String,
size: usize,
num: i32,
}
std::env::set_var("SIZE", "100");
let de: Example = toml::from_str(r#"
name = "${NAME:-Default Name}"
size = "$SIZE"
num = 42
"#).unwrap();
assert_eq!(&de.name, "Default Name");
assert_eq!(de.size, 100);
assert_eq!(de.num, 42);
Optional fields
#[env_field_wrap]
#[derive(Serialize, Deserialize)]
struct Example {
required: i32,
optional: Option<i32>,
}
let de: Example = toml::from_str(r#"
required = 512
"#).unwrap();
assert_eq!(de.required, 512);
assert!(de.optional.is_none());
std::env::set_var("OPTIONAL", "-1024");
let de: Example = toml::from_str(r#"
required = 512
optional = "$OPTIONAL"
"#).unwrap();
assert_eq!(de.required, 512);
assert_eq!(de.optional.unwrap(), -1024);
let de: Example = toml::from_str(r#"
required = 512
optional = 42
"#).unwrap();
assert_eq!(de.required, 512);
assert_eq!(de.optional.unwrap(), 42);
Vector fields
#[env_field_wrap]
#[derive(Serialize, Deserialize)]
struct Example {
seq: Vec<i32>,
}
std::env::set_var("NUM", "1000");
let de: Example = toml::from_str(r#"
seq = [
12, "$NUM", 145,
]
"#).unwrap();
assert_eq!(de.seq[0], 12);
assert_eq!(de.seq[1], 1000);
assert_eq!(de.seq[2], 145);
Skip a field
#[env_field_wrap]
#[derive(Serialize, Deserialize)]
struct Example {
wrapped: String,
#[env_field_wrap(skip)]
skipped: String,
}
std::env::set_var("WRAPPED", "From Env");
let de: Example = toml::from_str(r#"
wrapped = "$WRAPPED"
skipped = "$SKIPPED"
"#).unwrap();
assert_eq!(&de.wrapped, "From Env");
assert_eq!(&de.skipped, "$SKIPPED");
Skip an enum variant
#[env_field_wrap]
#[derive(Serialize, Deserialize)]
enum Example {
Wrapped(String),
#[env_field_wrap(skip)]
Skipped {
inner_str: String,
},
}
std::env::set_var("WRAPPED", "From Env");
let de: Example = serde_json::from_str(r#"
{
"Wrapped": "$WRAPPED"
}
"#).unwrap();
assert!(matches![de, Example::Wrapped(s) if &s == "From Env"]);
let de: Example = serde_json::from_str(r#"
{
"Skipped": {
"inner_str": "$WRAPPED"
}
}
"#).unwrap();
assert!(matches![de, Example::Skipped { inner_str } if inner_str == "$WRAPPED"]);
Wrap generics only
#[env_field_wrap]
#[derive(Serialize, Deserialize)]
struct Example {
// Will become
// `Generics<EnvField<String>, EnvField<i32>, EnvField<Variants, UseDeserialize>>`
// instead of
// `EnvField<Generics<String, i32, EnvField<Variants, UseDeserialize>>>`.
//
// Note:
// * if a generic is already wrapped into the `EnvField`, it *won't* be wrapped again.
// * the `Generics` don't need to implement the `FromStr` in this case.
#[env_field_wrap(generics_only)]
generics: Generics<String, i32, EnvField<Variants, UseDeserialize>>,
}
#[derive(Serialize, Deserialize)]
struct Generics<A, B, C> {
a: A,
b: B,
c: C,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "kebab-case")]
enum Variants {
FirstVariant,
SecondVariant,
}
std::env::set_var("GENERICS_STR", "env string");
std::env::set_var("GENERICS_I32", "517");
std::env::set_var("GENERICS_VARIANT", "first-variant");
let de: Example = toml::from_str(r#"
[generics]
a = "$GENERICS_STR"
b = "$GENERICS_I32"
c = "$GENERICS_VARIANT"
"#).unwrap();
assert_eq!(&de.generics.a, "env string");
assert_eq!(de.generics.b, 517);
assert!(matches!(*de.generics.c, Variants::FirstVariant));