use std::io::Write;
use struson::writer::{JsonStreamWriter, JsonWriter as _};
use crate::JsonBackend;
use docspec_core::{Error, Result};
pub struct StrusonBackend<W: Write> {
writer: JsonStreamWriter<W>,
}
impl<W: Write> StrusonBackend<W> {
#[inline]
pub fn new(writer: W) -> Self {
Self {
writer: JsonStreamWriter::new(writer),
}
}
}
impl<W: Write> JsonBackend for StrusonBackend<W> {
type Output = W;
#[inline]
fn begin_array(&mut self) -> Result<()> {
self.writer.begin_array().map_err(Error::from)
}
#[inline]
fn begin_object(&mut self) -> Result<()> {
self.writer.begin_object().map_err(Error::from)
}
#[inline]
fn end_array(&mut self) -> Result<()> {
self.writer.end_array().map_err(Error::from)
}
#[inline]
fn end_object(&mut self) -> Result<()> {
self.writer.end_object().map_err(Error::from)
}
#[inline]
fn finish(self) -> Result<W> {
self.writer.finish_document().map_err(Error::from)
}
#[inline]
fn write_bool(&mut self, b: bool) -> Result<()> {
self.writer.bool_value(b).map_err(Error::from)
}
#[inline]
fn write_name(&mut self, name: &str) -> Result<()> {
self.writer.name(name).map_err(Error::from)
}
#[inline]
fn write_null(&mut self) -> Result<()> {
self.writer.null_value().map_err(Error::from)
}
#[inline]
fn write_number(&mut self, n: u32) -> Result<()> {
self.writer.number_value(n).map_err(Error::from)
}
#[inline]
fn write_string(&mut self, s: &str) -> Result<()> {
self.writer.string_value(s).map_err(Error::from)
}
}
#[cfg(test)]
mod tests {
use super::*;
struct ErrorWriter;
impl Write for ErrorWriter {
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
fn write(&mut self, _: &[u8]) -> std::io::Result<usize> {
Err(std::io::Error::new(std::io::ErrorKind::BrokenPipe, "test"))
}
}
#[test]
fn struson_backend_error_propagates_as_io_err() {
let mut b = StrusonBackend::new(ErrorWriter);
let result = b.begin_object();
assert!(matches!(result, Err(Error::Io { .. })));
}
#[test]
fn struson_backend_error_writer_flush_succeeds() {
let mut w = ErrorWriter;
assert!(w.flush().is_ok());
}
#[test]
fn struson_backend_finish_returns_underlying_writer() {
let mut b = StrusonBackend::new(Vec::new());
assert!(b.begin_array().is_ok());
assert!(b.end_array().is_ok());
let result = b.finish();
assert!(result.is_ok());
let bytes = result.unwrap_or_default();
assert!(bytes == b"[]");
}
#[test]
fn struson_backend_writes_array_of_values() {
let mut b = StrusonBackend::new(Vec::new());
assert!(b.begin_array().is_ok());
assert!(b.write_number(1).is_ok());
assert!(b.write_bool(true).is_ok());
assert!(b.write_null().is_ok());
assert!(b.write_string("x").is_ok());
assert!(b.end_array().is_ok());
let result = b.finish();
assert!(result.is_ok());
let bytes = result.unwrap_or_default();
assert!(bytes == br#"[1,true,null,"x"]"#);
}
#[test]
fn struson_backend_writes_empty_object() {
let mut b = StrusonBackend::new(Vec::new());
assert!(b.begin_object().is_ok());
assert!(b.end_object().is_ok());
let result = b.finish();
assert!(result.is_ok());
let bytes = result.unwrap_or_default();
assert!(bytes == b"{}");
}
#[test]
fn struson_backend_writes_nested_structure() {
let mut b = StrusonBackend::new(Vec::new());
assert!(b.begin_object().is_ok());
assert!(b.write_name("a").is_ok());
assert!(b.begin_array().is_ok());
assert!(b.write_number(1).is_ok());
assert!(b.begin_object().is_ok());
assert!(b.write_name("b").is_ok());
assert!(b.write_bool(true).is_ok());
assert!(b.end_object().is_ok());
assert!(b.end_array().is_ok());
assert!(b.end_object().is_ok());
let result = b.finish();
assert!(result.is_ok());
let bytes = result.unwrap_or_default();
assert!(bytes == br#"{"a":[1,{"b":true}]}"#);
}
#[test]
fn struson_backend_writes_simple_key_value() {
let mut b = StrusonBackend::new(Vec::new());
assert!(b.begin_object().is_ok());
assert!(b.write_name("k").is_ok());
assert!(b.write_string("v").is_ok());
assert!(b.end_object().is_ok());
let result = b.finish();
assert!(result.is_ok());
let bytes = result.unwrap_or_default();
assert!(bytes == br#"{"k":"v"}"#);
}
}