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)]
76#[non_exhaustive]
77pub enum Token {
78    /// Represents `[`.
79    BeginArray,
80    /// Represents `{`.
81    BeginObject,
82    /// A boolean value.
83    BoolValue(bool),
84    /// Represents `]`.
85    EndArray,
86    /// Represents `}`.
87    EndObject,
88    /// An object key.
89    Name(String),
90    /// A `null` value.
91    NullValue,
92    /// A `u32` numeric value.
93    NumberValue(u32),
94    /// A string value.
95    StringValue(String),
96}
97
98/// Backend that records every operation as a [`Token`] without writing anywhere.
99///
100/// Useful for verifying [`crate::JsonEmitter`] behavior without depending on a
101/// real JSON serializer.
102#[derive(Debug, Default)]
103pub struct CapturingBackend {
104    tokens: Vec<Token>,
105}
106
107impl CapturingBackend {
108    /// Create a new empty `CapturingBackend`.
109    #[inline]
110    #[must_use]
111    pub fn new() -> Self {
112        Self::default()
113    }
114
115    /// Borrow the recorded tokens without consuming the backend.
116    #[inline]
117    #[must_use]
118    pub fn tokens(&self) -> &[Token] {
119        &self.tokens
120    }
121}
122
123impl JsonBackend for CapturingBackend {
124    type Output = Vec<Token>;
125
126    #[inline]
127    fn begin_array(&mut self) -> Result<()> {
128        self.tokens.push(Token::BeginArray);
129        Ok(())
130    }
131
132    #[inline]
133    fn begin_object(&mut self) -> Result<()> {
134        self.tokens.push(Token::BeginObject);
135        Ok(())
136    }
137
138    #[inline]
139    fn end_array(&mut self) -> Result<()> {
140        self.tokens.push(Token::EndArray);
141        Ok(())
142    }
143
144    #[inline]
145    fn end_object(&mut self) -> Result<()> {
146        self.tokens.push(Token::EndObject);
147        Ok(())
148    }
149
150    #[inline]
151    fn finish(self) -> Result<Vec<Token>> {
152        Ok(self.tokens)
153    }
154
155    #[inline]
156    fn write_bool(&mut self, b: bool) -> Result<()> {
157        self.tokens.push(Token::BoolValue(b));
158        Ok(())
159    }
160
161    #[inline]
162    fn write_name(&mut self, name: &str) -> Result<()> {
163        self.tokens.push(Token::Name(name.to_string()));
164        Ok(())
165    }
166
167    #[inline]
168    fn write_null(&mut self) -> Result<()> {
169        self.tokens.push(Token::NullValue);
170        Ok(())
171    }
172
173    #[inline]
174    fn write_number(&mut self, n: u32) -> Result<()> {
175        self.tokens.push(Token::NumberValue(n));
176        Ok(())
177    }
178
179    #[inline]
180    fn write_string(&mut self, s: &str) -> Result<()> {
181        self.tokens.push(Token::StringValue(s.to_string()));
182        Ok(())
183    }
184}
185
186#[cfg(test)]
187mod tests {
188    use super::*;
189
190    #[test]
191    fn capturing_backend_starts_empty() {
192        let b = CapturingBackend::new();
193        assert!(b.tokens().is_empty());
194    }
195
196    #[test]
197    fn capturing_backend_records_begin_object() {
198        let mut b = CapturingBackend::new();
199        assert!(b.begin_object().is_ok());
200        assert_eq!(b.tokens(), &[Token::BeginObject]);
201    }
202
203    #[test]
204    fn capturing_backend_records_all_token_types_in_order() {
205        let mut b = CapturingBackend::new();
206        assert!(b.begin_array().is_ok());
207        assert!(b.begin_object().is_ok());
208        assert!(b.write_name("k").is_ok());
209        assert!(b.write_string("v").is_ok());
210        assert!(b.write_bool(true).is_ok());
211        assert!(b.write_number(42).is_ok());
212        assert!(b.write_null().is_ok());
213        assert!(b.end_object().is_ok());
214        assert!(b.end_array().is_ok());
215        assert_eq!(
216            b.tokens(),
217            &[
218                Token::BeginArray,
219                Token::BeginObject,
220                Token::Name("k".to_string()),
221                Token::StringValue("v".to_string()),
222                Token::BoolValue(true),
223                Token::NumberValue(42),
224                Token::NullValue,
225                Token::EndObject,
226                Token::EndArray,
227            ]
228        );
229    }
230
231    #[test]
232    fn capturing_backend_finish_returns_recorded_tokens() {
233        let mut b = CapturingBackend::new();
234        assert!(b.begin_object().is_ok());
235        assert!(b.end_object().is_ok());
236        let result = b.finish();
237        assert!(result.is_ok());
238        let tokens = result.unwrap_or_default();
239        assert!(tokens == vec![Token::BeginObject, Token::EndObject]);
240    }
241}