Skip to main content

docspec_json/
struson_backend.rs

1//! [`JsonBackend`] adapter for `struson::JsonStreamWriter`.
2
3use std::io::Write;
4
5use struson::writer::{JsonStreamWriter, JsonWriter as _};
6
7use crate::JsonBackend;
8use docspec_core::{Error, Result};
9
10/// Adapter wrapping `struson::JsonStreamWriter<W>`.
11///
12/// Forwards each [`JsonBackend`] method to the corresponding struson API call.
13/// Errors from struson are converted to [`docspec_core::Error::Io`].
14pub struct StrusonBackend<W: Write> {
15    writer: JsonStreamWriter<W>,
16}
17
18impl<W: Write> StrusonBackend<W> {
19    /// Create a new `StrusonBackend` wrapping the given writer.
20    #[inline]
21    pub fn new(writer: W) -> Self {
22        Self {
23            writer: JsonStreamWriter::new(writer),
24        }
25    }
26}
27
28impl<W: Write> JsonBackend for StrusonBackend<W> {
29    type Output = W;
30
31    #[inline]
32    fn begin_array(&mut self) -> Result<()> {
33        self.writer.begin_array().map_err(Error::from)
34    }
35
36    #[inline]
37    fn begin_object(&mut self) -> Result<()> {
38        self.writer.begin_object().map_err(Error::from)
39    }
40
41    #[inline]
42    fn end_array(&mut self) -> Result<()> {
43        self.writer.end_array().map_err(Error::from)
44    }
45
46    #[inline]
47    fn end_object(&mut self) -> Result<()> {
48        self.writer.end_object().map_err(Error::from)
49    }
50
51    #[inline]
52    fn finish(self) -> Result<W> {
53        self.writer.finish_document().map_err(Error::from)
54    }
55
56    #[inline]
57    fn write_bool(&mut self, b: bool) -> Result<()> {
58        self.writer.bool_value(b).map_err(Error::from)
59    }
60
61    #[inline]
62    fn write_name(&mut self, name: &str) -> Result<()> {
63        self.writer.name(name).map_err(Error::from)
64    }
65
66    #[inline]
67    fn write_null(&mut self) -> Result<()> {
68        self.writer.null_value().map_err(Error::from)
69    }
70
71    #[inline]
72    fn write_number(&mut self, n: u32) -> Result<()> {
73        self.writer.number_value(n).map_err(Error::from)
74    }
75
76    #[inline]
77    fn write_string(&mut self, s: &str) -> Result<()> {
78        self.writer.string_value(s).map_err(Error::from)
79    }
80}
81
82#[cfg(test)]
83mod tests {
84    use super::*;
85
86    struct ErrorWriter;
87
88    impl Write for ErrorWriter {
89        fn flush(&mut self) -> std::io::Result<()> {
90            Ok(())
91        }
92
93        fn write(&mut self, _: &[u8]) -> std::io::Result<usize> {
94            Err(std::io::Error::new(std::io::ErrorKind::BrokenPipe, "test"))
95        }
96    }
97
98    #[test]
99    fn struson_backend_error_propagates_as_io_err() {
100        let mut b = StrusonBackend::new(ErrorWriter);
101        let result = b.begin_object();
102        assert!(matches!(result, Err(Error::Io { .. })));
103    }
104
105    #[test]
106    fn struson_backend_error_writer_flush_succeeds() {
107        let mut w = ErrorWriter;
108        assert!(w.flush().is_ok());
109    }
110
111    #[test]
112    fn struson_backend_finish_returns_underlying_writer() {
113        let mut b = StrusonBackend::new(Vec::new());
114        assert!(b.begin_array().is_ok());
115        assert!(b.end_array().is_ok());
116        let result = b.finish();
117        assert!(result.is_ok());
118        let bytes = result.unwrap_or_default();
119        assert!(bytes == b"[]");
120    }
121
122    #[test]
123    fn struson_backend_writes_array_of_values() {
124        let mut b = StrusonBackend::new(Vec::new());
125        assert!(b.begin_array().is_ok());
126        assert!(b.write_number(1).is_ok());
127        assert!(b.write_bool(true).is_ok());
128        assert!(b.write_null().is_ok());
129        assert!(b.write_string("x").is_ok());
130        assert!(b.end_array().is_ok());
131        let result = b.finish();
132        assert!(result.is_ok());
133        let bytes = result.unwrap_or_default();
134        assert!(bytes == br#"[1,true,null,"x"]"#);
135    }
136
137    #[test]
138    fn struson_backend_writes_empty_object() {
139        let mut b = StrusonBackend::new(Vec::new());
140        assert!(b.begin_object().is_ok());
141        assert!(b.end_object().is_ok());
142        let result = b.finish();
143        assert!(result.is_ok());
144        let bytes = result.unwrap_or_default();
145        assert!(bytes == b"{}");
146    }
147
148    #[test]
149    fn struson_backend_writes_nested_structure() {
150        let mut b = StrusonBackend::new(Vec::new());
151        assert!(b.begin_object().is_ok());
152        assert!(b.write_name("a").is_ok());
153        assert!(b.begin_array().is_ok());
154        assert!(b.write_number(1).is_ok());
155        assert!(b.begin_object().is_ok());
156        assert!(b.write_name("b").is_ok());
157        assert!(b.write_bool(true).is_ok());
158        assert!(b.end_object().is_ok());
159        assert!(b.end_array().is_ok());
160        assert!(b.end_object().is_ok());
161        let result = b.finish();
162        assert!(result.is_ok());
163        let bytes = result.unwrap_or_default();
164        assert!(bytes == br#"{"a":[1,{"b":true}]}"#);
165    }
166
167    #[test]
168    fn struson_backend_writes_simple_key_value() {
169        let mut b = StrusonBackend::new(Vec::new());
170        assert!(b.begin_object().is_ok());
171        assert!(b.write_name("k").is_ok());
172        assert!(b.write_string("v").is_ok());
173        assert!(b.end_object().is_ok());
174        let result = b.finish();
175        assert!(result.is_ok());
176        let bytes = result.unwrap_or_default();
177        assert!(bytes == br#"{"k":"v"}"#);
178    }
179}