1use indexmap::IndexMap;
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Default, Serialize, Deserialize)]
10pub struct ConfigMap {
11 flat: IndexMap<String, String>,
12 sections: IndexMap<String, IndexMap<String, String>>,
13}
14
15impl ConfigMap {
16 #[must_use]
18 pub fn new() -> Self {
19 Self::default()
20 }
21
22 pub fn insert_flat(&mut self, key: String, value: String) {
26 self.flat.insert(key, value);
27 }
28
29 pub fn insert_sectioned(&mut self, section: String, key: String, value: String) {
31 self.sections.entry(section).or_default().insert(key, value);
32 }
33
34 pub fn get_flat(&self, key: &str) -> Option<&str> {
38 self.flat.get(key).map(String::as_str)
39 }
40
41 pub fn get_in_section(&self, section: &str, key: &str) -> Option<&str> {
43 self.sections
44 .get(section)
45 .and_then(|s| s.get(key))
46 .map(String::as_str)
47 }
48
49 #[must_use]
51 pub fn get_section(&self, section: &str) -> Option<&IndexMap<String, String>> {
52 self.sections.get(section)
53 }
54
55 #[must_use]
57 pub fn has_section(&self, section: &str) -> bool {
58 self.sections.contains_key(section)
59 }
60
61 pub fn flat_iter(&self) -> impl Iterator<Item = (&str, &str)> {
65 self.flat.iter().map(|(k, v)| (k.as_str(), v.as_str()))
66 }
67
68 pub fn sections(&self) -> impl Iterator<Item = (&str, &IndexMap<String, String>)> {
70 self.sections.iter().map(|(k, v)| (k.as_str(), v))
71 }
72
73 #[must_use]
75 pub fn len(&self) -> usize {
76 self.flat.len() + self.sections.len()
77 }
78
79 #[must_use]
81 pub fn is_empty(&self) -> bool {
82 self.flat.is_empty() && self.sections.is_empty()
83 }
84
85 #[must_use]
87 pub fn contains_key(&self, key: &str) -> bool {
88 if self.flat.contains_key(key) {
89 return true;
90 }
91 self.sections.values().any(|s| s.contains_key(key))
92 }
93}