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
62 downloads per month
140KB
1.5K
SLoC
HashMapSettings
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
-
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 )
-
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 anAccount
, 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. -
Account
s can be individually deactivated allowing for a developer (or a user) to group settings in anAccount
and easily ignore them under certain conditions.
Drawbacks
-
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. -
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