use std::sync::Arc;
use crate::hashmap::HashMap;
use serde::Serialize;
use crate::{
attributes::{Attributes, CategoricalAttribute, NumericAttribute},
eval::eval_details::EvaluationDetails,
SdkMetadata, Str,
};
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Events {
pub assignment: Option<AssignmentEvent>,
pub bandit: Option<BanditEvent>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AssignmentEventBase {
pub feature_flag: Str,
pub allocation: Str,
pub experiment: String,
pub variation: Str,
pub meta_data: EventMetaData,
#[serde(flatten)]
pub extra_logging: HashMap<String, String>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AssignmentEvent {
#[serde(flatten)]
pub base: Arc<AssignmentEventBase>,
pub subject: Str,
pub subject_attributes: Arc<Attributes>,
pub timestamp: chrono::DateTime<chrono::Utc>,
#[serde(skip_serializing_if = "Option::is_none")]
pub evaluation_details: Option<Arc<EvaluationDetails>>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct BanditEvent {
pub flag_key: Str,
pub bandit_key: Str,
pub subject: Str,
pub action: Str,
pub action_probability: f64,
pub optimality_gap: f64,
pub model_version: Str,
pub timestamp: String,
pub subject_numeric_attributes: Arc<HashMap<Str, NumericAttribute>>,
pub subject_categorical_attributes: Arc<HashMap<Str, CategoricalAttribute>>,
pub action_numeric_attributes: Arc<HashMap<Str, NumericAttribute>>,
pub action_categorical_attributes: Arc<HashMap<Str, CategoricalAttribute>>,
pub meta_data: EventMetaData,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct EventMetaData {
pub sdk_name: &'static str,
pub sdk_version: &'static str,
pub core_version: &'static str,
}
impl From<SdkMetadata> for EventMetaData {
fn from(sdk: SdkMetadata) -> EventMetaData {
(&sdk).into()
}
}
impl From<&SdkMetadata> for EventMetaData {
fn from(sdk: &SdkMetadata) -> EventMetaData {
EventMetaData {
sdk_name: sdk.name,
sdk_version: sdk.version,
core_version: env!("CARGO_PKG_VERSION"),
}
}
}
#[cfg(feature = "pyo3")]
mod pyo3_impl {
use pyo3::prelude::*;
use super::{AssignmentEvent, BanditEvent};
impl<'py> IntoPyObject<'py> for &AssignmentEvent {
type Target = PyAny;
type Output = Bound<'py, Self::Target>;
type Error = PyErr;
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
serde_pyobject::to_pyobject(py, self).map_err(|err| err.0)
}
}
impl<'py> IntoPyObject<'py> for &BanditEvent {
type Target = PyAny;
type Output = Bound<'py, Self::Target>;
type Error = PyErr;
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
serde_pyobject::to_pyobject(py, self).map_err(|err| err.0)
}
}
}
#[cfg(feature = "magnus")]
mod magnus_impl {
use magnus::IntoValue;
use super::{AssignmentEvent, BanditEvent};
impl IntoValue for AssignmentEvent {
fn into_value_with(self, handle: &magnus::Ruby) -> magnus::Value {
serde_magnus::serialize(handle, &self)
.expect("AssignmentEvent should always be serializable to Ruby")
}
}
impl IntoValue for BanditEvent {
fn into_value_with(self, handle: &magnus::Ruby) -> magnus::Value {
serde_magnus::serialize(handle, &self)
.expect("BanditEvent should always be serializable to Ruby")
}
}
}