open_feature/evaluation/
value.rs1use std::collections::HashMap;
2
3#[derive(Clone, PartialEq, Debug)]
5#[allow(missing_docs)]
6pub enum Value {
7 Bool(bool),
8 Int(i64),
9 Float(f64),
10 String(String),
11 Array(Vec<Value>),
12 Struct(StructValue),
13}
14
15#[derive(Clone, PartialEq, Debug)]
18#[allow(missing_docs)]
19pub enum Type {
20 Bool,
21 Int,
22 Float,
23 String,
24 Array,
25 Struct,
26}
27
28#[derive(Clone, Default, PartialEq, Debug)]
31pub struct StructValue {
32 pub fields: HashMap<String, Value>,
34}
35
36impl Value {
37 pub fn is_bool(&self) -> bool {
39 matches!(self, Self::Bool(_))
40 }
41
42 pub fn as_bool(&self) -> Option<bool> {
44 match self {
45 Self::Bool(value) => Some(*value),
46 _ => None,
47 }
48 }
49
50 pub fn is_i64(&self) -> bool {
52 matches!(self, Self::Int(_))
53 }
54
55 pub fn as_i64(&self) -> Option<i64> {
57 match self {
58 Self::Int(value) => Some(*value),
59 _ => None,
60 }
61 }
62
63 pub fn is_f64(&self) -> bool {
65 matches!(self, Self::Float(_))
66 }
67
68 pub fn as_f64(&self) -> Option<f64> {
70 match self {
71 Self::Float(value) => Some(*value),
72 _ => None,
73 }
74 }
75
76 pub fn is_str(&self) -> bool {
78 matches!(self, Self::String(_))
79 }
80
81 pub fn as_str(&self) -> Option<&str> {
83 match self {
84 Self::String(value) => Some(value),
85 _ => None,
86 }
87 }
88
89 pub fn is_array(&self) -> bool {
91 matches!(self, Self::Array(_))
92 }
93
94 pub fn as_array(&self) -> Option<&Vec<Value>> {
96 match self {
97 Self::Array(value) => Some(value),
98 _ => None,
99 }
100 }
101
102 pub fn is_struct(&self) -> bool {
104 matches!(self, Self::Struct(_))
105 }
106
107 pub fn as_struct(&self) -> Option<&StructValue> {
109 match self {
110 Self::Struct(value) => Some(value),
111 _ => None,
112 }
113 }
114
115 pub fn get_type(&self) -> Type {
117 match self {
118 Self::Bool(_) => Type::Bool,
119 Self::Int(_) => Type::Int,
120 Self::Float(_) => Type::Float,
121 Self::String(_) => Type::String,
122 Self::Array(_) => Type::Array,
123 Self::Struct(_) => Type::Struct,
124 }
125 }
126}
127
128impl From<bool> for Value {
129 fn from(value: bool) -> Self {
130 Self::Bool(value)
131 }
132}
133
134impl From<i8> for Value {
135 fn from(value: i8) -> Self {
136 Self::Int(value.into())
137 }
138}
139
140impl From<i16> for Value {
141 fn from(value: i16) -> Self {
142 Self::Int(value.into())
143 }
144}
145
146impl From<i32> for Value {
147 fn from(value: i32) -> Self {
148 Self::Int(value.into())
149 }
150}
151
152impl From<i64> for Value {
153 fn from(value: i64) -> Self {
154 Self::Int(value)
155 }
156}
157
158impl From<u8> for Value {
159 fn from(value: u8) -> Self {
160 Self::Int(value.into())
161 }
162}
163
164impl From<u16> for Value {
165 fn from(value: u16) -> Self {
166 Self::Int(value.into())
167 }
168}
169
170impl From<u32> for Value {
171 fn from(value: u32) -> Self {
172 Self::Int(value.into())
173 }
174}
175
176impl From<f32> for Value {
177 fn from(value: f32) -> Self {
178 Self::Float(value.into())
179 }
180}
181
182impl From<f64> for Value {
183 fn from(value: f64) -> Self {
184 Self::Float(value)
185 }
186}
187
188impl From<String> for Value {
189 fn from(value: String) -> Self {
190 Self::String(value)
191 }
192}
193
194impl From<&str> for Value {
195 fn from(value: &str) -> Self {
196 Self::String(value.to_string())
197 }
198}
199
200impl<T> From<Vec<T>> for Value
201where
202 T: Into<Value>,
203{
204 fn from(value: Vec<T>) -> Self {
205 Self::Array(value.into_iter().map(Into::into).collect())
206 }
207}
208
209impl From<StructValue> for Value {
210 fn from(value: StructValue) -> Self {
211 Self::Struct(value)
212 }
213}
214
215impl StructValue {
216 #[must_use]
218 pub fn with_field(mut self, key: impl Into<String>, value: impl Into<Value>) -> Self {
219 self.add_field(key, value);
220 self
221 }
222
223 pub fn add_field(&mut self, key: impl Into<String>, value: impl Into<Value>) {
225 self.fields.insert(key.into(), value.into());
226 }
227}
228
229impl std::fmt::Display for Type {
230 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
231 match self {
232 Self::Bool => write!(f, "bool"),
233 Self::Int => write!(f, "int"),
234 Self::Float => write!(f, "float"),
235 Self::String => write!(f, "string"),
236 Self::Array => write!(f, "array"),
237 Self::Struct => write!(f, "struct"),
238 }
239 }
240}
241
242#[cfg(test)]
243mod tests {
244 use super::*;
245
246 #[test]
247 fn build_value() {
248 let alex = StructValue::default()
249 .with_field("is_male", false)
250 .with_field("id", 100)
251 .with_field("grade", 97.5)
252 .with_field("name", "Alex")
253 .with_field("friends", vec!["Bob", "Carl"])
254 .with_field(
255 "other",
256 StructValue::default().with_field("description", "A student"),
257 );
258
259 let is_male = alex.fields.get("is_male").unwrap();
260 assert!(is_male.is_bool());
261 assert_eq!(false, is_male.as_bool().unwrap());
262
263 let id = alex.fields.get("id").unwrap();
264 assert!(id.is_i64());
265 assert_eq!(100, id.as_i64().unwrap());
266
267 let grade = alex.fields.get("grade").unwrap();
268 assert!(grade.is_f64());
269 assert_eq!(97.5, grade.as_f64().unwrap());
270
271 let name = alex.fields.get("name").unwrap();
272 assert!(name.is_str());
273 assert_eq!("Alex", alex.fields.get("name").unwrap().as_str().unwrap());
274
275 let friends = alex.fields.get("friends").unwrap();
276 assert!(friends.is_array());
277 assert_eq!(
278 vec![
279 Value::String("Bob".to_string()),
280 Value::String("Carl".to_string())
281 ],
282 *friends.as_array().unwrap()
283 );
284
285 let other = alex.fields.get("other").unwrap();
286 assert!(other.is_struct());
287 assert_eq!(
288 "A student",
289 other
290 .as_struct()
291 .unwrap()
292 .fields
293 .get("description")
294 .unwrap()
295 .as_str()
296 .unwrap()
297 );
298 }
299}