Skip to content

Commit 17ddda4

Browse files
authored
feat: add an optional cow interface for context properties and results (#332)
1 parent e311598 commit 17ddda4

File tree

3 files changed

+54
-20
lines changed

3 files changed

+54
-20
lines changed

unleash-yggdrasil/src/lib.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -759,7 +759,8 @@ fn get_seed<'a>(stickiness: Option<&str>, context: &'a EnrichedContext<'a>) -> O
759759
"remoteAddress" => context.remote_address,
760760
_ => context
761761
.properties
762-
.and_then(|props| props.get(custom).map(|v| v.as_str())),
762+
.as_ref()
763+
.and_then(|props| props.get(custom)),
763764
},
764765
}
765766
}
@@ -775,11 +776,10 @@ fn lookup_override_context<'a>(
775776
"appName" => context.app_name,
776777
"currentTime" => context.current_time,
777778
"remoteAddress" => context.remote_address,
778-
_ => context.properties.and_then(|props| {
779-
props
780-
.get(variant_override.context_name.as_str())
781-
.map(|s| s.as_str())
782-
}),
779+
_ => context
780+
.properties
781+
.as_ref()
782+
.and_then(|props| props.get(variant_override.context_name.as_str())),
783783
}
784784
}
785785

unleash-yggdrasil/src/state.rs

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,48 @@
1-
use std::collections::HashMap;
1+
use std::{borrow::Cow, collections::HashMap};
22
use unleash_types::client_features::Context;
33

4+
pub type PropertiesCow<'a> = HashMap<Cow<'a, str>, Cow<'a, str>>;
5+
pub type ExternalResultsCow<'a> = HashMap<Cow<'a, str>, bool>;
6+
7+
#[derive(Copy, Clone)]
8+
pub enum PropertiesRef<'a> {
9+
Strings(&'a HashMap<String, String>),
10+
Cows(&'a PropertiesCow<'a>),
11+
}
12+
13+
#[derive(Copy, Clone)]
14+
pub enum ExternalResultsRef<'a> {
15+
Strings(&'a HashMap<String, bool>),
16+
Cows(&'a ExternalResultsCow<'a>),
17+
}
18+
19+
impl<'a> PropertiesRef<'a> {
20+
pub fn get(&self, key: &str) -> Option<&'a str> {
21+
match self {
22+
PropertiesRef::Strings(m) => m.get(key).map(|v| v.as_str()),
23+
PropertiesRef::Cows(m) => m.get(key).map(|v| v.as_ref()),
24+
}
25+
}
26+
}
27+
28+
impl<'a> ExternalResultsRef<'a> {
29+
pub fn get(&self, key: &str) -> Option<bool> {
30+
match self {
31+
ExternalResultsRef::Strings(m) => m.get(key).copied(),
32+
ExternalResultsRef::Cows(m) => m.get(key).copied(),
33+
}
34+
}
35+
}
36+
437
pub struct EnrichedContext<'a> {
538
pub user_id: Option<&'a str>,
639
pub session_id: Option<&'a str>,
740
pub environment: Option<&'a str>,
841
pub app_name: Option<&'a str>,
942
pub current_time: Option<&'a str>,
1043
pub remote_address: Option<&'a str>,
11-
pub properties: Option<&'a HashMap<String, String>>,
12-
pub external_results: Option<&'a HashMap<String, bool>>,
44+
pub properties: Option<PropertiesRef<'a>>,
45+
pub external_results: Option<ExternalResultsRef<'a>>,
1346
pub toggle_name: &'a str,
1447
pub runtime_hostname: Option<&'a str>,
1548
}
@@ -27,8 +60,8 @@ impl<'a> EnrichedContext<'a> {
2760
app_name: context.app_name.as_deref(),
2861
current_time: context.current_time.as_deref(),
2962
remote_address: context.remote_address.as_deref(),
30-
properties: context.properties.as_ref(),
31-
external_results,
63+
properties: context.properties.as_ref().map(PropertiesRef::Strings),
64+
external_results: external_results.map(ExternalResultsRef::Strings),
3265
toggle_name,
3366
runtime_hostname: None,
3467
}

