hashmap_settings 0.6.1

HashMap wrapper for layered Settings
Documentation
# HashMapSettings [![Version]][Crates.io] [![Documentation]][Docs.rs] [![Build Status]][Actions]


[Version]: https://img.shields.io/crates/v/hashmap_settings.svg
[Crates.io]: https://crates.io/crates/hashmap_settings
[Documentation]: https://img.shields.io/docsrs/hashmap_settings/latest
[Docs.rs]: https://docs.rs/hashmap_settings
[Build Status]: https://img.shields.io/github/actions/workflow/status/OxidizedLoop/HashMapSettings/rust.yml
[Actions]: https://github.com/OxidizedLoop/HashMapSettings/actions

## `HashMap` wrapper for layered settings


This crate facilitates the management of settings, with the goal of allowing developers to turn previously needlessly set in stone
values into a setting a user can change, as well as making it easier for a developer to create multiple priority levels of settings,
allowing users to have greater control and customization including across devices.

This crate allows a developer to store and access all program settings on a `Account`,
a wrapper around a `HashMap`.

This crate is intended to be used with some sort of type abstraction so that settings of distinct types can be stored in
a single `Account`. This crate provides the `Stg` type abstraction for this.

An `Account` can also hold other Accounts, allowing the existence of layered settings,
that permit the creation complex systems that have the:

### Benefits


1. Having multiple places changing the same setting with the value being taken from the place that is deemed
to have the most importance.
(eg: Default, Themes, Extensions, Global Settings, OS Settings, Device Settings, Temporary Settings )

2. Organization of Settings. Given that an `Account` can hold accounts, and they can hold accounts of they own, its possible for
small groups of settings to be organized in an `Account`, making it more convenient to locate a setting, or display a group of settings.
Important to notice that this organization doesn't need to be (but could be) enforced in all held accounts equally.

3. `Account`s can be individually deactivated allowing for a developer (or a user)
to group settings in an `Account` and easily ignore them under certain conditions.

### Drawbacks


1. Each `Account` holds a copy of the settings present in it's child Accounts, so there is a memory cost, but its
[planned]https://github.com/OxidizedLoop/HashMapSettings/issues/28 for it to be changed to a reference to the value instead.

2. Having to internally do a `HashMap`'s .get() will most likely be slower than alternatives.

## Example


This following example shows how values in some Child Accounts take priority over others, but also demonstrates that no values are lost and how they can still be accessible.

```rust
use hashmap_settings::prelude::*;
use std::collections::HashMap;

//creating the Parent Account
let mut account = Account::<
    String, //Account's name
    &str, //HashMap<K,V> K key
    Stg  //HashMap<K,v> V value
    >::default();

// inserting child Accounts
account.push(
    Account::new(
        "Default".to_string(), //Name of the Account
        true,//is the account active
        HashMap::from([
            ("lines", 3.stg()), // .stg() turns a type into the type abstraction Stg
            ("word_repetition", 10.stg()),
            ("word", "default".to_string().stg()),
        ]), //settings
        vec![], //child Accounts
    ),
    Valid::new_true(), // not relevant for this example and can be ignored.
);

account.push(
    Account::new(
        "Global Settings".to_string(),
        true,
        HashMap::from([
            ("word_repetition", 2.stg()),
            ("word", "global".to_string().stg()),
        ]), //this account is in a layer above the "Default" Account, so it's values will have priority
        vec![],
    ),
    Valid::new_true(),
);// we could be getting this from a database

account.push(
    Account::new(
        "Local Settings".to_string(),
        true,
        HashMap::from([("word", "local".to_string().stg())]),
        //this account is in a layer that's above "Default" and "Global Settings" Accounts,
        //so it's values will have priority over it
        vec![],
    ),
    Valid::new_true(),
);// we could be getting this Account from a local file

account.push(
    Account::new(
        "Inactive Account".to_string(),
        false, //this account is inactive so its settings will be ignored.
        HashMap::from([("word", "inactive".to_string().stg())]),
        vec![],
    ),
    Valid::new_true(),
);

//getting values from the account
let word: String = account.get(&"word").unstg()?;
let word_repetition = account.get(&"word_repetition").unstg()?;
let lines =account.get(&"lines").unstg()?;

//example of using the values
let mut sentence = String::new();
for _ in 0..word_repetition {
    sentence.push_str(&word);
    sentence.push(' ');
}
sentence.pop();
for _ in 0..lines {
    println!("{sentence}");
}
//this will print the following:
/*
local local
local local
local local
*/

//values in child accounts are still accessible
let ref_child_account: &Account<_, _, _> = account
    .deep(&mut vec![&"Default".to_string()])
    .unwrap();
let inactive_word: String = ref_child_account.get(&"word").unstg()?;
println!("{inactive_word}");
//this will print "default"

//this includes inactive accounts
let ref_child_account: &Account<_, _, _> = account
    .deep(&mut vec![&"Inactive Account".to_string()])
    .unwrap();
let inactive_word: String = ref_child_account.get(&"word").unstg()?;
println!("{inactive_word}");
//this will print "inactive"
# Ok::<(), StgError>(())


*/
```

## How to use


Add the following line to your Cargo.toml:

```toml
[dependencies]
hashmap_settings = "0.5"
```

Add the following line to your .rs file:

```rust
use hashmap_settings::prelude*;
```

## License


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