use alloc::borrow::Cow;
use alloc::collections::BTreeMap;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use core::convert::TryFrom;
use chrono::{NaiveDate, NaiveDateTime};
use serde::{Serialize, Serializer};
use crate::error::EtError;
pub trait StateMetadata {
fn metadata(&self) -> BTreeMap<String, Value> {
BTreeMap::new()
}
fn header(&self) -> Vec<&str>;
}
impl StateMetadata for () {
fn header(&self) -> Vec<&str> {
Vec::new()
}
}
#[macro_export]
macro_rules! impl_record {
($type:ty : $($key:ident),* ) => {
impl<'r> From<$type> for ::alloc::vec::Vec<$crate::record::Value<'r>> {
fn from(record: $type) -> Self {
::alloc::vec![$(record.$key.into(),)*]
}
}
};
($type:ty : $($key:ident)+ ) => { record!($($key),+) };
}
#[derive(PartialEq, Clone, Debug)]
pub enum Value<'a> {
Null,
Boolean(bool),
Datetime(NaiveDateTime),
Float(f64),
Integer(i64),
String(Cow<'a, str>),
List(Vec<Value<'a>>),
Record(BTreeMap<String, Value<'a>>),
}
impl<'a> Value<'a> {
pub fn from_iso_date(string: &str) -> Result<Self, EtError> {
let datetime = NaiveDateTime::parse_from_str(string, "%+")
.map_err(|e| EtError::from(e.to_string()))?;
Ok(Self::Datetime(datetime))
}
pub fn into_string(self) -> Result<String, EtError> {
if let Value::String(s) = self {
return Ok(s.into_owned());
}
Err(EtError::from("Value was not a string"))
}
}
impl<'a, T: Into<Value<'a>>> From<Option<T>> for Value<'a> {
fn from(x: Option<T>) -> Self {
match x {
None => Value::Null,
Some(s) => s.into(),
}
}
}
impl<'a> From<bool> for Value<'a> {
fn from(x: bool) -> Self {
Value::Boolean(x)
}
}
impl<'a> From<f32> for Value<'a> {
fn from(x: f32) -> Self {
Value::Float(f64::from(x))
}
}
impl<'a> From<f64> for Value<'a> {
fn from(x: f64) -> Self {
Value::Float(x)
}
}
impl<'a> From<u8> for Value<'a> {
fn from(x: u8) -> Self {
Value::Integer(i64::from(x))
}
}
impl<'a> From<u16> for Value<'a> {
fn from(x: u16) -> Self {
Value::Integer(i64::from(x))
}
}
impl<'a> From<i32> for Value<'a> {
fn from(x: i32) -> Self {
Value::Integer(i64::from(x))
}
}
impl<'a> From<u32> for Value<'a> {
fn from(x: u32) -> Self {
Value::Integer(i64::from(x))
}
}
impl<'a> From<i64> for Value<'a> {
fn from(x: i64) -> Self {
Value::Integer(x)
}
}
impl<'a> From<u64> for Value<'a> {
fn from(x: u64) -> Self {
if x.leading_zeros() == 0 {
Value::Integer(i64::MAX)
} else {
Value::Integer(i64::try_from(x).unwrap())
}
}
}
impl<'a> From<Cow<'a, [u8]>> for Value<'a> {
fn from(x: Cow<'a, [u8]>) -> Self {
Value::String(match x {
Cow::Borrowed(b) => String::from_utf8_lossy(b),
Cow::Owned(o) => Cow::Owned(String::from_utf8_lossy(&o).into_owned()),
})
}
}
impl<'a> From<&'a [u8]> for Value<'a> {
fn from(x: &'a [u8]) -> Self {
Value::String(String::from_utf8_lossy(x))
}
}
impl<'a> From<Vec<u8>> for Value<'a> {
fn from(x: Vec<u8>) -> Self {
Value::String(Cow::Owned(String::from_utf8_lossy(&x).into_owned()))
}
}
impl<'a> From<Cow<'a, str>> for Value<'a> {
fn from(x: Cow<'a, str>) -> Self {
Value::String(x)
}
}
impl<'a> From<&'a str> for Value<'a> {
fn from(x: &'a str) -> Self {
Value::String(x.into())
}
}
impl<'a> From<String> for Value<'a> {
fn from(x: String) -> Self {
Value::String(x.into())
}
}
impl<'a> From<NaiveDateTime> for Value<'a> {
fn from(d: NaiveDateTime) -> Self {
Value::Datetime(d)
}
}
impl<'a> From<NaiveDate> for Value<'a> {
fn from(d: NaiveDate) -> Self {
Value::Datetime(d.and_hms_opt(0, 0, 0).unwrap())
}
}
impl<'a> From<&'a [String]> for Value<'a> {
fn from(value: &'a [String]) -> Self {
let mut rec = Vec::with_capacity(value.len());
for v in value {
let bv: &str = v.as_ref();
rec.push(bv.into());
}
Value::List(rec)
}
}
impl<'a> From<Vec<String>> for Value<'a> {
fn from(value: Vec<String>) -> Self {
let mut rec = Vec::with_capacity(value.len());
for v in value {
rec.push(v.into());
}
Value::List(rec)
}
}
impl<'a> From<Vec<Value<'a>>> for Value<'a> {
fn from(value: Vec<Value<'a>>) -> Self {
Value::List(value)
}
}
impl<'a> Serialize for Value<'a> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match *self {
Value::Null => serializer.serialize_none(),
Value::Boolean(b) => serializer.serialize_bool(b),
Value::Datetime(ref s) => s.serialize(serializer),
Value::Float(f) => serializer.serialize_f64(f),
Value::Integer(i) => serializer.serialize_i64(i),
Value::List(ref a) => a.serialize(serializer),
Value::Record(ref t) => t.serialize(serializer),
Value::String(ref s) => serializer.serialize_str(s),
}
}
}