overwrite 0.2.0

A simple trait that defines how to overwrite a type by another types. Mainly useful to create an app configuration from different sources.
Documentation
  • Coverage
  • 50%
    2 out of 4 items documented2 out of 4 items with examples
  • Size
  • Source code size: 18.99 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 1.13 MB This is the summed size of all files generated by rustdoc for all configured targets
  • Links
  • a1akris/overwrite
    3 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • a1akris

Build

Overwrite

A simple trait that defines how to overwrite a type by another types. Mainly useful to create an app configuration from different sources.

Example

use overwrite::Overwrite;

struct Config {
    url: String,
    user: String,
    api_token: String,
}

impl Default for Config {
    fn default() -> Self {
        Self {
            url: "default".to_owned(),
            user: "default".to_owned(),
            api_token: "default".to_owned(),
        }
    }
}

struct CliArgs {
    url: Option<String>,
    user: Option<String>,
    api_token: Option<String>
}

impl Overwrite<CliArgs> for Config {
    fn overwrite_mut(&mut self, cli_args: CliArgs) -> &mut Self {
        // There is a blanket impl to overwrite values with Options.
        // Overwrite happens if the Option is Some.
        self.url.overwrite_mut(cli_args.url);
        self.user.overwrite_mut(cli_args.user);
        self.api_token.overwrite_mut(cli_args.api_token);
        self
    }
}

struct ConfFile {
    url: Option<String>,
    user: Option<String>,
    api_token: Option<String>,
}

impl Overwrite<ConfFile> for Config {
    fn overwrite_mut(&mut self, conf_file: ConfFile) -> &mut Self {
        self.url.overwrite_mut(conf_file.url);
        self.user.overwrite_mut(conf_file.user);
        self.api_token.overwrite_mut(conf_file.api_token);
        self
    }
}

struct EnvVars {
    url: Option<String>,
    user: Option<String>,
    api_token: Option<String>,
}

impl Overwrite<EnvVars> for Config {
    fn overwrite_mut(&mut self, env_vars: EnvVars) -> &mut Self {
        self.url.overwrite_mut(env_vars.url);
        self.user.overwrite_mut(env_vars.user);
        self.api_token.overwrite_mut(env_vars.api_token);
        self
    }
}

fn main() {
    let cli_args = parse_args();
    let conf_file = read_conf_file();
    let env_vars = parse_env();

    // Note the precedense. `cli_args` have the highest precedense while default config values
    // have the lowest precedense. `conf_file` values will be overwritten by `env_vars` if env
    // vars are present.
    let config = Config::default()
        .overwrite(conf_file)
        .overwrite(env_vars)
        .overwrite(cli_args);

    assert_eq!(config.url, "default");
    assert_eq!(config.user, "from_env_vars");
    assert_eq!(config.api_token, "from_cli_args");
}

fn parse_args() -> CliArgs {
    CliArgs {
        url: None,
        user: None,
        api_token: Some("from_cli_args".to_owned()),
    }
}

fn parse_env() -> EnvVars {
    EnvVars {
        url: None,
        user: Some("from_env_vars".to_owned()),
        api_token: None,
    }
}

fn read_conf_file() -> ConfFile {
    ConfFile {
        url: None,
        user: Some("from_conf_file".to_owned()),
        api_token: Some("from_conf_file".to_owned()),
    }
}

As you have noticed the trait implementation is quite repetetive. There will be a proc macro to automatically derive it in the future versions.

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.