Crate envoke

Source
Expand description

§envoke

Useful links

§Attributes

Container attributes apply to the whole struct influencing the behavior of the entire structure. Field attributes are applied to individual fields within struct, providing fine-grained control over how each field is processed. Both types of attributes allow for customizing how data is loaded, transformed, or handled.


§Container

Below are the current implemented container attributes. This list will be updated as more are added or changed.

AttributeDefaultDescription
prefixNoneSet a custom prefix which will be prepended infront of environment variables before fetching
suffixNoneSet a custom prefix which will be appended infront of environment variables before fetching
delimiterNoneSet a customer delimiter used for separated prefix, environment variable, and suffix. NB! If you are using the rename_all attribute as well it will take priority over the delimiter. It can still be useful to include the delimiter to ensure the prefix, environment variable, and suffix are separated before renaming occurs otherwise they will be interpreted as a single word!
rename_allNoneRename all environment variables to a different naming case. See name cases for a full list and description of the different options.

§Naming cases
CaseValueDescription
Lower caselowercase or lowerConverts all characters to lowercase and removes binding characters
Upper caseUPPERCASE or UPPERConverts all characters to uppercase and removes binding characters
Pascal casePascalCaseCapitalizes the first letter of each word and removes binding
Camel casecamelCaseLowercases the first letter but capitalizes the first letter of subsequent words while removing binding characters
Snake casesnake_caseConverts names to lowercase and uses underscores _ to separate words
Screaming snake caseSCREAMING_SNAKE_CASEConverts names to uppercase and uses underscores _ to separate words
Kebab casekebab-caseConverts names to lowercase and uses hyphens - to separate words
Screaming kebab caseSCREAMING-KEBAB-CASEConverts names to uppercase and uses hyphens - to separate words

§Field

Below are the current implemented field attributes. This list will be updated as more are added or changed.

AttributeDefaultDescription
envNoneEnvironment variable name to load the field value from. Can be chained multiple times to allow for fallbacks. The macro follows a first come, first serve basis meaning it attempts to load the variables in the order they are listed. Once an value is found it will try to parse it into the specified type. If it fails it will return an error and wont try the remaining ones in the list. This behavior might change in the future. Optionally, you can supply your own parsing function. See parse_fn for more information!
defaultNoneUse the default value if the environment variable is not found. Optionally to statically assign a value to the field env can be omitted.
parse_fnNoneSet a custom parsing function for parsing the retrieved value before assigning it to the field. This can be useful when the fields type does not implement the FromStr trait. Requires arg_type to be set
arg_typeNoneSpecify the argument type which the parse_fn function requires. As I don’t know if it is possible to find the type automatically this argument is required such that the environment variable value can be parsed into the expected type first before being set as the argument in the function call.
validate_fnNoneSet a custom validation function for ensuring the loaded value meets expectations. Note validate_fn supports both direct assignment and parentheses assignments. See example
delimiterComma (,)Used when parsing environment variable which is a stringified map or set. The delimiter specifies the boundary between values.
no_prefixFalseDisable adding the global prefix to this environment variable. This will also remove the delimiter that wouldn’t normally be between the environment variable and prefix
no_suffixFalseDisable adding the global suffix to this environment variable. This will also remove the delimiter that wouldn’t normally be between the environment variable and suffix
nestedFalseIndicate that the field is a struct. Required when the field type is another struct

§Examples


The simplest example of loading environment variable into a struct is

use envoke::Envoke;

#[derive(Fill)]
#[fill(rename_all = "UPPERCASE")]
struct Environment {
    #[fill(env)]
    field: String,
}

fn main() {
    let env = Environment::envoke();
}

It can also be used similar to the standard trait Default

use envoke::Envoke;

#[derive(Fill)]
#[fill(rename_all = "UPPERCASE")]
struct Environment {
    #[fill(env)]
    field1: String,

    #[fill(env)]
    field2: String,
}

