1use docspec_core::Result;
4
5pub trait JsonBackend {
9 type Output;
11
12 fn begin_array(&mut self) -> Result<()>;
18 fn begin_object(&mut self) -> Result<()>;
24 fn end_array(&mut self) -> Result<()>;
30 fn end_object(&mut self) -> Result<()>;
36 fn finish(self) -> Result<Self::Output>;
42 fn write_bool(&mut self, b: bool) -> Result<()>;
48 fn write_name(&mut self, name: &str) -> Result<()>;
54 fn write_null(&mut self) -> Result<()>;
60 fn write_number(&mut self, n: u32) -> Result<()>;
66 fn write_string(&mut self, s: &str) -> Result<()>;
72}
73
74#[derive(Debug, Clone, PartialEq, Eq)]
76#[non_exhaustive]
77pub enum Token {
78 BeginArray,
80 BeginObject,
82 BoolValue(bool),
84 EndArray,
86 EndObject,
88 Name(String),
90 NullValue,
92 NumberValue(u32),
94 StringValue(String),
96}
97
98#[derive(Debug, Default)]
103pub struct CapturingBackend {
104 tokens: Vec<Token>,
105}
106
107impl CapturingBackend {
108 #[inline]
110 #[must_use]
111 pub fn new() -> Self {
112 Self::default()
113 }
114
115 #[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}