use serde::{Deserialize, Serialize};
use std::fmt::{Display, Formatter};
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Value {
Bool(bool),
Int(i64),
Float(f64),
String(String),
}
impl Value {
pub fn as_bool(&self) -> Option<bool> {
if let Value::Bool(val) = self {
return Some(*val);
}
None
}
pub fn as_int(&self) -> Option<i64> {
if let Value::Int(val) = self {
return Some(*val);
}
None
}
pub fn as_float(&self) -> Option<f64> {
if let Value::Float(val) = self {
return Some(*val);
}
None
}
pub fn as_str(&self) -> Option<String> {
if let Value::String(val) = self {
return Some(val.clone());
}
None
}
}
impl Display for Value {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Value::Bool(val) => write!(f, "{val}"),
Value::Int(val) => write!(f, "{val}"),
Value::Float(val) => write!(f, "{val}"),
Value::String(val) => f.write_str(val),
}
}
}
pub trait OptionalValueDisplay {
fn to_str(&self) -> String;
}
impl OptionalValueDisplay for Option<&Value> {
fn to_str(&self) -> String {
match self {
None => "none".to_owned(),
Some(value) => format!("{value}"),
}
}
}
pub trait ValuePrimitive: Into<Value> {
fn from_value(value: &Value) -> Option<Self>;
}
macro_rules! primitive_impl {
($ob:ident $to:ident $as_m:ident $t:ty) => (
from_val_to_enum!($ob $to $t);
impl ValuePrimitive for $t {
fn from_value(value: &Value) -> Option<Self> {
value.$as_m()
}
}
)
}
primitive_impl!(Value String as_str String);
primitive_impl!(Value Float as_float f64);
primitive_impl!(Value Int as_int i64);
primitive_impl!(Value Bool as_bool bool);
from_val_to_enum_into!(Value String &str);