Skip to main content

open_feature/evaluation/
details.rs

1use std::collections::HashMap;
2use std::fmt::{Display, Formatter};
3
4use crate::EvaluationError;
5
6use super::Value;
7
8/// The result of evaluation.
9pub type EvaluationResult<T> = Result<T, EvaluationError>;
10
11// ============================================================
12//  EvaluationDetails
13// ============================================================
14
15/// The result of the flag evaluation process, and made available in the detailed flag resolution
16/// functions.
17#[derive(Clone, Default, Debug)]
18pub struct EvaluationDetails<T> {
19    /// The flag key argument passed to the detailed flag evaluation method.
20    pub flag_key: String,
21
22    /// The value of evaluation result.
23    pub value: T,
24
25    /// The optional returned by the configured provider.
26    pub reason: Option<EvaluationReason>,
27
28    /// The optional variant returned by the configured provider.
29    pub variant: Option<String>,
30
31    /// The optional flag metadata returned by the configured provider.
32    /// If the provider returns nothing, it is set to the default value.
33    pub flag_metadata: FlagMetadata,
34}
35
36impl EvaluationDetails<Value> {
37    /// Creates a new `EvaluationDetails` instance with an error reason.
38    pub fn error_reason(flag_key: impl Into<String>, value: impl Into<Value>) -> Self {
39        Self {
40            value: value.into(),
41            flag_key: flag_key.into(),
42            reason: Some(EvaluationReason::Error),
43            variant: None,
44            flag_metadata: FlagMetadata::default(),
45        }
46    }
47}
48
49impl<T> EvaluationDetails<T>
50where
51    T: Into<Value>,
52{
53    /// Convert the evaluation result of type `T` to `Value`.
54    pub fn into_value(self) -> EvaluationDetails<Value> {
55        EvaluationDetails {
56            flag_key: self.flag_key,
57            value: self.value.into(),
58            reason: self.reason,
59            variant: self.variant,
60            flag_metadata: self.flag_metadata,
61        }
62    }
63}
64
65// ============================================================
66//  EvaluationReason
67// ============================================================
68
69/// Reason for evaluation.
70#[derive(Clone, Default, Eq, PartialEq, Debug)]
71pub enum EvaluationReason {
72    /// The resolved value is static (no dynamic evaluation).
73    Static,
74
75    /// The resolved value fell back to a pre-configured value (no dynamic evaluation occurred or
76    /// dynamic evaluation yielded no result).
77    Default,
78
79    /// The resolved value was the result of a dynamic evaluation, such as a rule or specific
80    /// user-targeting.
81    TargetingMatch,
82
83    /// The resolved value was the result of pseudorandom assignment.
84    Split,
85
86    /// The resolved value was retrieved from cache.
87    Cached,
88
89    /// The resolved value was the result of the flag being disabled in the management system.
90    Disabled,
91
92    /// The reason for the resolved value could not be determined.
93    #[default]
94    Unknown,
95
96    /// The resolved value was the result of an error.
97    Error,
98
99    /// Other custom reason.
100    Other(String),
101}
102
103impl Display for EvaluationReason {
104    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
105        let reason = match self {
106            Self::Static => "STATIC",
107            Self::Default => "DEFAULT",
108            Self::TargetingMatch => "TARGETING_MATCH",
109            Self::Split => "SPLIT",
110            Self::Cached => "CACHED",
111            Self::Disabled => "DISABLED",
112            Self::Unknown => "UNKNOWN",
113            Self::Error => "ERROR",
114            Self::Other(reason) => reason.as_str(),
115        };
116        write!(f, "{reason}")
117    }
118}
119
120// ============================================================
121//  FlagMetadata
122// ============================================================
123
124/// A structure which supports definition of arbitrary properties, with keys of type string, and
125/// values of type boolean, string, or number.
126///
127/// This structure is populated by a provider for use by an Application Author (via the Evaluation
128/// API) or an Application Integrator (via hooks).
129#[derive(Clone, Default, PartialEq, Debug)]
130pub struct FlagMetadata {
131    /// The fields of the metadata.
132    pub values: HashMap<String, FlagMetadataValue>,
133}
134
135impl FlagMetadata {
136    /// Append givne `key` and `value` to the fields of metadata.
137    #[must_use]
138    pub fn with_value(
139        mut self,
140        key: impl Into<String>,
141        value: impl Into<FlagMetadataValue>,
142    ) -> Self {
143        self.add_value(key, value);
144        self
145    }
146
147    /// Append givne `key` and `value` to the fields of metadata.
148    pub fn add_value(&mut self, key: impl Into<String>, value: impl Into<FlagMetadataValue>) {
149        self.values.insert(key.into(), value.into());
150    }
151}
152
153// ============================================================
154//  FlagMetadataValue
155// ============================================================
156
157/// Supported values of flag metadata fields.
158#[derive(Clone, PartialEq, Debug)]
159#[allow(missing_docs)]
160pub enum FlagMetadataValue {
161    Bool(bool),
162    Int(i64),
163    Float(f64),
164    String(String),
165}
166
167impl From<bool> for FlagMetadataValue {
168    fn from(value: bool) -> Self {
169        Self::Bool(value)
170    }
171}
172
173impl From<i8> for FlagMetadataValue {
174    fn from(value: i8) -> Self {
175        Self::Int(value.into())
176    }
177}
178
179impl From<i16> for FlagMetadataValue {
180    fn from(value: i16) -> Self {
181        Self::Int(value.into())
182    }
183}
184
185impl From<i32> for FlagMetadataValue {
186    fn from(value: i32) -> Self {
187        Self::Int(value.into())
188    }
189}
190
191impl From<i64> for FlagMetadataValue {
192    fn from(value: i64) -> Self {
193        Self::Int(value)
194    }
195}
196
197impl From<u8> for FlagMetadataValue {
198    fn from(value: u8) -> Self {
199        Self::Int(value.into())
200    }
201}
202
203impl From<u16> for FlagMetadataValue {
204    fn from(value: u16) -> Self {
205        Self::Int(value.into())
206    }
207}
208
209impl From<u32> for FlagMetadataValue {
210    fn from(value: u32) -> Self {
211        Self::Int(value.into())
212    }
213}
214
215impl From<f32> for FlagMetadataValue {
216    fn from(value: f32) -> Self {
217        Self::Float(value.into())
218    }
219}
220
221impl From<f64> for FlagMetadataValue {
222    fn from(value: f64) -> Self {
223        Self::Float(value)
224    }
225}
226
227impl From<String> for FlagMetadataValue {
228    fn from(value: String) -> Self {
229        Self::String(value)
230    }
231}
232
233impl From<&str> for FlagMetadataValue {
234    fn from(value: &str) -> Self {
235        Self::String(value.into())
236    }
237}