use std::collections::HashMap;
use std::fmt;
use std::fmt::{Debug, Display};
#[cfg(feature = "serde1")]
use serde::{Deserialize, Serialize};
#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub enum KvValue {
Float(f64),
Int(i64),
Uint(u64),
Bool(bool),
Str(String),
}
impl KvValue {
pub fn kind(&self) -> &'static str {
match self {
KvValue::Float(_) => "Float",
KvValue::Int(_) => "Int",
KvValue::Uint(_) => "Uint",
KvValue::Bool(_) => "Bool",
KvValue::Str(_) => "Str",
}
}
pub fn get_float(&self) -> Option<f64> {
match self {
KvValue::Float(x) => Some(*x),
KvValue::Int(x) => Some(*x as f64),
KvValue::Uint(x) => Some(*x as f64),
KvValue::Bool(true) => Some(1.0),
KvValue::Bool(false) => Some(0.0),
_ => None,
}
}
pub fn get_int(&self) -> Option<i64> {
if let KvValue::Int(x) = *self {
Some(x)
} else {
None
}
}
pub fn get_uint(&self) -> Option<u64> {
if let KvValue::Uint(x) = *self {
Some(x)
} else {
None
}
}
pub fn get_bool(&self) -> Option<bool> {
if let KvValue::Bool(x) = *self {
Some(x)
} else {
None
}
}
pub fn get_string(&self) -> Option<String> {
if let KvValue::Str(x) = self {
Some(x.clone())
} else {
None
}
}
pub fn as_string(&self) -> String {
match self {
KvValue::Str(x) => x.clone(),
KvValue::Float(x) => format!("{x}"),
KvValue::Bool(x) => format!("{x}"),
KvValue::Int(x) => format!("{x}"),
KvValue::Uint(x) => format!("{x}"),
}
}
}
impl From<f64> for KvValue {
fn from(x: f64) -> KvValue {
KvValue::Float(x)
}
}
impl From<f32> for KvValue {
fn from(x: f32) -> KvValue {
KvValue::Float(f64::from(x))
}
}
impl From<i64> for KvValue {
fn from(x: i64) -> KvValue {
KvValue::Int(x)
}
}
impl From<u64> for KvValue {
fn from(x: u64) -> KvValue {
KvValue::Uint(x)
}
}
impl From<i32> for KvValue {
fn from(x: i32) -> KvValue {
KvValue::Int(i64::from(x))
}
}
impl From<u32> for KvValue {
fn from(x: u32) -> KvValue {
KvValue::Uint(u64::from(x))
}
}
impl From<bool> for KvValue {
fn from(x: bool) -> KvValue {
KvValue::Bool(x)
}
}
impl From<String> for KvValue {
fn from(x: String) -> KvValue {
KvValue::Str(x)
}
}
impl<'a> From<&'a str> for KvValue {
fn from(x: &'a str) -> KvValue {
KvValue::Str(x.to_string())
}
}
impl Display for KvValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
KvValue::Float(x) => write!(f, "{x}")?,
KvValue::Int(x) => write!(f, "{x}")?,
KvValue::Uint(x) => write!(f, "{x}")?,
KvValue::Bool(x) => write!(f, "{x}")?,
KvValue::Str(x) => write!(f, "{x}")?,
};
Ok(())
}
}
#[derive(Clone, Default, PartialEq)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct KV {
pub kv: HashMap<String, KvValue>,
}
impl Debug for KV {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "{self}")?;
Ok(())
}
}
impl Display for KV {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "KV")?;
for (key, val) in self.kv.iter() {
writeln!(f, " {key}: {val}")?;
}
Ok(())
}
}
impl KV {
pub fn new() -> Self {
KV { kv: HashMap::new() }
}
pub fn insert<T: AsRef<str>>(&mut self, key: T, val: KvValue) -> &mut Self {
self.kv.insert(key.as_ref().into(), val);
self
}
pub fn get<T: AsRef<str>>(&self, key: T) -> Option<&KvValue> {
self.kv.get(key.as_ref())
}
pub fn keys(&self) -> Vec<(String, &'static str)> {
self.kv.iter().map(|(k, v)| (k.clone(), v.kind())).collect()
}
#[must_use]
pub fn merge(mut self, other: KV) -> Self {
self.kv.extend(other.kv);
self
}
}
impl std::iter::FromIterator<(&'static str, KvValue)> for KV {
fn from_iter<I: IntoIterator<Item = (&'static str, KvValue)>>(iter: I) -> Self {
let mut c = KV::new();
for i in iter {
c.insert(i.0, i.1);
}
c
}
}
impl std::iter::Extend<(&'static str, KvValue)> for KV {
fn extend<I: IntoIterator<Item = (&'static str, KvValue)>>(&mut self, iter: I) {
for i in iter {
self.insert(i.0, i.1);
}
}
}