use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
pub type Attributes = BTreeMap<String, AttrValue>;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum AttrValue {
Bool(bool),
Int(i64),
Float(f64),
Str(String),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ValueType {
Bool,
Int,
Float,
Str,
}
impl AttrValue {
pub fn value_type(&self) -> ValueType {
match self {
AttrValue::Bool(_) => ValueType::Bool,
AttrValue::Int(_) => ValueType::Int,
AttrValue::Float(_) => ValueType::Float,
AttrValue::Str(_) => ValueType::Str,
}
}
}
impl From<bool> for AttrValue {
fn from(v: bool) -> Self {
AttrValue::Bool(v)
}
}
impl From<i64> for AttrValue {
fn from(v: i64) -> Self {
AttrValue::Int(v)
}
}
impl From<u32> for AttrValue {
fn from(v: u32) -> Self {
AttrValue::Int(v as i64)
}
}
impl From<f64> for AttrValue {
fn from(v: f64) -> Self {
AttrValue::Float(v)
}
}
impl From<String> for AttrValue {
fn from(v: String) -> Self {
AttrValue::Str(v)
}
}
impl From<&str> for AttrValue {
fn from(v: &str) -> Self {
AttrValue::Str(v.to_string())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn value_type_maps_each_variant() {
assert_eq!(AttrValue::Bool(true).value_type(), ValueType::Bool);
assert_eq!(AttrValue::Int(1).value_type(), ValueType::Int);
assert_eq!(AttrValue::Float(1.5).value_type(), ValueType::Float);
assert_eq!(AttrValue::Str("x".into()).value_type(), ValueType::Str);
}
#[test]
fn from_impls_cover_each_scalar() {
assert_eq!(AttrValue::from(true), AttrValue::Bool(true));
assert_eq!(AttrValue::from(7_i64), AttrValue::Int(7));
assert_eq!(AttrValue::from(7_u32), AttrValue::Int(7));
assert_eq!(AttrValue::from(2.5_f64), AttrValue::Float(2.5));
assert_eq!(AttrValue::from("s".to_string()), AttrValue::Str("s".into()));
assert_eq!(AttrValue::from("s"), AttrValue::Str("s".into()));
}
}