use std::collections::HashMap;
use std::fmt::{Display, Formatter};
use crate::EvaluationError;
use super::Value;
pub type EvaluationResult<T> = Result<T, EvaluationError>;
#[derive(Clone, Default, Debug)]
pub struct EvaluationDetails<T> {
pub flag_key: String,
pub value: T,
pub reason: Option<EvaluationReason>,
pub variant: Option<String>,
pub flag_metadata: FlagMetadata,
}
impl EvaluationDetails<Value> {
pub fn error_reason(flag_key: impl Into<String>, value: impl Into<Value>) -> Self {
Self {
value: value.into(),
flag_key: flag_key.into(),
reason: Some(EvaluationReason::Error),
variant: None,
flag_metadata: FlagMetadata::default(),
}
}
}
impl<T> EvaluationDetails<T>
where
T: Into<Value>,
{
pub fn into_value(self) -> EvaluationDetails<Value> {
EvaluationDetails {
flag_key: self.flag_key,
value: self.value.into(),
reason: self.reason,
variant: self.variant,
flag_metadata: self.flag_metadata,
}
}
}
#[derive(Clone, Default, Eq, PartialEq, Debug)]
pub enum EvaluationReason {
Static,
Default,
TargetingMatch,
Split,
Cached,
Disabled,
#[default]
Unknown,
Error,
Other(String),
}
impl Display for EvaluationReason {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let reason = match self {
Self::Static => "STATIC",
Self::Default => "DEFAULT",
Self::TargetingMatch => "TARGETING_MATCH",
Self::Split => "SPLIT",
Self::Cached => "CACHED",
Self::Disabled => "DISABLED",
Self::Unknown => "UNKNOWN",
Self::Error => "ERROR",
Self::Other(reason) => reason.as_str(),
};
write!(f, "{reason}")
}
}
#[derive(Clone, Default, PartialEq, Debug)]
pub struct FlagMetadata {
pub values: HashMap<String, FlagMetadataValue>,
}
impl FlagMetadata {
#[must_use]
pub fn with_value(
mut self,
key: impl Into<String>,
value: impl Into<FlagMetadataValue>,
) -> Self {
self.add_value(key, value);
self
}
pub fn add_value(&mut self, key: impl Into<String>, value: impl Into<FlagMetadataValue>) {
self.values.insert(key.into(), value.into());
}
}
#[derive(Clone, PartialEq, Debug)]
#[allow(missing_docs)]
pub enum FlagMetadataValue {
Bool(bool),
Int(i64),
Float(f64),
String(String),
}
impl From<bool> for FlagMetadataValue {
fn from(value: bool) -> Self {
Self::Bool(value)
}
}
impl From<i8> for FlagMetadataValue {
fn from(value: i8) -> Self {
Self::Int(value.into())
}
}
impl From<i16> for FlagMetadataValue {
fn from(value: i16) -> Self {
Self::Int(value.into())
}
}
impl From<i32> for FlagMetadataValue {
fn from(value: i32) -> Self {
Self::Int(value.into())
}
}
impl From<i64> for FlagMetadataValue {
fn from(value: i64) -> Self {
Self::Int(value)
}
}
impl From<u8> for FlagMetadataValue {
fn from(value: u8) -> Self {
Self::Int(value.into())
}
}
impl From<u16> for FlagMetadataValue {
fn from(value: u16) -> Self {
Self::Int(value.into())
}
}
impl From<u32> for FlagMetadataValue {
fn from(value: u32) -> Self {
Self::Int(value.into())
}
}
impl From<f32> for FlagMetadataValue {
fn from(value: f32) -> Self {
Self::Float(value.into())
}
}
impl From<f64> for FlagMetadataValue {
fn from(value: f64) -> Self {
Self::Float(value)
}
}
impl From<String> for FlagMetadataValue {
fn from(value: String) -> Self {
Self::String(value)
}
}
impl From<&str> for FlagMetadataValue {
fn from(value: &str) -> Self {
Self::String(value.into())
}
}