use std::{fmt, result};
use std::error::Error;
use super::UniNode;
#[derive(Debug, Clone, PartialEq)]
pub enum Unexpected {
Bool(bool),
Integer(i64),
UInteger(u64),
Float(f64),
Bytes(Vec<u8>),
String(String),
Array,
Object,
Null,
}
impl fmt::Display for Unexpected {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Unexpected::Bool(b) => write!(f, "boolean `{}`", b),
Unexpected::Integer(i) => write!(f, "integer `{}`", i),
Unexpected::UInteger(i) => write!(f, "unsigned integer `{}`", i),
Unexpected::Float(v) => write!(f, "floating point `{}`", v),
Unexpected::String(s) => write!(f, "string {:?}", s),
Unexpected::Bytes(b) => write!(f, "bytes {:?} ...", b),
Unexpected::Array => write!(f, "array"),
Unexpected::Object => write!(f, "object"),
Unexpected::Null => write!(f, "null value"),
}
}
}
impl From<&UniNode> for Unexpected {
fn from(val: &UniNode) -> Unexpected {
match val {
UniNode::Null => Unexpected::Null,
UniNode::Boolean(val) => Unexpected::Bool(*val),
UniNode::Integer(val) => Unexpected::Integer(*val),
UniNode::UInteger(val) => Unexpected::UInteger(*val),
UniNode::Float(val) => Unexpected::Float(*val),
UniNode::String(val) => Unexpected::String(val.clone()),
UniNode::Bytes(val) => {
Unexpected::Bytes(val[0..val.len().min(10)].to_vec())
},
UniNode::Array(_) => Unexpected::Array,
UniNode::Object(_) => Unexpected::Object,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Expected {
Bool,
Integer,
UInteger,
Float,
Bytes,
String,
Array,
Object,
Null,
}
impl fmt::Display for Expected {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Expected::Bool => write!(f, "a boolean"),
Expected::Integer => write!(f, "a integer"),
Expected::UInteger => write!(f, "a unsigned integer"),
Expected::Float => write!(f, "a floating point"),
Expected::String => write!(f, "a string"),
Expected::Bytes => write!(f, "a bytes"),
Expected::Array => write!(f, "a array"),
Expected::Object => write!(f, "a object"),
Expected::Null => write!(f, "a null value"),
}
}
}
#[derive(Debug, PartialEq, Clone)]
pub struct UniNodeError {
pub unexpected: Unexpected,
pub expected: Expected,
}
impl UniNodeError {
pub fn invalid_type(value: &UniNode, expected: Expected) -> Self {
UniNodeError {
unexpected: value.into(),
expected,
}
}
}
impl fmt::Display for UniNodeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"invalid type: {}, expected {}",
self.unexpected, self.expected
)
}
}
impl Error for UniNodeError {}
pub type Result<T> = result::Result<T, UniNodeError>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn expected() {
assert_eq!(format!("{}", Expected::Float), "a floating point");
}
#[test]
fn unexpected() {
let n = UniNode::Bytes(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
let uex = Unexpected::from(&n);
assert_eq!(
format!("{}", uex),
"bytes [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] ..."
);
}
#[test]
fn invalid() {
let n = UniNode::Boolean(false);
let e = UniNodeError::invalid_type(&n, Expected::Float);
assert_eq!(e.unexpected, Unexpected::Bool(false));
assert_eq!(e.expected, Expected::Float);
}
#[test]
fn display() {
let err = UniNodeError {
unexpected: Unexpected::Bool(true),
expected: Expected::Bytes,
};
assert_eq!(
format!("{}", err),
"invalid type: boolean `true`, expected a bytes"
);
}
#[test]
fn handle_error() {
let n = UniNode::Boolean(false);
let err = n.as_str().unwrap_err();
assert!(matches!(err.unexpected, Unexpected::Bool(_)));
assert!(matches!(err.expected, Expected::String));
}
}