flagsmith_flag_engine/engine_eval/
context.rs1use crate::types::FlagsmithValue;
2use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4
5#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
6#[serde(rename_all = "snake_case")]
7pub enum SegmentSource {
8 Api,
10 IdentityOverride,
12}
13
14#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq)]
16pub struct FeatureMetadata {
17 #[serde(default)]
19 pub feature_id: u32,
20}
21
22#[derive(Clone, Debug, Serialize, Deserialize)]
24pub struct FeatureValue {
25 pub value: FlagsmithValue,
27 pub weight: f64,
29 #[serde(skip_serializing_if = "Option::is_none")]
31 pub priority: Option<f64>,
32}
33
34#[derive(Clone, Debug, Serialize, Deserialize)]
36pub struct FeatureContext {
37 pub key: String,
39 pub name: String,
41 pub enabled: bool,
43 pub value: FlagsmithValue,
45 #[serde(skip_serializing_if = "Option::is_none")]
47 pub priority: Option<f64>,
48 #[serde(default, skip_serializing_if = "Vec::is_empty")]
50 pub variants: Vec<FeatureValue>,
51 #[serde(default)]
53 pub metadata: FeatureMetadata,
54}
55
56#[derive(Clone, Debug, Serialize, Deserialize)]
58pub struct EnvironmentContext {
59 pub key: String,
61 pub name: String,
63}
64
65#[derive(Clone, Debug, Serialize, Deserialize)]
67pub struct IdentityContext {
68 pub identifier: String,
70 #[serde(default)]
73 pub key: String,
74 #[serde(default)]
76 pub traits: HashMap<String, FlagsmithValue>,
77}
78
79#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
81#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
82pub enum ConditionOperator {
83 Equal,
84 NotEqual,
85 GreaterThan,
86 GreaterThanInclusive,
87 LessThan,
88 LessThanInclusive,
89 Contains,
90 NotContains,
91 In,
92 Regex,
93 PercentageSplit,
94 Modulo,
95 IsSet,
96 IsNotSet,
97}
98
99#[derive(Clone, Debug, Serialize)]
101#[serde(untagged)]
102pub enum ConditionValue {
103 Multiple(Vec<String>),
105 Single(String),
107}
108
109impl<'de> serde::Deserialize<'de> for ConditionValue {
110 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
111 where
112 D: serde::Deserializer<'de>,
113 {
114 use serde_json::Value;
115 let value: Value = serde::Deserialize::deserialize(deserializer)?;
116
117 match value {
118 Value::Array(arr) => {
120 let strings: Vec<String> = arr
121 .into_iter()
122 .map(|v| match v {
123 Value::String(s) => s,
124 _ => v.to_string(),
125 })
126 .collect();
127 Ok(ConditionValue::Multiple(strings))
128 }
129 Value::String(s) => {
131 if s.trim().starts_with('[') {
132 if let Ok(arr) = serde_json::from_str::<Vec<String>>(&s) {
134 return Ok(ConditionValue::Multiple(arr));
135 }
136 }
137 Ok(ConditionValue::Single(s))
139 }
140 _ => Ok(ConditionValue::Single(value.to_string())),
142 }
143 }
144}
145
146impl ConditionValue {
147 pub fn as_string(&self) -> String {
149 match self {
150 ConditionValue::Single(s) => s.clone(),
151 ConditionValue::Multiple(arr) => arr.join(","),
152 }
153 }
154
155 pub fn as_vec(&self) -> Vec<String> {
157 match self {
158 ConditionValue::Single(s) => s.split(',').map(|s| s.trim().to_string()).collect(),
159 ConditionValue::Multiple(arr) => arr.clone(),
160 }
161 }
162
163 pub fn contains_string(&self, search: &str) -> bool {
165 match self {
166 ConditionValue::Single(s) => s.split(',').any(|v| v.trim() == search),
167 ConditionValue::Multiple(arr) => arr.iter().any(|v| v == search),
168 }
169 }
170}
171
172#[derive(Clone, Debug, Serialize, Deserialize)]
174pub struct Condition {
175 pub operator: ConditionOperator,
177 pub property: String,
179 pub value: ConditionValue,
181}
182
183#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
185#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
186pub enum SegmentRuleType {
187 All,
188 Any,
189 None,
190}
191
192#[derive(Clone, Debug, Serialize, Deserialize)]
194pub struct SegmentRule {
195 #[serde(rename = "type")]
197 pub rule_type: SegmentRuleType,
198 #[serde(default)]
200 pub conditions: Vec<Condition>,
201 #[serde(default)]
203 pub rules: Vec<SegmentRule>,
204}
205
206#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
208pub struct SegmentMetadata {
209 #[serde(skip_serializing_if = "Option::is_none")]
211 pub segment_id: Option<i32>,
212 pub source: SegmentSource,
214}
215
216impl Default for SegmentMetadata {
217 fn default() -> Self {
218 Self {
219 segment_id: None,
220 source: SegmentSource::Api,
221 }
222 }
223}
224
225#[derive(Clone, Debug, Serialize, Deserialize)]
227pub struct SegmentContext {
228 pub key: String,
230 pub name: String,
232 #[serde(default)]
234 pub metadata: SegmentMetadata,
235 #[serde(default)]
237 pub overrides: Vec<FeatureContext>,
238 pub rules: Vec<SegmentRule>,
240}
241
242#[derive(Clone, Debug, Serialize, Deserialize)]
245pub struct EngineEvaluationContext {
246 pub environment: EnvironmentContext,
248
249 #[serde(default)]
251 pub features: HashMap<String, FeatureContext>,
252
253 #[serde(default)]
255 pub segments: HashMap<String, SegmentContext>,
256
257 #[serde(skip_serializing_if = "Option::is_none")]
259 pub identity: Option<IdentityContext>,
260}