geam_core/host/component/
configuration.rs1use ecow::EcoString;
2use std::collections::BTreeMap;
3
4#[derive(Debug, Clone, PartialEq)]
6pub struct HostProviderConfiguration {
7 values: BTreeMap<EcoString, HostProviderConfigurationValue>,
8}
9
10#[derive(Debug, Clone, PartialEq)]
12pub enum HostProviderConfigurationValue {
13 String(EcoString),
14 Integer(i64),
15 Float(f64),
16 Bool(bool),
17 Array(Vec<Self>),
18 Table(HostProviderConfiguration),
19}
20
21impl HostProviderConfiguration {
22 pub fn new(values: BTreeMap<EcoString, HostProviderConfigurationValue>) -> Self {
23 Self { values }
24 }
25
26 pub fn empty() -> Self {
27 Self::new(BTreeMap::new())
28 }
29
30 pub fn get(&self, key: &str) -> Option<&HostProviderConfigurationValue> {
31 self.values.get(key)
32 }
33
34 pub fn iter(
35 &self,
36 ) -> impl ExactSizeIterator<Item = (&EcoString, &HostProviderConfigurationValue)> {
37 self.values.iter()
38 }
39
40 pub fn is_empty(&self) -> bool {
41 self.values.is_empty()
42 }
43}
44
45impl HostProviderConfigurationValue {
46 pub fn as_string(&self) -> Option<&EcoString> {
47 match self {
48 Self::String(value) => Some(value),
49 _ => None,
50 }
51 }
52
53 pub fn as_integer(&self) -> Option<i64> {
54 match self {
55 Self::Integer(value) => Some(*value),
56 _ => None,
57 }
58 }
59
60 pub fn as_float(&self) -> Option<f64> {
61 match self {
62 Self::Float(value) => Some(*value),
63 _ => None,
64 }
65 }
66
67 pub fn as_bool(&self) -> Option<bool> {
68 match self {
69 Self::Bool(value) => Some(*value),
70 _ => None,
71 }
72 }
73
74 pub fn as_array(&self) -> Option<&[Self]> {
75 match self {
76 Self::Array(value) => Some(value),
77 _ => None,
78 }
79 }
80
81 pub fn as_table(&self) -> Option<&HostProviderConfiguration> {
82 match self {
83 Self::Table(value) => Some(value),
84 _ => None,
85 }
86 }
87}
88
89impl From<EcoString> for HostProviderConfigurationValue {
90 fn from(value: EcoString) -> Self {
91 Self::String(value)
92 }
93}
94
95impl From<&str> for HostProviderConfigurationValue {
96 fn from(value: &str) -> Self {
97 Self::String(value.into())
98 }
99}
100
101impl From<i64> for HostProviderConfigurationValue {
102 fn from(value: i64) -> Self {
103 Self::Integer(value)
104 }
105}
106
107impl From<f64> for HostProviderConfigurationValue {
108 fn from(value: f64) -> Self {
109 Self::Float(value)
110 }
111}
112
113impl From<bool> for HostProviderConfigurationValue {
114 fn from(value: bool) -> Self {
115 Self::Bool(value)
116 }
117}
118
119impl From<Vec<HostProviderConfigurationValue>> for HostProviderConfigurationValue {
120 fn from(value: Vec<HostProviderConfigurationValue>) -> Self {
121 Self::Array(value)
122 }
123}
124
125impl From<HostProviderConfiguration> for HostProviderConfigurationValue {
126 fn from(value: HostProviderConfiguration) -> Self {
127 Self::Table(value)
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use super::{HostProviderConfiguration, HostProviderConfigurationValue};
134 use ecow::EcoString;
135 use std::collections::BTreeMap;
136
137 #[test]
138 fn configuration_preserves_every_owned_value_family() {
139 let nested = HostProviderConfiguration::new(BTreeMap::from([(
140 EcoString::from("enabled"),
141 true.into(),
142 )]));
143 let configuration = HostProviderConfiguration::new(BTreeMap::from([
144 (
145 EcoString::from("array"),
146 vec![1_i64.into(), false.into()].into(),
147 ),
148 (EcoString::from("float"), 1.5.into()),
149 (EcoString::from("integer"), (-7_i64).into()),
150 (EcoString::from("string"), "value".into()),
151 (EcoString::from("table"), nested.into()),
152 ]));
153
154 assert!(!configuration.is_empty());
155 assert_eq!(configuration.iter().len(), 5);
156 assert_eq!(
157 configuration
158 .get("string")
159 .and_then(|value| value.as_string()),
160 Some(&EcoString::from("value"))
161 );
162 assert_eq!(
163 configuration
164 .get("integer")
165 .and_then(HostProviderConfigurationValue::as_integer),
166 Some(-7)
167 );
168 assert_eq!(
169 configuration
170 .get("float")
171 .and_then(HostProviderConfigurationValue::as_float),
172 Some(1.5)
173 );
174 let array = configuration
175 .get("array")
176 .and_then(HostProviderConfigurationValue::as_array)
177 .expect("array should be present");
178 assert_eq!(array[0].as_integer(), Some(1));
179 assert_eq!(array[1].as_bool(), Some(false));
180 assert_eq!(
181 configuration
182 .get("table")
183 .and_then(HostProviderConfigurationValue::as_table)
184 .and_then(|table| table.get("enabled"))
185 .and_then(HostProviderConfigurationValue::as_bool),
186 Some(true)
187 );
188 assert_eq!(configuration.clone(), configuration);
189 assert!(HostProviderConfiguration::empty().is_empty());
190 }
191
192 #[test]
193 fn configuration_accessors_do_not_coerce_value_families() {
194 let value = HostProviderConfigurationValue::String("text".into());
195 let owned = HostProviderConfigurationValue::from(EcoString::from("owned"));
196
197 assert_eq!(value.as_string().map(EcoString::as_str), Some("text"));
198 assert_eq!(owned.as_string().map(EcoString::as_str), Some("owned"));
199 assert_eq!(value.as_integer(), None);
200 assert_eq!(value.as_float(), None);
201 assert_eq!(value.as_bool(), None);
202 assert_eq!(value.as_array(), None);
203 assert_eq!(value.as_table(), None);
204 assert_eq!(HostProviderConfigurationValue::Integer(1).as_string(), None);
205 }
206}