use std::fmt::Display;
use super::{state_error::StateError, unit_codec_name::UnitCodecType};
use crate::model::traversal::state::state_variable::StateVar;
use ordered_float::OrderedFloat;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum CustomFeatureFormat {
FloatingPoint { initial: OrderedFloat<f64> },
SignedInteger { initial: i64 },
UnsignedInteger { initial: u64 },
Boolean { initial: bool },
}
impl Default for CustomFeatureFormat {
fn default() -> Self {
Self::FloatingPoint {
initial: OrderedFloat(0.0),
}
}
}
impl Display for CustomFeatureFormat {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let initial = self
.initial()
.map(|i| format!("{}", i))
.unwrap_or_else(|_| String::from("<invalid initial argument>"));
write!(f, "{}: {}", self.name(), initial)
}
}
impl CustomFeatureFormat {
pub fn name(&self) -> String {
match self {
CustomFeatureFormat::FloatingPoint { initial: _ } => {
UnitCodecType::FloatingPoint.to_string()
}
CustomFeatureFormat::SignedInteger { initial: _ } => {
UnitCodecType::SignedInteger.to_string()
}
CustomFeatureFormat::UnsignedInteger { initial: _ } => {
UnitCodecType::UnsignedInteger.to_string()
}
CustomFeatureFormat::Boolean { initial: _ } => UnitCodecType::Boolean.to_string(),
}
}
pub fn initial(&self) -> Result<StateVar, StateError> {
match self {
CustomFeatureFormat::FloatingPoint { initial } => self.encode_f64(initial),
CustomFeatureFormat::SignedInteger { initial } => self.encode_i64(initial),
CustomFeatureFormat::UnsignedInteger { initial } => self.encode_u64(initial),
CustomFeatureFormat::Boolean { initial } => self.encode_bool(initial),
}
}
pub fn encode_f64(&self, value: &f64) -> Result<StateVar, StateError> {
match self {
CustomFeatureFormat::FloatingPoint { initial: _ } => Ok(StateVar(*value)),
_ => Err(StateError::EncodeError(
UnitCodecType::FloatingPoint.to_string(),
self.name(),
)),
}
}
pub fn encode_i64(&self, value: &i64) -> Result<StateVar, StateError> {
match self {
CustomFeatureFormat::SignedInteger { initial: _ } => Ok(StateVar(*value as f64)),
_ => Err(StateError::EncodeError(
UnitCodecType::SignedInteger.to_string(),
self.name(),
)),
}
}
pub fn encode_u64(&self, value: &u64) -> Result<StateVar, StateError> {
match self {
CustomFeatureFormat::UnsignedInteger { initial: _ } => Ok(StateVar(*value as f64)),
_ => Err(StateError::EncodeError(
UnitCodecType::UnsignedInteger.to_string(),
self.name(),
)),
}
}
pub fn encode_bool(&self, value: &bool) -> Result<StateVar, StateError> {
match self {
CustomFeatureFormat::Boolean { initial: _ } => {
if *value {
Ok(StateVar(1.0))
} else {
Ok(StateVar(0.0))
}
}
_ => Err(StateError::EncodeError(
UnitCodecType::Boolean.to_string(),
self.name(),
)),
}
}
pub fn decode_f64(&self, value: &StateVar) -> Result<f64, StateError> {
match self {
CustomFeatureFormat::FloatingPoint { initial: _ } => Ok(value.0),
_ => Err(StateError::DecodeError(
*value,
UnitCodecType::FloatingPoint.to_string(),
self.name(),
)),
}
}
pub fn decode_i64(&self, value: &StateVar) -> Result<i64, StateError> {
match self {
CustomFeatureFormat::SignedInteger { initial: _ } => Ok(value.0 as i64),
_ => Err(StateError::DecodeError(
*value,
UnitCodecType::SignedInteger.to_string(),
self.name(),
)),
}
}
pub fn decode_u64(&self, value: &StateVar) -> Result<u64, StateError> {
match self {
CustomFeatureFormat::UnsignedInteger { initial: _ } => {
if value < &StateVar::ZERO {
Err(StateError::ValueError(
*value,
UnitCodecType::UnsignedInteger.to_string(),
))
} else {
Ok(value.0 as u64)
}
}
_ => Err(StateError::DecodeError(
*value,
UnitCodecType::UnsignedInteger.to_string(),
self.name(),
)),
}
}
pub fn decode_bool(&self, value: &StateVar) -> Result<bool, StateError> {
match self {
CustomFeatureFormat::Boolean { initial: _ } => {
let is_false = value.0 == 0.0;
if is_false {
Ok(false)
} else {
Ok(true)
}
}
_ => Err(StateError::DecodeError(
*value,
UnitCodecType::Boolean.to_string(),
self.name(),
)),
}
}
}