Git Product home page Git Product logo

cfgmap's Introduction

cfgmap

A special hashmap made with configuration in mind.


This crate contains a new data structure that acts as a wrapper around a HashMap. It provides its own data enum for values (CfgValue), and contains multiple helper functions that let you navigate the hashmap easily.

Its primary purpose is for configuration, allowing for validation as well. In essence, a CfgMap would represent a configuration for an application. So far, alternatives for configuration would be to use a data format library directly, or utilise a struct that a configuration file, like JSON or TOML, would serialise into.

This can be more than satisfactory, especially for basic configurations, however in certain situations it can prove to be more than a bit cumbersome. For example, if you plan on using default options in the case that certain options aren't set, having multiple nested objects to validate and go through, etc.

If you'd like to use the most common features supplied by this crate, you can simply do:

use cfgmap::prelude::*;

This will include the CfgMap, all CfgValues, all public macros, all Conditions, and the Checkable trait.

Features

This crate is customizable, allowing for multiple features depending on your needs:

  • from_toml: Allows to create a hashmap from TOML values, also having an additional Datetime CfgValue.
  • from_json: Allows to create a hashmap from JSON values, also having an additional Null CfgValue.
  • generator: Includes additional methods for CfgValues that allows for generating numbers (int or float) using a value.

Tutorial (of sorts):

It is very easy to make a new CfgMap, there are multiple methods:

use cfgmap::CfgMap;

let map1 = CfgMap::new();
let mut map2 = CfgMap::new();
map2.default = "default".into();

CfgMap allows for some functionality with regards to default values. For map1 above, default was never set, so the values would be retrieved from the root. For map2 however, it's assumed that all default values are located in default.

Path syntax

CfgMap also comes with support for a certain path syntax with its keys:

cfgmap.get("hello/there/pal");

This helps to make access to nested items easy. The line above is essentially equal to:

map.get("hello")
    .and_then(|a| a.as_map())
    .and_then(|a| a.get("there"))
    .and_then(|a| a.as_map())
    .and_then(|a| a.get("pal"));

Note that if hello or there weren't CfgMaps as well, the whole expression would evaluate to None. This key can also contain array indexes. For example, with a/0/c, it will check whether a is a Map or a List. If its the former, it will try to find a key with the value 0. If its the latter, it will instead try to index into the list.

Conditions

Now, what if you want to check what a certain value evaluates to? This is something that you'll encounter very quickly if you'd like to use any value. This crate comes with an extensive support for Conditions!

use cfgmap::{Condition::*, Checkable};
let is_number = cfgmap.get("hello/there/pal").check_that(IsInt | IsFloat);

The above line will check whether the value at hello/there/pal is a CfgValue::Int or a CfgValue::Float. There are more conditions listed here. If there are more conditions that you'd like added, feel free to open up an issue or open a PR! All of these serve as utilities to help validate a certain value.

Default values

Defaults can also be used quite easily:+

map.get_option("http_settings", "ip_address");

Let's say that map was initialised with its default at default. The above line will be equivalent to the following:

map.get("http_settings/ip_address").or(map.get("default/ip_address"));

You can also update an option like this, using update_option. This works similar to using add, except that it doesn't add a new option if it isn't found, only updating an existing one.

HashMap methods

All HashMap methods are also available, since CfgMap implements Deref and DerefMut for HashMap<String, CfgValue>. For example, you can call .iter() on it, even though that is not directly implemented.

Complete example

use cfgmap::{CfgMap, CfgValue::*, Condition::*, Checkable};

let toml = toml::toml! {
   [package]
   name = "cfgmap"
   version = "0.1.0"
   authors = ["ENBYSS"]

   [lib]
   name = "cfgmap"
   path = "src/cfgmap.rs"

   [dependencies]
   serde_json = { version = "1.0.48", optional = true }
   toml = { version = "0.5.6", optional = true }

   [other]
   date = 2020-02-29
   float = 1.2
   int = 3
   internal.more = "hello"

   [[person]]
   name = "a"

   [[person]]
   name = "b"
};

let cmap = CfgMap::from_toml(toml);

assert!(cmap.get("package/name").check_that(IsExactlyStr("cfgmap".into())));
assert!(cmap.get("package/version").check_that(IsExactlyStr("0.1.0".into())));
assert!(cmap.get("package/authors").check_that(IsExactlyList(vec![Str("ENBYSS".into())])));

assert!(cmap.get("lib/name").check_that(IsExactlyStr("cfgmap".into())));
assert!(cmap.get("lib/path").check_that(IsExactlyStr("src/cfgmap.rs".into())));

assert!(cmap.get("dependencies/serde_json/version").check_that(IsExactlyStr("1.0.48".into())));
assert!(cmap.get("dependencies/serde_json/optional").check_that(IsTrue));
assert!(cmap.get("dependencies/toml/version").check_that(IsExactlyStr("0.5.6".into())));
assert!(cmap.get("dependencies/toml/optional").check_that(IsTrue));

assert!(cmap.get("other/date").check_that(IsDatetime));
assert!(cmap.get("other/float").check_that(IsExactlyFloat(1.2)));
assert!(cmap.get("other/int").check_that(IsExactlyInt(3)));
assert!(cmap.get("other/internal/more").check_that(IsExactlyStr("hello".into())));

assert!(cmap.get("person").check_that(IsListWith(Box::new(IsMap))));
assert!(cmap.get("person/0/name").check_that(IsExactlyStr("a".into())));
assert!(cmap.get("person/1/name").check_that(IsExactlyStr("b".into())));

cfgmap's People

Contributors

aejenk avatar

Stargazers

 avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.