Skip to content

Commit 38f9b2c

Browse files
committed
fix(ffe): Fix Rust compilation errors in FFE module
- Fix EvaluationContext construction (no Deserialize/Default) - Fix AssignmentValue::Json struct pattern - Add parse_evaluation_context helper - Resolve workspace inheritance in datadog-ffe Cargo.toml - Remove unused imports
1 parent 77adcc2 commit 38f9b2c

2 files changed

Lines changed: 46 additions & 19 deletions

File tree

components-rs/ffe.rs

Lines changed: 45 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
use datadog_ffe::rules_based::{
2-
self as ffe, AssignmentReason, AssignmentValue, Configuration, EvaluationContext,
3-
EvaluationError, UniversalFlagConfig,
2+
self as ffe, Attribute, AssignmentReason, AssignmentValue, Configuration, EvaluationContext,
3+
EvaluationError, Str, UniversalFlagConfig,
44
};
5-
use serde_json::Value;
65
use std::collections::HashMap;
76
use std::ffi::{c_char, CStr, CString};
87
use std::ptr;
9-
use std::sync::Mutex;
8+
use std::sync::{Arc, Mutex};
109

1110
lazy_static::lazy_static! {
1211
static ref FFE_CONFIG: Mutex<Option<Configuration>> = Mutex::new(None);
@@ -103,12 +102,9 @@ pub extern "C" fn ddog_ffe_evaluate(
103102
// Parse context from JSON
104103
let context = if !context_json.is_null() && context_json_len > 0 {
105104
let bytes = unsafe { std::slice::from_raw_parts(context_json, context_json_len) };
106-
match serde_json::from_slice::<EvaluationContext>(bytes) {
107-
Ok(ctx) => ctx,
108-
Err(_) => EvaluationContext::default(),
109-
}
105+
parse_evaluation_context(bytes)
110106
} else {
111-
EvaluationContext::default()
107+
EvaluationContext::new(None, Arc::new(HashMap::new()))
112108
};
113109

114110
let guard = match FFE_CONFIG.lock() {
@@ -281,16 +277,47 @@ fn assignment_value_to_json(value: &AssignmentValue) -> String {
281277
AssignmentValue::String(s) => serde_json::to_string(s.as_str()).unwrap_or_default(),
282278
AssignmentValue::Integer(i) => i.to_string(),
283279
AssignmentValue::Float(f) => {
284-
// Ensure floats are serialized consistently
285-
if f.fract() == 0.0 && f.abs() < i64::MAX as f64 {
286-
format!("{f:.1}")
287-
} else {
288-
serde_json::Number::from_f64(*f)
289-
.map(|n| n.to_string())
290-
.unwrap_or_else(|| f.to_string())
291-
}
280+
serde_json::Number::from_f64(*f)
281+
.map(|n| n.to_string())
282+
.unwrap_or_else(|| f.to_string())
292283
}
293284
AssignmentValue::Boolean(b) => b.to_string(),
294-
AssignmentValue::Json(v) => serde_json::to_string(v).unwrap_or_default(),
285+
AssignmentValue::Json { raw, .. } => raw.get().to_string(),
286+
}
287+
}
288+
289+
/// Parse a JSON evaluation context into an EvaluationContext.
290+
/// Expected format: {"targeting_key": "...", "attributes": {"key": value, ...}}
291+
fn parse_evaluation_context(bytes: &[u8]) -> EvaluationContext {
292+
let parsed: serde_json::Value = match serde_json::from_slice(bytes) {
293+
Ok(v) => v,
294+
Err(_) => return EvaluationContext::new(None, Arc::new(HashMap::new())),
295+
};
296+
297+
let targeting_key = parsed
298+
.get("targeting_key")
299+
.and_then(|v| v.as_str())
300+
.map(Str::from);
301+
302+
let mut attributes = HashMap::new();
303+
if let Some(attrs) = parsed.get("attributes").and_then(|v| v.as_object()) {
304+
for (k, v) in attrs {
305+
let attr = match v {
306+
serde_json::Value::String(s) => Attribute::from(s.as_str()),
307+
serde_json::Value::Number(n) => {
308+
if let Some(f) = n.as_f64() {
309+
Attribute::from(f)
310+
} else {
311+
continue;
312+
}
313+
}
314+
serde_json::Value::Bool(b) => Attribute::from(*b),
315+
serde_json::Value::Null => continue,
316+
_ => continue,
317+
};
318+
attributes.insert(Str::from(k.as_str()), attr);
319+
}
295320
}
321+
322+
EvaluationContext::new(targeting_key, Arc::new(attributes))
296323
}

libdatadog

0 commit comments

Comments
 (0)