use rust_decimal::Decimal;
use serde::{Serialize, Serializer, ser::SerializeMap, ser::SerializeSeq};
use serde_json::Value as JsonValue;
use crate::zbase::ZBASE32;
#[derive(Debug, Clone, PartialEq)]
pub enum DynValue {
Void,
Bool(bool),
U8(u8),
U16(u16),
U32(u32),
U64(u64),
I32(i32),
I64(i64),
F32(f32),
F64(f64),
Str(String),
Datetime(i64),
Timestamp(u64),
Decimal(Decimal),
Id32(u32),
Id64(u64),
Fuid(u64),
LowId(u32),
Bytes(Vec<u8>),
ArrayBytes(Vec<u8>),
Array(Vec<DynValue>),
Vec(Vec<DynValue>),
Optional(Option<Box<DynValue>>),
SimpleEnum {
name: &'static str,
variant: u8,
variant_name: &'static str,
},
Struct {
name: &'static str,
fields: StructValue,
},
Enum {
name: &'static str,
variant: u8,
variant_name: &'static str,
field: Box<DynValue>,
},
RustJson(JsonValue),
JsonBytes(String),
}
#[derive(Debug, Clone, PartialEq)]
pub enum StructValue {
Named(Vec<(&'static str, DynValue)>),
Unnamed(Vec<DynValue>),
}
fn ms_to_rfc3339<E: serde::ser::Error>(ms: i64) -> Result<String, E> {
let t = time::OffsetDateTime::from_unix_timestamp_nanos((ms as i128) * 1_000_000)
.map_err(serde::ser::Error::custom)?;
t.format(&time::format_description::well_known::Rfc3339)
.map_err(serde::ser::Error::custom)
}
impl Serialize for DynValue {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
use data_encoding::HEXLOWER;
match self {
DynValue::Void => s.serialize_unit(),
DynValue::Bool(b) => s.serialize_bool(*b),
DynValue::U8(v) => s.serialize_u8(*v),
DynValue::U16(v) => s.serialize_u16(*v),
DynValue::U32(v) => s.serialize_u32(*v),
DynValue::U64(v) => s.serialize_u64(*v),
DynValue::I32(v) => s.serialize_i32(*v),
DynValue::I64(v) => s.serialize_i64(*v),
DynValue::F32(v) => s.serialize_f32(*v),
DynValue::F64(v) => s.serialize_f64(*v),
DynValue::Str(v) => s.serialize_str(v),
DynValue::Datetime(ms) => s.serialize_str(&ms_to_rfc3339::<S::Error>(*ms)?),
DynValue::Timestamp(ms) => s.serialize_str(&ms_to_rfc3339::<S::Error>(*ms as i64)?),
DynValue::Decimal(d) => s.serialize_str(&d.to_string()),
DynValue::Id32(v) => s.serialize_str(&format!("{v:08x}")),
DynValue::Id64(v) | DynValue::Fuid(v) => {
s.serialize_str(&ZBASE32.encode(&v.to_be_bytes()))
}
DynValue::LowId(v) => s.serialize_u32(*v),
DynValue::Bytes(v) | DynValue::ArrayBytes(v) => s.serialize_str(&HEXLOWER.encode(v)),
DynValue::Array(items) | DynValue::Vec(items) => {
let mut seq = s.serialize_seq(Some(items.len()))?;
for item in items {
seq.serialize_element(item)?;
}
seq.end()
}
DynValue::Optional(None) => s.serialize_none(),
DynValue::Optional(Some(v)) => v.serialize(s),
DynValue::SimpleEnum { variant_name, .. } => s.serialize_str(variant_name),
DynValue::Struct {
fields: StructValue::Named(pairs),
..
} => {
let mut map = s.serialize_map(Some(pairs.len()))?;
for (k, v) in pairs {
map.serialize_entry(k, v)?;
}
map.end()
}
DynValue::Struct {
fields: StructValue::Unnamed(items),
..
} => {
let mut seq = s.serialize_seq(Some(items.len()))?;
for item in items {
seq.serialize_element(item)?;
}
seq.end()
}
DynValue::Enum {
variant_name,
field,
..
} => {
let mut map = s.serialize_map(Some(1))?;
map.serialize_entry(variant_name, field.as_ref())?;
map.end()
}
DynValue::RustJson(v) => v.serialize(s),
DynValue::JsonBytes(raw) => {
let parsed: JsonValue =
serde_json::from_str(raw).map_err(serde::ser::Error::custom)?;
parsed.serialize(s)
}
}
}
}