use zerompk::Write;
use super::instant_ext::InstantKind;
use super::json_value::JsonValue;
#[inline]
pub fn json_to_msgpack(value: &serde_json::Value) -> zerompk::Result<Vec<u8>> {
zerompk::to_msgpack_vec(&JsonValue(value.clone()))
}
#[inline]
pub fn json_to_msgpack_or_empty(value: &serde_json::Value) -> Vec<u8> {
json_to_msgpack(value).unwrap_or_else(|_| vec![0x80])
}
pub fn value_to_msgpack(value: &crate::Value) -> zerompk::Result<Vec<u8>> {
zerompk::to_msgpack_vec(&NativeRef(value))
}
struct NativeRef<'a>(&'a crate::Value);
impl zerompk::ToMessagePack for NativeRef<'_> {
fn write<W: Write>(&self, writer: &mut W) -> zerompk::Result<()> {
write_native_value(writer, self.0)
}
}
pub(crate) fn write_native_value<W: Write>(
writer: &mut W,
value: &crate::Value,
) -> zerompk::Result<()> {
match value {
crate::Value::Null => writer.write_nil(),
crate::Value::Bool(b) => writer.write_boolean(*b),
crate::Value::Integer(i) => writer.write_i64(*i),
crate::Value::Float(f) => writer.write_f64(*f),
crate::Value::String(s)
| crate::Value::Uuid(s)
| crate::Value::Ulid(s)
| crate::Value::Regex(s) => writer.write_string(s),
crate::Value::Bytes(b) => writer.write_binary(b),
crate::Value::Array(arr) | crate::Value::Set(arr) => {
writer.write_array_len(arr.len())?;
for v in arr {
write_native_value(writer, v)?;
}
Ok(())
}
crate::Value::Object(map) => {
writer.write_map_len(map.len())?;
for (k, v) in map {
writer.write_string(k)?;
write_native_value(writer, v)?;
}
Ok(())
}
crate::Value::DateTime(dt) => write_instant_ext(writer, InstantKind::Utc, dt.micros),
crate::Value::NaiveDateTime(dt) => write_instant_ext(writer, InstantKind::Naive, dt.micros),
crate::Value::Duration(d) => writer.write_string(&d.to_string()),
crate::Value::Decimal(d) => match crate::Value::decimal_as_wide_u64(d) {
Some(u) => writer.write_u64(u),
None => writer.write_string(&d.to_string()),
},
crate::Value::Geometry(g) => match sonic_rs::to_string(g) {
Ok(s) => writer.write_string(&s),
Err(_) => writer.write_nil(),
},
crate::Value::Range { .. } | crate::Value::Record { .. } => writer.write_nil(),
crate::Value::Vector(v) => {
writer.write_array_len(v.len())?;
for f in v.iter() {
writer.write_f64(f64::from(*f))?;
}
Ok(())
}
crate::Value::ArrayCell(cell) => {
let map_len = if cell.system_time.is_some() { 3 } else { 2 };
writer.write_map_len(map_len)?;
writer.write_string("coords")?;
writer.write_array_len(cell.coords.len())?;
for v in &cell.coords {
write_native_value(writer, v)?;
}
writer.write_string("attrs")?;
writer.write_array_len(cell.attrs.len())?;
for v in &cell.attrs {
write_native_value(writer, v)?;
}
if let Some(ts) = cell.system_time {
writer.write_string("_ts_system")?;
writer.write_i64(ts)?;
}
Ok(())
}
}
}
fn write_instant_ext<W: Write>(
writer: &mut W,
kind: InstantKind,
micros: i64,
) -> zerompk::Result<()> {
writer.write_ext(kind.ext_type(), µs.to_be_bytes())
}