Crate env_config

Source
Expand description

Adds proc macro that adds methods to parse environment variables and write documentation using doc-writer.

§Examples

#![allow(dead_code)]

use doc_writer::DocumentationWriter;
use env_config::EnvConfig;
use std::error::Error;
use std::str::FromStr;
use std::{env, io};

#[derive(EnvConfig)]
#[env(prefix = "SERVER_")]
pub struct Config {
    /// Timeout in milliseconds.
    #[env(rename = "timeout")]
    timeout_millis: u32,

    /// The verbosity level.
    #[env(no_prefix)]
    verbosity_level: Verbosity,

    /// The address to listen on.
    #[env(skip, flatten)] // flatten is not yet implemented
    address: Address,

    /// Process ID of the current process. Read automatically.
    #[env(skip)]
    process_id: u64,
}

#[derive(EnvConfig)]
pub struct Address {
    /// The domain to listen on.
    domain: String,

    /// The port to listen on.
    #[env(default = 80)]
    port: u16,
}

#[derive(EnvConfig, Debug, Eq, PartialEq)]
#[env(rename_all = "lowercase")]
pub enum Verbosity {
    /// Log informational, warning, and error messages.
    Info,
    /// Log warning and error messages.
    #[env(default)]
    Warning,
    /// Log error messages.
    #[env(rename = "Error")]
    Panic,
    /// Log nothing. Cannot be set manually only activated by `--batch-mode`.
    #[env(skip)]
    Silent,
}

fn main() -> Result<(), Box<dyn Error>> {
    // == Parsing the environment ==
    // typical invocation
    let cfg = Config::from_env(env::vars())?;

    // works with any Iterator<Item = (String, String)>
    let cfg = Config::from_env(vec!["SERVER_TIMEOUT", "3000"])?;
    assert_eq!(3000, cfg.timeout_millis);

    // == Documentation ==
    // takes an io::Writer that captures the markdown output
    let mut doc = doc_writer::render::MarkdownWriter::new(io::stdout());

    // ... typical doc-writer stuff like calling adding a title and description

    // document environment variables
    doc.start_environment()?;
    Config::default().document_env(&mut doc)?;

    // document the Verbosity enum
    doc.start_enum("Verbosity")?;
    Verbosity::document_enum(&mut doc)?;

    // == Rust Traits ==
    // for struct fields #[env(default = <expr>)] sets the default value
    assert_eq!(80, Address::default().port);

    // for enum variants #[env(default)] marks the default variant
    assert_eq!(Verbosity::Warning, Verbosity::default());

    // for enums from_str is implemented
    assert_eq!(Verbosity::Panic, Verbosity::from_str("ErRoR")?);

    // produces human readable error messages
    assert_eq!(
        r#"expected one of "info", "warning", "error", got "silent""#,
        &format!("{}", Verbosity::from_str("silent").unwrap_err())
    );
    assert_eq!(
        r#"expected one of "info", "warning", "error", got "panic""#,
        &format!("{}", Verbosity::from_str("panic").unwrap_err())
    );
    Ok(())
}

Would yield the following documentation:

§Environment

  • SERVER_TIMEOUT=0: Timeout in milliseconds.
  • VERBOSITY_LEVEL=warning: The verbosity level.

§Verbosity

  • info: Log informational, warning, and error messages.
  • warning: Log warning and error messages.
  • error: Log error messages.

Derive Macros§

EnvConfig
Derives EnvConfig as described in the module description.