eppo_core/attributes/
context_attributes.rs1use std::{collections::HashMap, sync::Arc};
2
3use serde::{Deserialize, Serialize};
4
5use crate::Str;
6
7use super::{
8 AttributeValue, AttributeValueImpl, Attributes, CategoricalAttribute, NumericAttribute,
9};
10
11#[derive(Debug, Clone, Default, Serialize, Deserialize)]
17#[serde(rename_all = "camelCase")]
18#[cfg_attr(feature = "pyo3", pyo3::pyclass(module = "eppo_client"))]
19pub struct ContextAttributes {
20 #[serde(alias = "numericAttributes")]
25 pub numeric: Arc<HashMap<Str, NumericAttribute>>,
26 #[serde(alias = "categoricalAttributes")]
29 pub categorical: Arc<HashMap<Str, CategoricalAttribute>>,
30}
31
32impl From<Attributes> for ContextAttributes {
33 fn from(value: Attributes) -> Self {
34 ContextAttributes::from_iter(value)
35 }
36}
37
38impl<K, V> FromIterator<(K, V)> for ContextAttributes
39where
40 K: Into<Str>,
41 V: Into<AttributeValue>,
42{
43 fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
44 let (categorical, numeric) = iter.into_iter().fold(
45 (HashMap::new(), HashMap::new()),
46 |(mut categorical, mut numeric), (key, value)| {
47 match value.into() {
48 AttributeValue(AttributeValueImpl::Categorical(value)) => {
49 categorical.insert(key.into(), value);
50 }
51 AttributeValue(AttributeValueImpl::Numeric(value)) => {
52 numeric.insert(key.into(), value);
53 }
54 AttributeValue(AttributeValueImpl::Null) => {
55 }
57 }
58 (categorical, numeric)
59 },
60 );
61 ContextAttributes {
62 numeric: Arc::new(numeric),
63 categorical: Arc::new(categorical),
64 }
65 }
66}
67
68impl ContextAttributes {
69 pub fn to_generic_attributes(&self) -> Attributes {
71 let mut result = HashMap::with_capacity(self.numeric.len() + self.categorical.capacity());
72 for (key, value) in self.numeric.iter() {
73 result.insert(key.clone(), value.clone().into());
74 }
75 for (key, value) in self.categorical.iter() {
76 result.insert(key.clone(), value.clone().into());
77 }
78 result
79 }
80}
81
82#[cfg(feature = "pyo3")]
83mod pyo3_impl {
84 use std::{collections::HashMap, sync::Arc};
85
86 use pyo3::prelude::*;
87
88 use crate::{Attributes, CategoricalAttribute, NumericAttribute, Str};
89
90 use super::ContextAttributes;
91
92 #[pymethods]
93 impl ContextAttributes {
94 #[new]
95 fn new(
96 numeric_attributes: HashMap<Str, NumericAttribute>,
97 categorical_attributes: HashMap<Str, CategoricalAttribute>,
98 ) -> ContextAttributes {
99 ContextAttributes {
100 numeric: Arc::new(numeric_attributes),
101 categorical: Arc::new(categorical_attributes),
102 }
103 }
104
105 #[staticmethod]
111 fn empty() -> ContextAttributes {
112 ContextAttributes::default()
113 }
114
115 #[staticmethod]
125 fn from_dict(attributes: Attributes) -> ContextAttributes {
126 attributes.into()
127 }
128
129 #[getter]
132 fn get_numeric_attributes(&self, py: Python) -> PyObject {
133 self.numeric.to_object(py)
134 }
135
136 #[getter]
139 fn get_categorical_attributes(&self, py: Python) -> PyObject {
140 self.categorical.to_object(py)
141 }
142 }
143}