Crate irx_config

Crate irx_config 

Source
Expand description

§irx-config library

GitHub top language Crates.io Crates.io Crates.io Libraries.io dependency status for latest release docs.rs GitHub Actions Workflow Status

The irx-config library provides convenient way to represent/parse configuration from different sources. The main goals is to be very easy to use and to be extendable.

§Features

  • Fully compatible with serde
  • Full deep merge of nested dictionaries/mappings
  • Case sensitive/insensitive parameters names matching/merging
  • Sealing secrets during display/debugging
  • Get all configuration parameters or just cherry pick few
  • Several embedded parsers available via library features:
    • Command-line argument (via clap)
    • Environment variables
    • File based parsers: JSON, JSON5, YAML and TOML
  • Could be extended with custom parsers

§Examples

§JSON with environment variables

To enable parsers used in example below, one has to add the following to Cargo.toml:

[dependencies]
irx-config = { version = "3.5", features = ["env", "json"] }
use irx_config::parsers::{env, json};
use irx_config::ConfigBuilder;
use serde::Deserialize;

#[derive(Deserialize)]
struct Conf {
    id: u32,
    logger: String,
    tag: String,
}

// Data from two parsers will be merged. The values from parser appended first (`JSON`)
// will take precedence if values have a same names
let config = ConfigBuilder::default()
    .append_parser(
        json::ParserBuilder::default()
            .default_path("config.json")
            .build()?,
    )
    .append_parser(
        env::ParserBuilder::default()
            .default_prefix("APP_")
            .build()?,
    )
    .load()?;

let conf_data: Conf = config.get()?;

§Command-line, TOML and environment variables

To enable parsers used in example below, one has to add the following to Cargo.toml:

[dependencies]
irx-config = { version = "3.5", features = ["cmd", "env", "toml-parser"] }
use clap::app_from_crate;
use irx_config::parsers::{cmd, env, toml};
use irx_config::ConfigBuilder;
use serde::Deserialize;

fn localhost() -> String {
    "localhost".into()
}

#[derive(Deserialize)]
struct Logger {
    level: String,
    path: String,
}

#[derive(Deserialize)]
struct Connection {
    #[serde(default = "localhost")]
    host: String,
    port: u16,
}

#[derive(Deserialize)]
struct Conf {
    id: u32,
    logger: Logger,
    connection: Connection,
}

let app = app_from_crate!();

// Data from three parsers will be merged. The values from parser appended first (`cmd`)
// will take precedence if values have a same names
let config = ConfigBuilder::default()
    .append_parser(
        cmd::ParserBuilder::new(app)
            .exit_on_error(true)
            .build()?,
    )
    .append_parser(
        toml::ParserBuilder::default()
            .default_path("config.toml")
            .path_option("config")
            .build()?,
    )
    .append_parser(
        env::ParserBuilder::default()
            .default_prefix("APP_")
            .prefix_option("prefix")
            .build()?,
    )
    .load()?;

let conf_data: Conf = config.get()?;

§Custom parser

use irx_config::{AnyResult, Case, ConfigBuilder, Parse, Value};
use serde::Deserialize;
use std::borrow::Cow;

#[derive(Deserialize)]
struct Conf {
    id: u32,
    logger: String,
    tag: String,
}

struct JsonStringParser<'a> {
    data: Cow<'a, str>,
}

impl<'a> JsonStringParser<'a> {
    pub fn new(data: impl Into<Cow<'a, str>>) -> Self {
        JsonStringParser { data: data.into() }
    }
}

impl Case for JsonStringParser<'_> {}

impl Parse for JsonStringParser<'_> {
    fn parse(&mut self, _value: &Value) -> AnyResult<Value> {
        Ok(serde_json::from_str(&self.data)?)
    }
}

let data = r#"{ "id": 42, "logger": "file", "tag": "test" }"#;
let config = ConfigBuilder::load_one(JsonStringParser::new(data))?;
let conf_data: Conf = config.get()?;

§JSON parser get partial data

To enable parsers used in example below, one has to add the following to Cargo.toml:

[dependencies]
irx-config = { version = "3.5", features = ["json"] }
use irx_config::parsers::json;
use irx_config::ConfigBuilder;
use serde::Deserialize;

fn localhost() -> String {
    "localhost".into()
}

#[derive(Deserialize)]
struct Logger {
    level: String,
    path: String,
}

#[derive(Deserialize)]
struct Connection {
    #[serde(default = "localhost")]
    host: String,
    port: u16,
}

let config = ConfigBuilder::load_one(
    json::ParserBuilder::default()
        .default_path("config.json")
        .build()?,
)?;

let logger: Logger = config.get_by_key_path("logger")?.unwrap();
let port: u16 = config.get_by_key_path("connection:port")?.unwrap();

Re-exports§

pub use crate::config::Config;
pub use crate::config::ConfigBuilder;
pub use crate::value::Value;

Modules§

config
This module define main configuration structures: Config and ConfigBuilder.
parsers
This module define base structures (FileParser and FileParserBuilder) which help to implement file based parsers. All embedded file based parsers is using that base structures.
value
This module define Value structure which represent key-value based configuration data.

Macros§

json
Construct a serde_json::Value from a JSON literal.

Enums§

Error
Error generated during any crate operations.
MergeCase
Case mode to merging keys during (re)load.

Constants§

DEFAULT_KEYS_SEPARATOR
Default key level separator.

Traits§

Case
A data structure that has case-sensitive or case-insensitive keys.
Parse
A data structure that can be parsed.

Type Aliases§

AnyResult
A result type with any error.
Result
A result type with internal error.