envious
allows you to deserialize your serde enabled structs from
environment variables.
See it in action:
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
enum StaircaseOrientation {
Left,
Right,
}
#[derive(Serialize, Deserialize, Debug)]
struct Config {
target_temp: f32,
automate_doors: bool,
staircase_orientation: StaircaseOrientation,
}
let config: Config = envious::from_env(envious::Prefix::None).expect("Could not deserialize from env");
With the following environment variables:
EXPORT target_temp=25.0
EXPORT automate_doors=true
EXPORT staircase_orientation=Left
it will parse it from the environment and give you a Rust struct you can use in your application.
Note: The environment variables are case sensitive! This is due to how
serde
works internally. If you want your structs to use SCREAMING_SNAKE_CASE, then be sure to use the#[serde(rename_all = "SCREAMING_SNAKE_CASE"]
annotation on all concerned structs.
To use envious
simply add it to your Cargo.toml
with:
cargo add envious
and deserialize from your environment with envious::from_env
!
- Tuple Enum Variants can currently not be longer than one element!
- Ordering of arrays is highly sensitive to environment order
- No ordering is currently done, and the ordering depends on how the operating system propagates variables
The mapping between environment variables and the serde model is as follows:
For example, if you have the following struct:
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
struct Radiator {
min_temp: f32,
max_temp: f32,
}
#[derive(Serialize, Deserialize)]
struct Config {
target_temp: f32,
radiator: Option<Radiator>
}
You can deserialize Config
with the following variables:
export target_temp=21.0
export radiator__min_temp=15.0
export radiator__max_temp=30.0
Arrays are represented as anonymous structs, with the 'fields' being the individual elements.
A more complex example could look like this:
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
enum Material {
Wood,
Plastic,
}
#[derive(Serialize, Deserialize)]
struct Door {
width: f32,
height: f32,
material: Material,
}
#[derive(Serialize, Deserialize)]
struct House {
age: u32,
entrance_doors: Vec<Door>,
}
Now, to deserialize a House
we can set the following variables:
export age=120
export entrance_doors__0__width=100
export entrance_doors__0__height=100
export entrance_doors__0__material="Wood"
export entrance_doors__1__width=200
export entrance_doors__1__height=120
export entrance_doors__1__material="Plastic"
export entrance_doors__foo__width=400
export entrance_doors__foo__height=20
export entrance_doors__foo__material="Plastic"
As you can see, the individual 'keys' of the array do not matter! The same key refers to the same object though.
As you can see in the example above, the Material
enum gets simply deserialized from the name of the variant. Be careful about upper/lower case Serde expects per-default that the case is exactly the same!
Per default serde
uses external tagging for more complicated enum variants.
Tuple enums are currently only supported with a single value.
To see what this means, lets take this enum as an example:
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
enum Shape {
Rectangle { width: f32, height: f32 },
Circle(f32),
Nothing,
}
#[derive(Serialize, Deserialize)]
struct Config {
expected_shape: Shape,
}
To deserialize Config
here, we can use the following variables:
export expected_shape__Rectangle__width=50.0
export expected_shape__Rectangle__height=10.0
// OR
export expected_shape__Circle=15.0
// OR
export expected_shape=Nothing
Any of these sets of variables would give you the expected outcome.
Should you change the tagging of your struct, be sure to adapt the given variables.
envious
is licensed under MIT or Apache 2.0, as you wish.
To contribute to envious
you can:
- Open up issues with ideas, remarks, bug reports, etc...
- Fork and implement new features and send them in as pull requests
- Leave it a Star and spread the word! ;)