unleash-yggdrasil/src/strategy_parsing.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ fn context_property(node: Pairs<Rule>) -> ContextResolver {
189189
.properties
190190
.as_ref()?
191191
.get(context_name.as_str())
192-
.map(|v| Cow::Borrowed(v.as_str()))
192+
.map(Cow::Borrowed)
193193
})
194194
}
195195

@@ -530,7 +530,6 @@ fn external_value(node: Pairs<Rule>) -> CompileResult<RuleFragment> {
530530
.external_results
531531
.as_ref()
532532
.and_then(|strategy_results| strategy_results.get(&strategy_index))
533-
.copied()
534533
.unwrap_or(false)
535534
}))
536535
}
@@ -661,6 +660,8 @@ pub fn compile_rule(rule: &str) -> CompileResult<RuleFragment> {
661660

662661
#[cfg(test)]
663662
mod tests {
663+
use crate::state::{ExternalResultsRef, PropertiesRef};
664+
664665
use super::*;
665666
use std::collections::HashMap;
666667
use test_case::test_case;
@@ -825,7 +826,7 @@ mod tests {
825826
let context = Context {
826827
current_time: None,
827828
user_id: Some("6".into()),
828-
properties: Some(&context_property),
829+
properties: Some(PropertiesRef::Strings(&context_property)),
829830
session_id: None,
830831
environment: None,
831832
app_name: None,
@@ -872,7 +873,7 @@ mod tests {
872873
let context = Context {
873874
user_id: Some("42".into()),
874875
session_id: Some("7".into()),
875-
properties: Some(&props),
876+
properties: Some(PropertiesRef::Strings(&props)),
876877
..Context::default()
877878
};
878879

@@ -958,7 +959,7 @@ mod tests {
958959
let mut context = Context::default();
959960
let mut props = HashMap::new();
960961
props.insert("cutoff".into(), "2022-01-25T13:00:00.000Z".into());
961-
context.properties = Some(&props);
962+
context.properties = Some(PropertiesRef::Strings(&props));
962963

963964
assert_eq!(rule(&context), expected);
964965
}
@@ -971,7 +972,7 @@ mod tests {
971972
let mut context = Context::default();
972973
let mut props = HashMap::new();
973974
props.insert("cutoff".into(), "2022-01-25T13:00:00.000Z".into());
974-
context.properties = Some(&props);
975+
context.properties = Some(PropertiesRef::Strings(&props));
975976

976977
assert!(!rule(&context));
977978
}
@@ -1052,7 +1053,7 @@ mod tests {
10521053
custom_strategy_results.insert("test_value".to_string(), true);
10531054

10541055
let context = Context {
1055-
external_results: Some(&custom_strategy_results),
1056+
external_results: Some(ExternalResultsRef::Strings(&custom_strategy_results)),
10561057
..Context::default()
10571058
};
10581059

@@ -1068,7 +1069,7 @@ mod tests {
10681069
custom_strategy_results.insert("test_value".to_string(), true);
10691070

10701071
let context = Context {
1071-
external_results: Some(&custom_strategy_results),
1072+
external_results: Some(ExternalResultsRef::Strings(&custom_strategy_results)),
10721073
..Context::default()
10731074
};
10741075

@@ -1077,7 +1078,7 @@ mod tests {
10771078
let mut custom_strategy_results = HashMap::new();
10781079
custom_strategy_results.insert("test_value".to_string(), false);
10791080
let context = Context {
1080-
external_results: Some(&custom_strategy_results),
1081+
external_results: Some(ExternalResultsRef::Strings(&custom_strategy_results)),
10811082
..Context::default()
10821083
};
10831084

0 commit comments

Comments
 (0)