Skip to main content

docspec_json/
backend.rs

1//! Backend trait for JSON token emission.
2
3use docspec_core::Result;
4
5/// Low-level JSON token emitter. Implementations write JSON tokens to an
6/// underlying sink. State validation is performed by [`crate::JsonEmitter`],
7/// not by the backend.
8pub trait JsonBackend {
9    /// Type returned by [`JsonBackend::finish`].
10    type Output;
11
12    /// Begin a JSON array (writes `[`).
13    ///
14    /// # Errors
15    ///
16    /// Returns any error produced by the underlying backend.
17    fn begin_array(&mut self) -> Result<()>;
18    /// Begin a JSON object (writes `{`).
19    ///
20    /// # Errors
21    ///
22    /// Returns any error produced by the underlying backend.
23    fn begin_object(&mut self) -> Result<()>;
24    /// End the current JSON array (writes `]`).
25    ///
26    /// # Errors
27    ///
28    /// Returns any error produced by the underlying backend.
29    fn end_array(&mut self) -> Result<()>;
30    /// End the current JSON object (writes `}`).
31    ///
32    /// # Errors
33    ///
34    /// Returns any error produced by the underlying backend.
35    fn end_object(&mut self) -> Result<()>;
36    /// Finish writing and return the backend's output.
37    ///
38    /// # Errors
39    ///
40    /// Returns any error produced by the underlying backend.
41    fn finish(self) -> Result<Self::Output>;
42    /// Write a boolean value.
43    ///
44    /// # Errors
45    ///
46    /// Returns any error produced by the underlying backend.
47    fn write_bool(&mut self, b: bool) -> Result<()>;
48    /// Write an object key.
49    ///
50    /// # Errors
51    ///
52    /// Returns any error produced by the underlying backend.
53    fn write_name(&mut self, name: &str) -> Result<()>;
54    /// Write a `null` value.
55    ///
56    /// # Errors
57    ///
58    /// Returns any error produced by the underlying backend.
59    fn write_null(&mut self) -> Result<()>;
60    /// Write a `u32` numeric value.
61    ///
62    /// # Errors
63    ///
64    /// Returns any error produced by the underlying backend.
65    fn write_number(&mut self, n: u32) -> Result<()>;
66    /// Write a string value.
67    ///
68    /// # Errors
69    ///
70    /// Returns any error produced by the underlying backend.
71    fn write_string(&mut self, s: &str) -> Result<()>;
72}
73
74/// A token captured by [`CapturingBackend`].
75#[derive(Debug, Clone, PartialEq, Eq)]
76pub enum Token {
77    /// Represents `[`.
78    BeginArray,
79    /// Represents `{`.
80    BeginObject,
81    /// A boolean value.
82    BoolValue(bool),
83    /// Represents `]`.
84    EndArray,
85    /// Represents `}`.
86    EndObject,
87    /// An object key.
88    Name(String),
89    /// A `null` value.
90    NullValue,
91    /// A `u32` numeric value.
92    NumberValue(u32),
93    /// A string value.
94    StringValue(String),
95}
96
97/// Backend that records every operation as a [`Token`] without writing anywhere.
98///
99/// Useful for verifying [`crate::JsonEmitter`] behavior without depending on a
100/// real JSON serializer.
101#[derive(Debug, Default)]
102pub struct CapturingBackend {
103    tokens: Vec<Token>,
104}
105
106impl CapturingBackend {
107    /// Create a new empty `CapturingBackend`.
108    #[inline]
109    #[must_use]
110    pub fn new() -> Self {
111        Self::default()
112    }
113
114    /// Borrow the recorded tokens without consuming the backend.
115    #[inline]
116    #[must_use]
117    pub fn tokens(&self) -> &[Token] {
118        &self.tokens
119    }
120}
121
122impl JsonBackend for CapturingBackend {
123    type Output = Vec<Token>;
124
125    #[inline]
126    fn begin_array(&mut self) -> Result<()> {
127        self.tokens.push(Token::BeginArray);
128        Ok(())
129    }
130
131    #[inline]
132    fn begin_object(&mut self) -> Result<()> {
133        self.tokens.push(Token::BeginObject);
134        Ok(())
135    }
136
137    #[inline]
138    fn end_array(&mut self) -> Result<()> {
139        self.tokens.push(Token::EndArray);
140        Ok(())
141    }
142
143    #[inline]
144    fn end_object(&mut self) -> Result<()> {
145        self.tokens.push(Token::EndObject);
146        Ok(())
147    }
148
149    #[inline]
150    fn finish(self) -> Result<Vec<Token>> {
151        Ok(self.tokens)
152    }
153
154    #[inline]
155    fn write_bool(&mut self, b: bool) -> Result<()> {
156        self.tokens.push(Token::BoolValue(b));
157        Ok(())
158    }
159
160    #[inline]
161    fn write_name(&mut self, name: &str) -> Result<()> {
162        self.tokens.push(Token::Name(name.to_string()));
163        Ok(())
164    }
165
166    #[inline]
167    fn write_null(&mut self) -> Result<()> {
168        self.tokens.push(Token::NullValue);
169        Ok(())
170    }
171
172    #[inline]
173    fn write_number(&mut self, n: u32) -> Result<()> {
174        self.tokens.push(Token::NumberValue(n));
175        Ok(())
176    }
177
178    #[inline]
179    fn write_string(&mut self, s: &str) -> Result<()> {
180        self.tokens.push(Token::StringValue(s.to_string()));
181        Ok(())
182    }
183}
184
185#[cfg(test)]
186mod tests {
187    use super::*;
188
189    #[test]
190    fn capturing_backend_starts_empty() {
191        let b = CapturingBackend::new();
192        assert!(b.tokens().is_empty());
193    }
194
195    #[test]
196    fn capturing_backend_records_begin_object() {
197        let mut b = CapturingBackend::new();
198        assert!(b.begin_object().is_ok());
199        assert_eq!(b.tokens(), &[Token::BeginObject]);
200    }
201
202    #[test]
203    fn capturing_backend_records_all_token_types_in_order() {
204        let mut b = CapturingBackend::new();
205        assert!(b.begin_array().is_ok());
206        assert!(b.begin_object().is_ok());
207        assert!(b.write_name("k").is_ok());
208        assert!(b.write_string("v").is_ok());
209        assert!(b.write_bool(true).is_ok());
210        assert!(b.write_number(42).is_ok());
211        assert!(b.write_null().is_ok());
212        assert!(b.end_object().is_ok());
213        assert!(b.end_array().is_ok());
214        assert_eq!(
215            b.tokens(),
216            &[
217                Token::BeginArray,
218                Token::BeginObject,
219                Token::Name("k".to_string()),
220                Token::StringValue("v".to_string()),
221                Token::BoolValue(true),
222                Token::NumberValue(42),
223                Token::NullValue,
224                Token::EndObject,
225                Token::EndArray,
226            ]
227        );
228    }
229
230    #[test]
231    fn capturing_backend_finish_returns_recorded_tokens() {
232        let mut b = CapturingBackend::new();
233        assert!(b.begin_object().is_ok());
234        assert!(b.end_object().is_ok());
235        let result = b.finish();
236        assert!(result.is_ok());
237        let tokens = result.unwrap_or_default();
238        assert!(tokens == vec![Token::BeginObject, Token::EndObject]);
239    }
240}