#[cfg(feature = "serde_json")]
use std::convert::TryFrom;
#[cfg(feature = "serde_json")]
use serde_json::{Error as SjError, error::Category};
#[cfg(feature = "serde_json")]
use crate::{AppErrorKind, Context, Error, field};
#[cfg(feature = "serde_json")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde_json")))]
impl From<SjError> for Error {
fn from(err: SjError) -> Self {
build_context(&err).into_error(err)
}
}
#[cfg(feature = "serde_json")]
fn build_context(err: &SjError) -> Context {
let category = err.classify();
let mut context = match category {
Category::Io => Context::new(AppErrorKind::Serialization),
Category::Syntax | Category::Data | Category::Eof => {
Context::new(AppErrorKind::Deserialization)
}
}
.with(field::str("serde_json.category", format!("{:?}", category)));
let line = err.line();
if line != 0 {
let value = u64::try_from(line).unwrap_or(u64::MAX);
context = context.with(field::u64("serde_json.line", value));
}
let column = err.column();
if column != 0 {
let value = u64::try_from(column).unwrap_or(u64::MAX);
context = context.with(field::u64("serde_json.column", value));
}
if line != 0 && column != 0 {
context = context.with(field::str(
"serde_json.position",
format!("{line}:{column}")
));
}
context
}
#[cfg(test)]
mod tests {
use std::io::{self, Write};
use serde_json::json;
use super::*;
use crate::{AppErrorKind, FieldValue};
#[test]
fn io_maps_to_serialization() {
struct FailWriter;
impl Write for FailWriter {
fn write(&mut self, _buf: &[u8]) -> io::Result<usize> {
Err(io::Error::other("fail"))
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
let err = serde_json::to_writer(FailWriter, &json!({"k": "v"})).unwrap_err();
let app: Error = err.into();
assert!(matches!(app.kind, AppErrorKind::Serialization));
assert_eq!(
app.metadata().get("serde_json.category"),
Some(&FieldValue::Str("Io".into()))
);
}
#[test]
fn syntax_maps_to_deserialization() {
let err = serde_json::from_str::<serde_json::Value>("not-json").unwrap_err();
let app: Error = err.into();
assert!(matches!(app.kind, AppErrorKind::Deserialization));
let metadata = app.metadata();
assert_eq!(
metadata.get("serde_json.category"),
Some(&FieldValue::Str("Syntax".into()))
);
assert_eq!(
metadata.get("serde_json.position"),
Some(&FieldValue::Str("1:2".into()))
);
}
}