use std::{fmt, result, error::Error};
use crate::value::UniNode;
use serde::{ser, de};
use serde::de::Unexpected;
#[derive(Debug)]
pub enum UniNodeSerError {
KeyMustBeAString,
Custom(String),
MissingField(String),
UnknownVariant(String, Vec<String>),
}
pub type Result<T> = result::Result<T, UniNodeSerError>;
struct OneOf<'a>(&'a [String]);
impl<'a> fmt::Display for OneOf<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0.len() {
0 => panic!(),
1 => write!(f, "'{}'", self.0[0]),
2 => write!(f, "'{}' or '{}'", self.0[0], self.0[1]),
_ => {
write!(f, "one of ")?;
for (i, v) in self.0.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "'{}'", v)?;
}
Ok(())
},
}
}
}
impl fmt::Display for UniNodeSerError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
UniNodeSerError::KeyMustBeAString => {
f.write_str("key must be a string")
},
UniNodeSerError::Custom(msg) => f.write_str(msg),
UniNodeSerError::MissingField(fld) => {
write!(f, "Missing field '{}'", fld)
},
UniNodeSerError::UnknownVariant(v, exp) => {
if exp.is_empty() {
write!(f, "Unknown variant '{}'", v)
} else {
let one = OneOf(exp.as_slice());
write!(f, "Unknown variant '{}', expected {}", v, one)
}
},
}
}
}
impl Error for UniNodeSerError {}
impl ser::Error for UniNodeSerError {
fn custom<T: fmt::Display>(msg: T) -> Self {
UniNodeSerError::Custom(msg.to_string())
}
}
impl de::Error for UniNodeSerError {
fn custom<T: fmt::Display>(msg: T) -> Self {
UniNodeSerError::Custom(msg.to_string())
}
fn missing_field(field: &'static str) -> Self {
UniNodeSerError::MissingField(String::from(field))
}
fn unknown_variant(
variant: &str, expected: &'static [&'static str],
) -> Self {
let expected = expected.iter().map(|&v| String::from(v)).collect();
UniNodeSerError::UnknownVariant(String::from(variant), expected)
}
}
impl UniNode {
pub fn invalid_type(&self, exp: &dyn de::Expected) -> UniNodeSerError {
<UniNodeSerError as serde::de::Error>::invalid_type(self.into(), exp)
}
}
impl<'a> From<&'a UniNode> for Unexpected<'a> {
fn from(val: &'a UniNode) -> Unexpected<'a> {
match val {
UniNode::Null => Unexpected::Unit,
UniNode::Boolean(val) => Unexpected::Bool(*val),
UniNode::Integer(val) => Unexpected::Signed(*val),
UniNode::UInteger(val) => Unexpected::Unsigned(*val),
UniNode::Float(val) => Unexpected::Float(*val),
UniNode::String(val) => Unexpected::Str(val),
UniNode::Bytes(val) => {
Unexpected::Bytes(&val[0..val.len().min(10)])
},
UniNode::Array(_) => Unexpected::Seq,
UniNode::Object(_) => Unexpected::Map,
}
}
}