use std::{fmt::Display, io::Write};
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug)]
pub enum Error {
IoError(std::io::Error),
SerializeError(String),
IllegalStringChar,
}
impl From<std::io::Error> for Error {
fn from(value: std::io::Error) -> Self {
Error::IoError(value)
}
}
impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::IoError(e) => e.fmt(f),
Error::SerializeError(msg) => f.write_str(msg),
Error::IllegalStringChar => write!(f, "illegal string characteter"),
}
}
}
impl std::error::Error for Error {}
impl serde::ser::Error for Error {
fn custom<T>(msg: T) -> Self
where
T: Display,
{
Error::SerializeError(msg.to_string())
}
}
pub fn to_string<T: serde::Serialize>(value: &T) -> Result<String> {
let mut out = Vec::new();
let mut s = Serializer::new(&mut out);
value.serialize(&mut s)?;
Ok(String::from_utf8(out).unwrap())
}
pub struct Serializer<'a, W> {
out: &'a mut W,
}
impl<'a, W> Serializer<'a, W> {
pub fn new(out: &'a mut W) -> Self {
Self { out }
}
}
impl<'a, W: Write> Serializer<'a, W> {
fn serialize_identifier(&mut self, ident: &str) -> std::result::Result<(), Error> {
self.out.write_all(ident.as_bytes()).map_err(Into::into)
}
}
const NULL: &[u8] = "null".as_bytes();
const PAREN_OPEN: &[u8] = "(".as_bytes();
const PAREN_CLOSE: &[u8] = ")".as_bytes();
const PAREN_EMPTY_CLOSED: &[u8] = "()".as_bytes();
const BRACKET_OPEN: &[u8] = "[".as_bytes();
const BRACKET_CLOSE: &[u8] = "]".as_bytes();
const BRACE_OPEN: &[u8] = "{".as_bytes();
const BRACE_CLOSE: &[u8] = "}".as_bytes();
const COMMA: &[u8] = ",".as_bytes();
const COLON: &[u8] = ":".as_bytes();
impl<'a, 'w, W: Write> serde::ser::Serializer for &'a mut Serializer<'w, W> {
type Ok = ();
type Error = Error;
type SerializeSeq = SeqSerializer<'a, 'w, W>;
type SerializeTuple = SeqSerializer<'a, 'w, W>;
type SerializeTupleStruct = SeqSerializer<'a, 'w, W>;
type SerializeTupleVariant = SeqSerializer<'a, 'w, W>;
type SerializeMap = MapSerializer<'a, 'w, W>;
type SerializeStruct = StructSerializer<'a, 'w, W>;
type SerializeStructVariant = StructSerializer<'a, 'w, W>;
fn serialize_bool(self, v: bool) -> std::result::Result<Self::Ok, Self::Error> {
let s = if v { "true" } else { "false" };
self.out.write_all(s.as_bytes())?;
Ok(())
}
fn serialize_i8(self, v: i8) -> std::result::Result<Self::Ok, Self::Error> {
self.serialize_i64(v.into())
}
fn serialize_i16(self, v: i16) -> std::result::Result<Self::Ok, Self::Error> {
self.serialize_i64(v.into())
}
fn serialize_i32(self, v: i32) -> std::result::Result<Self::Ok, Self::Error> {
self.serialize_i64(v.into())
}
fn serialize_i64(self, v: i64) -> std::result::Result<Self::Ok, Self::Error> {
write!(self.out, "{}", v).map_err(From::from)
}
fn serialize_u8(self, v: u8) -> std::result::Result<Self::Ok, Self::Error> {
self.serialize_u64(v.into())
}
fn serialize_u16(self, v: u16) -> std::result::Result<Self::Ok, Self::Error> {
self.serialize_u64(v.into())
}
fn serialize_u32(self, v: u32) -> std::result::Result<Self::Ok, Self::Error> {
self.serialize_u64(v.into())
}
fn serialize_u64(self, v: u64) -> std::result::Result<Self::Ok, Self::Error> {
write!(self.out, "{}", v).map_err(From::from)
}
fn serialize_f32(self, v: f32) -> std::result::Result<Self::Ok, Self::Error> {
self.serialize_f64(v.into())
}
fn serialize_f64(self, v: f64) -> std::result::Result<Self::Ok, Self::Error> {
write!(self.out, "{}", v).map_err(From::from)
}
fn serialize_char(self, v: char) -> std::result::Result<Self::Ok, Self::Error> {
if v == '"' {
Err(Error::IllegalStringChar)
} else {
write!(self.out, "\"{}\"", v).map_err(From::from)
}
}
fn serialize_str(self, v: &str) -> std::result::Result<Self::Ok, Self::Error> {
if v.contains('"') {
Err(Error::IllegalStringChar)
} else {
write!(self.out, "\"{}\"", v).map_err(From::from)
}
}
fn serialize_bytes(self, v: &[u8]) -> std::result::Result<Self::Ok, Self::Error> {
use serde::ser::SerializeSeq;
let mut seq = self.serialize_seq(Some(v.len()))?;
for byte in v {
seq.serialize_element(byte)?;
}
seq.end()
}
fn serialize_none(self) -> std::result::Result<Self::Ok, Self::Error> {
self.serialize_unit()
}
fn serialize_some<T>(self, value: &T) -> std::result::Result<Self::Ok, Self::Error>
where
T: ?Sized + serde::Serialize,
{
value.serialize(self)
}
fn serialize_unit(self) -> std::result::Result<Self::Ok, Self::Error> {
self.out.write_all(NULL).map_err(From::from)
}
fn serialize_unit_struct(
self,
name: &'static str,
) -> std::result::Result<Self::Ok, Self::Error> {
self.serialize_identifier(name)?;
self.out.write_all(PAREN_EMPTY_CLOSED).map_err(From::from)
}
fn serialize_unit_variant(
self,
_name: &'static str,
_variant_index: u32,
variant: &'static str,
) -> std::result::Result<Self::Ok, Self::Error> {
self.serialize_unit_struct(variant)
}
fn serialize_newtype_struct<T>(
self,
name: &'static str,
value: &T,
) -> std::result::Result<Self::Ok, Self::Error>
where
T: ?Sized + serde::Serialize,
{
self.serialize_identifier(name)?;
self.out.write_all(PAREN_OPEN)?;
value.serialize(&mut *self)?;
self.out.write_all(PAREN_CLOSE)?;
Ok(())
}
fn serialize_newtype_variant<T>(
self,
_name: &'static str,
_variant_index: u32,
variant: &'static str,
value: &T,
) -> std::result::Result<Self::Ok, Self::Error>
where
T: ?Sized + serde::Serialize,
{
self.serialize_newtype_struct(variant, value)
}
fn serialize_seq(
self,
_len: Option<usize>,
) -> std::result::Result<Self::SerializeSeq, Self::Error> {
self.out.write_all(BRACKET_OPEN)?;
Ok(SeqSerializer::new(self, BRACKET_CLOSE))
}
fn serialize_tuple(self, len: usize) -> std::result::Result<Self::SerializeTuple, Self::Error> {
self.serialize_seq(Some(len))
}
fn serialize_tuple_struct(
self,
name: &'static str,
_len: usize,
) -> std::result::Result<Self::SerializeTupleStruct, Self::Error> {
self.serialize_identifier(name)?;
self.out.write_all("(".as_bytes())?;
Ok(SeqSerializer::new(self, PAREN_CLOSE))
}
fn serialize_tuple_variant(
self,
_name: &'static str,
_variant_index: u32,
variant: &'static str,
len: usize,
) -> std::result::Result<Self::SerializeTupleVariant, Self::Error> {
self.serialize_tuple_struct(variant, len)
}
fn serialize_map(
self,
_len: Option<usize>,
) -> std::result::Result<Self::SerializeMap, Self::Error> {
self.out.write_all(BRACE_OPEN)?;
Ok(MapSerializer::new(self))
}
fn serialize_struct(
self,
name: &'static str,
_len: usize,
) -> std::result::Result<Self::SerializeStruct, Self::Error> {
self.serialize_identifier(name)?;
self.out.write_all(BRACE_OPEN)?;
Ok(StructSerializer::new(self))
}
fn serialize_struct_variant(
self,
_name: &'static str,
_variant_index: u32,
variant: &'static str,
len: usize,
) -> std::result::Result<Self::SerializeStructVariant, Self::Error> {
self.serialize_struct(variant, len)
}
}
pub struct SeqSerializer<'a, 'w, W> {
first: bool,
inner: &'a mut Serializer<'w, W>,
end: &'static [u8],
}
impl<'a, 'w, W> SeqSerializer<'a, 'w, W> {
fn new(inner: &'a mut Serializer<'w, W>, end: &'static [u8]) -> Self {
Self {
first: true,
inner,
end,
}
}
}
impl<W: Write> serde::ser::SerializeSeq for SeqSerializer<'_, '_, W> {
type Ok = ();
type Error = Error;
fn serialize_element<T>(&mut self, value: &T) -> std::result::Result<(), Self::Error>
where
T: ?Sized + serde::Serialize,
{
if self.first {
self.first = false;
} else {
self.inner.out.write_all(COMMA)?;
}
value.serialize(&mut *self.inner)
}
fn end(self) -> std::result::Result<Self::Ok, Self::Error> {
self.inner.out.write_all(self.end).map_err(From::from)
}
}
impl<W: Write> serde::ser::SerializeTuple for SeqSerializer<'_, '_, W> {
type Ok = ();
type Error = Error;
fn serialize_element<T>(&mut self, value: &T) -> std::result::Result<(), Self::Error>
where
T: ?Sized + serde::Serialize,
{
<Self as serde::ser::SerializeSeq>::serialize_element(self, value)
}
fn end(self) -> std::result::Result<Self::Ok, Self::Error> {
<Self as serde::ser::SerializeSeq>::end(self)
}
}
impl<W: Write> serde::ser::SerializeTupleStruct for SeqSerializer<'_, '_, W> {
type Ok = ();
type Error = Error;
fn serialize_field<T>(&mut self, value: &T) -> std::result::Result<(), Self::Error>
where
T: ?Sized + serde::Serialize,
{
<Self as serde::ser::SerializeSeq>::serialize_element(self, value)
}
fn end(self) -> std::result::Result<Self::Ok, Self::Error> {
<Self as serde::ser::SerializeSeq>::end(self)
}
}
impl<W: Write> serde::ser::SerializeTupleVariant for SeqSerializer<'_, '_, W> {
type Ok = ();
type Error = Error;
fn serialize_field<T>(&mut self, value: &T) -> std::result::Result<(), Self::Error>
where
T: ?Sized + serde::Serialize,
{
<Self as serde::ser::SerializeSeq>::serialize_element(self, value)
}
fn end(self) -> std::result::Result<Self::Ok, Self::Error> {
<Self as serde::ser::SerializeSeq>::end(self)
}
}
pub struct MapSerializer<'a, 'w, W> {
first: bool,
inner: &'a mut Serializer<'w, W>,
}
impl<'a, 'w, W> MapSerializer<'a, 'w, W> {
fn new(inner: &'a mut Serializer<'w, W>) -> Self {
Self { first: true, inner }
}
}
impl<W: Write> serde::ser::SerializeMap for MapSerializer<'_, '_, W> {
type Ok = ();
type Error = Error;
fn serialize_key<T>(&mut self, key: &T) -> std::result::Result<(), Self::Error>
where
T: ?Sized + serde::Serialize,
{
if self.first {
self.first = false;
} else {
self.inner.out.write_all(COMMA)?;
}
key.serialize(&mut *self.inner)?;
self.inner.out.write_all(COLON).map_err(From::from)
}
fn serialize_value<T>(&mut self, value: &T) -> std::result::Result<(), Self::Error>
where
T: ?Sized + serde::Serialize,
{
value.serialize(&mut *self.inner)
}
fn end(self) -> std::result::Result<Self::Ok, Self::Error> {
self.inner.out.write_all(BRACE_CLOSE).map_err(From::from)
}
}
pub struct StructSerializer<'a, 'w, W> {
first: bool,
inner: &'a mut Serializer<'w, W>,
}
impl<'a, 'w, W> StructSerializer<'a, 'w, W> {
fn new(inner: &'a mut Serializer<'w, W>) -> Self {
Self { first: true, inner }
}
}
impl<W: Write> serde::ser::SerializeStruct for StructSerializer<'_, '_, W> {
type Ok = ();
type Error = Error;
fn serialize_field<T>(
&mut self,
key: &'static str,
value: &T,
) -> std::result::Result<(), Self::Error>
where
T: ?Sized + serde::Serialize,
{
if self.first {
self.first = false;
} else {
self.inner.out.write_all(COMMA)?;
}
self.inner.serialize_identifier(key)?;
self.inner.out.write_all(COLON)?;
value.serialize(&mut *self.inner)
}
fn end(self) -> std::result::Result<Self::Ok, Self::Error> {
self.inner.out.write_all(BRACE_CLOSE).map_err(From::from)
}
}
impl<W: Write> serde::ser::SerializeStructVariant for StructSerializer<'_, '_, W> {
type Ok = ();
type Error = Error;
fn serialize_field<T>(
&mut self,
key: &'static str,
value: &T,
) -> std::result::Result<(), Self::Error>
where
T: ?Sized + serde::Serialize,
{
<Self as serde::ser::SerializeStruct>::serialize_field(self, key, value)
}
fn end(self) -> std::result::Result<Self::Ok, Self::Error> {
<Self as serde::ser::SerializeStruct>::end(self)
}
}
#[cfg(test)]
mod tests {
mod serialize {
use std::collections::BTreeMap;
use serde::Serialize;
fn to_string<T: Serialize>(value: &T) -> String {
crate::to_string(value).unwrap_or_else(|e| format!("error: {e}"))
}
#[test]
fn test_bool() {
assert_eq!("true", to_string(&true));
assert_eq!("false", to_string(&false));
}
#[test]
fn test_primitives() {
assert_eq!("42", to_string(&42_u8));
assert_eq!("-42", to_string(&-42_i8));
assert_eq!("10242", to_string(&10242_u16));
assert_eq!("-10242", to_string(&-10242_i16));
assert_eq!("1610242", to_string(&1_610_242_u32));
assert_eq!("-1610242", to_string(&-1_610_242_i32));
assert_eq!("2123001610242", to_string(&2_123_001_610_242_u64));
assert_eq!("-2123001610242", to_string(&-2_123_001_610_242_i64));
assert_eq!("0.15625", to_string(&0.15625_f32));
assert_eq!("-0.15625", to_string(&-0.15625_f32));
assert_eq!("2.314001", to_string(&2.314_001_f64));
assert_eq!("-2.314001", to_string(&-2.314_001_f64));
assert_eq!("\"a\"", to_string(&'a'));
assert_eq!("\"abc\"", to_string(&"abc"));
}
#[test]
fn test_bytes() {
assert_eq!("[12,128,255]", to_string(&[12_u8, 128_u8, 255_u8]));
}
#[test]
fn test_optional() {
assert_eq!("null", to_string(&None::<u32>));
assert_eq!("123", to_string(&Some(123)));
}
#[test]
fn test_unit() {
assert_eq!("null", to_string(&()));
}
#[test]
fn test_unit_struct() {
#[derive(Serialize)]
struct Foo;
assert_eq!("Foo()", to_string(&Foo));
}
#[derive(Serialize)]
#[allow(dead_code)]
enum Zahl {
Eins,
Zwei,
Drei,
}
#[test]
fn test_unit_variant() {
assert_eq!("Zwei()", to_string(&Zahl::Zwei));
}
#[test]
fn test_unit_variant_seq() {
assert_eq!(
"[Zwei(),Eins(),Drei()]",
to_string(&[Zahl::Zwei, Zahl::Eins, Zahl::Drei])
);
}
#[test]
fn test_tuple_variant() {
#[derive(Serialize)]
enum T {
T1(u32),
T2(u32, bool),
T3(u32, bool, &'static str),
}
assert_eq!(
"[T3(12,false,\"quux\"),T1(99),T2(42,true)]",
to_string(&[T::T3(12, false, "quux"), T::T1(99), T::T2(42, true)])
);
}
#[test]
fn test_tuple_struct() {
#[derive(Serialize)]
struct Rgb(u8, u8, u8);
assert_eq!("Rgb(36,35,255)", to_string(&Rgb(36, 35, 255)));
}
#[test]
fn test_map() {
let mut m = BTreeMap::new();
m.insert("abc", 123);
m.insert("def", 234);
m.insert("aaa", 8765);
assert_eq!(r#"{"aaa":8765,"abc":123,"def":234}"#, to_string(&m));
}
#[test]
fn test_struct() {
#[derive(Serialize)]
#[serde(rename = "Quux")]
struct Bar {
name: &'static str,
age: usize,
}
assert_eq!(
r#"Quux{name:"Lale",age:26}"#,
to_string(&Bar {
name: "Lale",
age: 26
})
);
}
#[test]
fn test_struct_variant() {
#[derive(Serialize)]
#[allow(dead_code)]
enum Quux {
Foo { name: &'static str, age: usize },
Bar { minimum: usize, maximum: usize },
}
assert_eq!(
r#"Bar{minimum:1001,maximum:1101}"#,
to_string(&Quux::Bar {
minimum: 1001,
maximum: 1101,
})
);
}
}
}