wyrd/authoring/
serde_json_codec.rs1use core::fmt;
6
7use std::string::String;
8
9use crate::{ValidationError, Weave, WeaveDef};
10
11#[derive(Debug)]
13#[non_exhaustive]
14pub enum JsonCodecError {
15 Parse {
17 source: serde_json::Error,
19 line: usize,
21 column: usize,
23 },
24 Validation(ValidationError),
26 Serialize(serde_json::Error),
28}
29
30impl fmt::Display for JsonCodecError {
31 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32 match self {
33 Self::Parse {
34 source,
35 line,
36 column,
37 } => write!(
38 f,
39 "JSON parse error at line {line}, column {column}: {source}"
40 ),
41 Self::Validation(error) => write!(f, "invalid JSON weave: {error}"),
42 Self::Serialize(error) => write!(f, "JSON serialization error: {error}"),
43 }
44 }
45}
46
47impl std::error::Error for JsonCodecError {
48 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
49 match self {
50 Self::Parse { source, .. } | Self::Serialize(source) => Some(source),
51 Self::Validation(source) => Some(source),
52 }
53 }
54}
55
56impl From<ValidationError> for JsonCodecError {
57 fn from(value: ValidationError) -> Self {
58 Self::Validation(value)
59 }
60}
61
62pub fn from_json(text: &str) -> Result<Weave, JsonCodecError> {
64 let def: WeaveDef = serde_json::from_str(text).map_err(|source| {
65 let line = source.line();
66 let column = source.column();
67 JsonCodecError::Parse {
68 source,
69 line,
70 column,
71 }
72 })?;
73 Ok(Weave::try_from(def)?)
74}
75
76pub fn to_json(weave: &Weave) -> Result<String, JsonCodecError> {
78 serde_json::to_string_pretty(&weave.to_def()).map_err(JsonCodecError::Serialize)
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84 use std::error::Error as _;
85 use std::io;
86 use std::string::ToString;
87
88 struct FailingWriter;
89
90 impl io::Write for FailingWriter {
91 fn write(&mut self, _: &[u8]) -> io::Result<usize> {
92 Err(io::Error::other("writer unavailable"))
93 }
94
95 fn flush(&mut self) -> io::Result<()> {
96 Ok(())
97 }
98 }
99
100 #[test]
101 fn serialize_error_formats_and_retains_its_source() {
102 let mut writer = FailingWriter;
103 io::Write::flush(&mut writer).expect("test writer flushes successfully");
104
105 let source = serde_json::to_writer(FailingWriter, &"codec")
106 .expect_err("writer failure must be preserved as a JSON error");
107 let error = JsonCodecError::Serialize(source);
108
109 assert!(error.to_string().starts_with("JSON serialization error: "));
110 assert!(error.source().is_some());
111 }
112}