open_feature/evaluation/
context_field_value.rs1use std::{any::Any, sync::Arc};
2
3use time::OffsetDateTime;
4
5#[derive(Clone, Debug)]
7#[allow(missing_docs)]
8pub enum EvaluationContextFieldValue {
9 Bool(bool),
10 Int(i64),
11 Float(f64),
12 String(String),
13 DateTime(OffsetDateTime),
14 Struct(Arc<dyn Any + Send + Sync>), }
16
17impl EvaluationContextFieldValue {
18 pub fn new_struct<T>(value: T) -> Self
20 where
21 T: Any + Send + Sync,
22 {
23 Self::Struct(Arc::new(value))
24 }
25
26 pub fn is_bool(&self) -> bool {
28 matches!(self, Self::Bool(_))
29 }
30
31 pub fn as_bool(&self) -> Option<bool> {
33 match self {
34 Self::Bool(value) => Some(*value),
35 _ => None,
36 }
37 }
38
39 pub fn is_i64(&self) -> bool {
41 matches!(self, Self::Int(_))
42 }
43
44 pub fn as_i64(&self) -> Option<i64> {
46 match self {
47 Self::Int(value) => Some(*value),
48 _ => None,
49 }
50 }
51
52 pub fn is_f64(&self) -> bool {
54 matches!(self, Self::Float(_))
55 }
56
57 pub fn as_f64(&self) -> Option<f64> {
59 match self {
60 Self::Float(value) => Some(*value),
61 _ => None,
62 }
63 }
64
65 pub fn is_str(&self) -> bool {
67 matches!(self, Self::String(_))
68 }
69
70 pub fn as_str(&self) -> Option<&str> {
72 match self {
73 Self::String(value) => Some(value),
74 _ => None,
75 }
76 }
77
78 pub fn is_date_time(&self) -> bool {
80 matches!(self, Self::DateTime(_))
81 }
82
83 pub fn as_date_time(&self) -> Option<&OffsetDateTime> {
85 match self {
86 Self::DateTime(value) => Some(value),
87 _ => None,
88 }
89 }
90
91 pub fn is_struct(&self) -> bool {
93 matches!(self, Self::Struct(_))
94 }
95
96 pub fn as_struct(&self) -> Option<Arc<dyn Any + Send + Sync>> {
98 match self {
99 Self::Struct(value) => Some(value.clone()),
100 _ => None,
101 }
102 }
103}
104
105impl From<bool> for EvaluationContextFieldValue {
106 fn from(value: bool) -> Self {
107 Self::Bool(value)
108 }
109}
110
111impl From<i8> for EvaluationContextFieldValue {
112 fn from(value: i8) -> Self {
113 Self::Int(value.into())
114 }
115}
116
117impl From<i16> for EvaluationContextFieldValue {
118 fn from(value: i16) -> Self {
119 Self::Int(value.into())
120 }
121}
122
123impl From<i32> for EvaluationContextFieldValue {
124 fn from(value: i32) -> Self {
125 Self::Int(value.into())
126 }
127}
128
129impl From<i64> for EvaluationContextFieldValue {
130 fn from(value: i64) -> Self {
131 Self::Int(value)
132 }
133}
134
135impl From<u8> for EvaluationContextFieldValue {
136 fn from(value: u8) -> Self {
137 Self::Int(value.into())
138 }
139}
140
141impl From<u16> for EvaluationContextFieldValue {
142 fn from(value: u16) -> Self {
143 Self::Int(value.into())
144 }
145}
146
147impl From<u32> for EvaluationContextFieldValue {
148 fn from(value: u32) -> Self {
149 Self::Int(value.into())
150 }
151}
152
153impl From<f32> for EvaluationContextFieldValue {
154 fn from(value: f32) -> Self {
155 Self::Float(value.into())
156 }
157}
158
159impl From<f64> for EvaluationContextFieldValue {
160 fn from(value: f64) -> Self {
161 Self::Float(value)
162 }
163}
164
165impl From<String> for EvaluationContextFieldValue {
166 fn from(value: String) -> Self {
167 Self::String(value)
168 }
169}
170
171impl From<&str> for EvaluationContextFieldValue {
172 fn from(value: &str) -> Self {
173 Self::String(value.to_string())
174 }
175}
176
177impl From<OffsetDateTime> for EvaluationContextFieldValue {
178 fn from(value: OffsetDateTime) -> Self {
179 Self::DateTime(value)
180 }
181}
182
183impl<T: Any + Send + Sync> From<Arc<T>> for EvaluationContextFieldValue {
184 fn from(value: Arc<T>) -> Self {
185 Self::Struct(value)
186 }
187}
188
189impl PartialEq for EvaluationContextFieldValue {
190 fn eq(&self, other: &Self) -> bool {
191 match (self, other) {
192 (EvaluationContextFieldValue::Bool(left), EvaluationContextFieldValue::Bool(right)) => {
193 left == right
194 }
195 (EvaluationContextFieldValue::Int(left), EvaluationContextFieldValue::Int(right)) => {
196 left == right
197 }
198 (
199 EvaluationContextFieldValue::Float(left),
200 EvaluationContextFieldValue::Float(right),
201 ) => left == right,
202 (
203 EvaluationContextFieldValue::String(left),
204 EvaluationContextFieldValue::String(right),
205 ) => left == right,
206 (
207 EvaluationContextFieldValue::DateTime(left),
208 EvaluationContextFieldValue::DateTime(right),
209 ) => left == right,
210 (_, _) => false,
211 }
212 }
213}
214
215#[cfg(test)]
216mod tests {
217 use super::*;
218 use crate::*;
219
220 #[test]
221 fn evaluation_context_custom_fields() {
222 let now = OffsetDateTime::now_utc();
223
224 let context = EvaluationContext::default()
225 .with_targeting_key("Some Key")
226 .with_custom_field("Bool", false)
227 .with_custom_field("Bool", EvaluationContextFieldValue::Bool(true))
228 .with_custom_field("Int", 42)
229 .with_custom_field("Float", 42.0)
230 .with_custom_field("String", "StringValue")
231 .with_custom_field("DateTime", now.clone())
232 .with_custom_field(
233 "Struct",
234 EvaluationContextFieldValue::new_struct(EvaluationReason::Cached),
235 );
236
237 if let EvaluationContextFieldValue::Bool(value) = context.custom_fields.get("Bool").unwrap()
239 {
240 assert_eq!(true, *value);
241 } else {
242 panic!()
243 }
244
245 if let EvaluationContextFieldValue::Int(value) = context.custom_fields.get("Int").unwrap() {
247 assert_eq!(42, *value);
248 } else {
249 panic!()
250 }
251
252 if let EvaluationContextFieldValue::Float(value) =
254 context.custom_fields.get("Float").unwrap()
255 {
256 assert_eq!(42.0, *value);
257 } else {
258 panic!()
259 }
260
261 if let EvaluationContextFieldValue::String(value) =
263 context.custom_fields.get("String").unwrap()
264 {
265 assert_eq!("StringValue", value);
266 } else {
267 panic!()
268 }
269
270 if let EvaluationContextFieldValue::DateTime(value) =
272 context.custom_fields.get("DateTime").unwrap()
273 {
274 assert_eq!(now, *value);
275 } else {
276 panic!()
277 }
278
279 if let EvaluationContextFieldValue::Struct(value) =
281 context.custom_fields.get("Struct").unwrap().clone()
282 {
283 let v = value.clone().downcast::<EvaluationReason>().unwrap();
284 assert_eq!(EvaluationReason::Cached, *v);
285 } else {
286 panic!()
287 };
288 }
289}