use std::borrow::Cow;
use itoa::{Buffer as ItoaBuffer, Integer};
use nt_syntax::Value;
use serde::{
Serialize,
ser::{
self, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, SerializeTuple,
SerializeTupleStruct, SerializeTupleVariant,
},
};
use zmij::{Buffer as ZmijBuffer, Float};
use crate::error::{Error, Result};
pub fn to_value<T: Serialize + ?Sized>(value: &T) -> Result<Value<'static>> {
value.serialize(ValueSer)
}
struct ValueSer;
macro_rules! val_int {
($($method:ident => $t:ty),* $(,)?) => {
$(
fn $method(self, v: $t) -> Result<Value<'static>> {
Ok(int(v))
}
)*
};
}
impl ser::Serializer for ValueSer {
type Ok = Value<'static>;
type Error = Error;
type SerializeSeq = SeqSer;
type SerializeTuple = SeqSer;
type SerializeTupleStruct = SeqSer;
type SerializeTupleVariant = TupleVariantSer;
type SerializeMap = MapSer;
type SerializeStruct = MapSer;
type SerializeStructVariant = StructVariantSer;
fn serialize_bool(self, v: bool) -> Result<Value<'static>> {
Ok(Value::Str(Cow::Borrowed(if v { "true" } else { "false" })))
}
val_int! {
serialize_i8 => i8,
serialize_i16 => i16,
serialize_i32 => i32,
serialize_i64 => i64,
serialize_i128 => i128,
serialize_u8 => u8,
serialize_u16 => u16,
serialize_u32 => u32,
serialize_u64 => u64,
serialize_u128 => u128,
}
fn serialize_f32(self, v: f32) -> Result<Value<'static>> {
Ok(float(v))
}
fn serialize_f64(self, v: f64) -> Result<Value<'static>> {
Ok(float(v))
}
fn serialize_char(self, v: char) -> Result<Value<'static>> {
Ok(Value::Str(Cow::Owned(v.to_string())))
}
fn serialize_str(self, v: &str) -> Result<Value<'static>> {
Ok(Value::Str(Cow::Owned(v.to_owned())))
}
fn serialize_bytes(self, _: &[u8]) -> Result<Value<'static>> {
Err(Error::msg("NestedText does not support byte arrays"))
}
fn serialize_none(self) -> Result<Value<'static>> {
Ok(Value::empty_str())
}
fn serialize_some<T: Serialize + ?Sized>(self, value: &T) -> Result<Value<'static>> {
value.serialize(self)
}
fn serialize_unit(self) -> Result<Value<'static>> {
Ok(Value::empty_str())
}
fn serialize_unit_struct(self, _: &'static str) -> Result<Value<'static>> {
Ok(Value::empty_str())
}
fn serialize_unit_variant(
self,
_: &'static str,
_: u32,
variant: &'static str,
) -> Result<Value<'static>> {
Ok(Value::Str(Cow::Borrowed(variant)))
}
fn serialize_newtype_struct<T: Serialize + ?Sized>(
self,
_: &'static str,
value: &T,
) -> Result<Value<'static>> {
value.serialize(self)
}
fn serialize_newtype_variant<T: Serialize + ?Sized>(
self,
_: &'static str,
_: u32,
variant: &'static str,
value: &T,
) -> Result<Value<'static>> {
Ok(Value::Dict(vec![(
Cow::Borrowed(variant),
value.serialize(self)?,
)]))
}
fn serialize_seq(self, len: Option<usize>) -> Result<SeqSer> {
Ok(SeqSer {
item_li: Vec::with_capacity(len.unwrap_or(0)),
})
}
fn serialize_tuple(self, len: usize) -> Result<SeqSer> {
self.serialize_seq(Some(len))
}
fn serialize_tuple_struct(self, _: &'static str, len: usize) -> Result<SeqSer> {
self.serialize_seq(Some(len))
}
fn serialize_tuple_variant(
self,
_: &'static str,
_: u32,
variant: &'static str,
len: usize,
) -> Result<TupleVariantSer> {
Ok(TupleVariantSer {
variant,
item_li: Vec::with_capacity(len),
})
}
fn serialize_map(self, len: Option<usize>) -> Result<MapSer> {
Ok(MapSer {
pair_li: Vec::with_capacity(len.unwrap_or(0)),
key: None,
})
}
fn serialize_struct(self, _: &'static str, len: usize) -> Result<MapSer> {
self.serialize_map(Some(len))
}
fn serialize_struct_variant(
self,
_: &'static str,
_: u32,
variant: &'static str,
len: usize,
) -> Result<StructVariantSer> {
Ok(StructVariantSer {
variant,
pair_li: Vec::with_capacity(len),
})
}
}
fn int(v: impl Integer) -> Value<'static> {
let mut buf = ItoaBuffer::new();
Value::Str(Cow::Owned(buf.format(v).to_owned()))
}
fn float(v: impl Float) -> Value<'static> {
let mut buf = ZmijBuffer::new();
Value::Str(Cow::Owned(buf.format(v).to_owned()))
}
pub struct SeqSer {
item_li: Vec<Value<'static>>,
}
impl SerializeSeq for SeqSer {
type Ok = Value<'static>;
type Error = Error;
fn serialize_element<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<()> {
self.item_li.push(value.serialize(ValueSer)?);
Ok(())
}
fn end(self) -> Result<Value<'static>> {
Ok(Value::List(self.item_li))
}
}
impl SerializeTuple for SeqSer {
type Ok = Value<'static>;
type Error = Error;
fn serialize_element<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<()> {
SerializeSeq::serialize_element(self, value)
}
fn end(self) -> Result<Value<'static>> {
SerializeSeq::end(self)
}
}
impl SerializeTupleStruct for SeqSer {
type Ok = Value<'static>;
type Error = Error;
fn serialize_field<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<()> {
SerializeSeq::serialize_element(self, value)
}
fn end(self) -> Result<Value<'static>> {
SerializeSeq::end(self)
}
}
pub struct TupleVariantSer {
variant: &'static str,
item_li: Vec<Value<'static>>,
}
impl SerializeTupleVariant for TupleVariantSer {
type Ok = Value<'static>;
type Error = Error;
fn serialize_field<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<()> {
self.item_li.push(value.serialize(ValueSer)?);
Ok(())
}
fn end(self) -> Result<Value<'static>> {
Ok(Value::Dict(vec![(
Cow::Borrowed(self.variant),
Value::List(self.item_li),
)]))
}
}
pub struct MapSer {
pair_li: Vec<(Cow<'static, str>, Value<'static>)>,
key: Option<Cow<'static, str>>,
}
impl SerializeMap for MapSer {
type Ok = Value<'static>;
type Error = Error;
fn serialize_key<T: Serialize + ?Sized>(&mut self, key: &T) -> Result<()> {
self.key = Some(match key.serialize(ValueSer)? {
Value::Str(s) => s,
_ => return Err(Error::msg("NestedText dictionary keys must be strings")),
});
Ok(())
}
fn serialize_value<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<()> {
let key = self
.key
.take()
.ok_or_else(|| Error::msg("missing dictionary key"))?;
self.pair_li.push((key, value.serialize(ValueSer)?));
Ok(())
}
fn end(self) -> Result<Value<'static>> {
Ok(Value::Dict(self.pair_li))
}
}
impl SerializeStruct for MapSer {
type Ok = Value<'static>;
type Error = Error;
fn serialize_field<T: Serialize + ?Sized>(&mut self, key: &'static str, value: &T) -> Result<()> {
self
.pair_li
.push((Cow::Borrowed(key), value.serialize(ValueSer)?));
Ok(())
}
fn end(self) -> Result<Value<'static>> {
Ok(Value::Dict(self.pair_li))
}
}
pub struct StructVariantSer {
variant: &'static str,
pair_li: Vec<(Cow<'static, str>, Value<'static>)>,
}
impl SerializeStructVariant for StructVariantSer {
type Ok = Value<'static>;
type Error = Error;
fn serialize_field<T: Serialize + ?Sized>(&mut self, key: &'static str, value: &T) -> Result<()> {
self
.pair_li
.push((Cow::Borrowed(key), value.serialize(ValueSer)?));
Ok(())
}
fn end(self) -> Result<Value<'static>> {
Ok(Value::Dict(vec![(
Cow::Borrowed(self.variant),
Value::Dict(self.pair_li),
)]))
}
}