#settings #account #hash-map

nightly hashmap_settings

HashMap wrapper for layered Settings

7 releases (4 breaking)

0.5.1 Feb 18, 2024
0.5.0 Jan 31, 2024
0.4.1 Jan 7, 2024
0.3.0 Nov 15, 2023
0.1.0 Oct 30, 2023

#258 in Configuration

Download history 8/week @ 2024-07-28 7/week @ 2024-09-22

62 downloads per month

MIT/Apache

140KB
1.5K SLoC

HashMapSettings Version Rust Version Documentation Build Status

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. Accounts 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 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.

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

This crate relies on the nightly feature dyn trait upcasting that was supposed to be stable in rust 1.76.0, unfortunately it has been delayed so currently the nightly compiler is required.

Add the following line to your Cargo.toml:

[dependencies]
hashmap_settings = "0.5"

Add the following line to your .rs file:

use hashmap_settings::prelude*;

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 HashMapSettings by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Dependencies

~245KB