fn main() {
    let env = Environment {
        field1: "Hello, User!".to_string(),
        ..Envoke::envoke()
    };
}

Multiple environment variable names can be chained in a row to add fallbacks

use envoke::Envoke;

#[derive(Fill)]
#[fill(rename_all = "UPPERCASE")]
struct Environment {
    #[fill(env, env = "FALLBACK1", env = "FALLBACK2")]
    field: String,
}

fn main() {
    let env = Environment::envoke();
}

The environment variables will be loaded in the order they are defined. One the first successful load it will be parsed and set as the fields value. If the parsing fails the macro will return an error and not retry the other variables. This behavior might change in the future!

Note that just supplying env means just use the field name as the environment variable name and is not required.


To use enums we recommend using the strum crate as such

use envoke::Envoke;

#[derive(strum::EnumString)]
#[strum(serialize_all = "lowercase")]
enum Level {
    Info,
    Warn,
    Error,
}

#[derive(Fill)]
#[fill(rename_all = "UPPERCASE")]
struct Environment {
    #[fill(env)]
    level: Level,
}

fn main() {
    let env = Environment::envoke();
}

Behind the scenes it is required for the type to bet set implements the FromStr trait. Although this can be omitted by implementing a custom parsing function

use std::time::Duration;

use envoke::Envoke;

fn to_time(sec: u64) -> Duration {
    Duration::from_secs(sec)
}

#[derive(Fill)]
#[fill(rename_all = "UPPERCASE")]
struct Environment {
    #[fill(env, parse_fn = to_time, arg_type = u64)]
    dur: Duration,
}

fn main() {
    let env = Environment::envoke();
}

Default fallbacks can also be added, or used alone

use envoke::Envoke;

#[derive(Fill)]
#[fill(rename_all = "UPPERCASE")]
struct Environment {
    #[fill(env, default)]
    field: String,
}

fn main() {
    let env = Environment::envoke();
}

Default can be used alone which will load the field types default value, supports direct value assignment, and a function call which returns the fields type


Field can also be validated before and/or after parsing. Note that if you do not specify where the validation should occur; before or after parsing. It will automatically be called after parsing. Both cases can be seen in the example below

use envoke::{Envoke, Fill};

fn less_than_ten_opt(amount: &Option<u64>) -> std::result::Result<(), String> {
    if let Some(amount) = amount {
        if *amount > 10 {
            return Err("amount should be less than 10".to_string());
        }
    }

    Ok(())
}

fn more_than_ten_opt(amount: &Option<u64>) -> std::result::Result<(), String> {
    if let Some(amount) = amount {
        if *amount < 10 {
            return Err("amount should be more than 10".to_string());
        }
    }

    Ok(())
}

fn more_than_ten(amount: &u64) -> std::result::Result<(), String> {
    match *amount > 10 {
        true => Ok(()),
        false => Err("amount should be more than 10".to_string()),
    }
}

fn add_ten_opt(amount: Option<u64>) -> Option<u64> {
    amount.and_then(|x| Some(x + 10))
}

fn add_ten(amount: u64) -> u64 {
    amount + 10
}

#[derive(Fill)]
struct Example {
    #[fill(env = "TEST_ENV", parse_fn = add_ten_opt, arg_type = Option<u64>, validate_fn(before = less_than_ten_opt, after = more_than_ten_opt))]
    field1: Option<u64>,

    #[fill(env = "TEST_ENV", parse_fn = add_ten, arg_type = u64, validate_fn = more_than_ten)]
    field2: u64,
}

fn main() {
    let env = Environment::envoke();
}

There are more container-/field attributes not mentioned here so take a look at them! They are designed to be used together for both simple and complex environment loading. If there are any attributes you feel are missing open an issue on our github page and we’ll take a look at is as soon as possible!


§License
Licensed under either of Apache License, Version 2.0 or MIT license at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Traits§

Envoke