#[cfg(feature = "serialize")]
use serde::{Deserialize, Serialize};
use std::borrow::Cow;
use std::fmt;
#[cfg_attr(feature = "serialize", derive(Deserialize, Serialize))]
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Key(Cow<'static, str>);
impl Key {
pub fn new<S: Into<Cow<'static, str>>>(value: S) -> Self {
Key(value.into())
}
pub const fn from_static_str(value: &'static str) -> Self {
Key(Cow::Borrowed(value))
}
pub fn bool<T: Into<bool>>(self, value: T) -> KeyValue {
KeyValue {
key: self,
value: Value::Bool(value.into()),
}
}
pub fn i64(self, value: i64) -> KeyValue {
KeyValue {
key: self,
value: Value::I64(value),
}
}
pub fn f64(self, value: f64) -> KeyValue {
KeyValue {
key: self,
value: Value::F64(value),
}
}
pub fn string<T: Into<Cow<'static, str>>>(self, value: T) -> KeyValue {
KeyValue {
key: self,
value: Value::String(value.into()),
}
}
pub fn array<T: Into<Array>>(self, value: T) -> KeyValue {
KeyValue {
key: self,
value: Value::Array(value.into()),
}
}
pub fn as_str(&self) -> &str {
self.0.as_ref()
}
}
impl From<&'static str> for Key {
fn from(key_str: &'static str) -> Self {
Key(Cow::from(key_str))
}
}
impl From<String> for Key {
fn from(string: String) -> Self {
Key(Cow::from(string))
}
}
impl From<Key> for String {
fn from(key: Key) -> Self {
key.0.into_owned()
}
}
impl fmt::Display for Key {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(fmt)
}
}
#[cfg_attr(feature = "serialize", derive(Deserialize, Serialize))]
#[derive(Clone, Debug, PartialEq)]
pub enum Array {
Bool(Vec<bool>),
I64(Vec<i64>),
F64(Vec<f64>),
String(Vec<Cow<'static, str>>),
}
impl fmt::Display for Array {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Array::Bool(values) => display_array_str(values, fmt),
Array::I64(values) => display_array_str(values, fmt),
Array::F64(values) => display_array_str(values, fmt),
Array::String(values) => {
write!(fmt, "[")?;
for (i, t) in values.iter().enumerate() {
if i > 0 {
write!(fmt, ",")?;
}
write!(fmt, "{:?}", t)?;
}
write!(fmt, "]")
}
}
}
}
fn display_array_str<T: fmt::Display>(slice: &[T], fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(fmt, "[")?;
for (i, t) in slice.iter().enumerate() {
if i > 0 {
write!(fmt, ",")?;
}
write!(fmt, "{}", t)?;
}
write!(fmt, "]")
}
macro_rules! into_array {
($(($t:ty, $val:expr),)+) => {
$(
impl From<$t> for Array {
fn from(t: $t) -> Self {
$val(t)
}
}
)+
}
}
into_array!(
(Vec<bool>, Array::Bool),
(Vec<i64>, Array::I64),
(Vec<f64>, Array::F64),
(Vec<Cow<'static, str>>, Array::String),
);
#[cfg_attr(feature = "serialize", derive(Deserialize, Serialize))]
#[derive(Clone, Debug, PartialEq)]
pub enum Value {
Bool(bool),
I64(i64),
F64(f64),
String(Cow<'static, str>),
Array(Array),
}
impl Value {
pub fn as_str(&self) -> Cow<'_, str> {
match self {
Value::Bool(v) => format!("{}", v).into(),
Value::I64(v) => format!("{}", v).into(),
Value::F64(v) => format!("{}", v).into(),
Value::String(v) => Cow::Borrowed(v.as_ref()),
Value::Array(v) => format!("{}", v).into(),
}
}
}
macro_rules! from_values {
(
$(
($t:ty, $val:expr);
)+
) => {
$(
impl From<$t> for Value {
fn from(t: $t) -> Self {
$val(t)
}
}
)+
}
}
from_values!(
(bool, Value::Bool);
(i64, Value::I64);
(f64, Value::F64);
(Cow<'static, str>, Value::String);
);
impl From<&'static str> for Value {
fn from(s: &'static str) -> Self {
Value::String(s.into())
}
}
impl From<String> for Value {
fn from(s: String) -> Self {
Value::String(s.into())
}
}
impl fmt::Display for Value {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Value::Bool(v) => fmt.write_fmt(format_args!("{}", v)),
Value::I64(v) => fmt.write_fmt(format_args!("{}", v)),
Value::F64(v) => fmt.write_fmt(format_args!("{}", v)),
Value::String(v) => fmt.write_fmt(format_args!("{}", v)),
Value::Array(v) => fmt.write_fmt(format_args!("{}", v)),
}
}
}
#[cfg_attr(feature = "serialize", derive(Deserialize, Serialize))]
#[derive(Clone, Debug, PartialEq)]
pub struct KeyValue {
pub key: Key,
pub value: Value,
}
impl KeyValue {
pub fn new<K, V>(key: K, value: V) -> Self
where
K: Into<Key>,
V: Into<Value>,
{
KeyValue {
key: key.into(),
value: value.into(),
}
}
}