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)]
76pub enum Token {
77 BeginArray,
79 BeginObject,
81 BoolValue(bool),
83 EndArray,
85 EndObject,
87 Name(String),
89 NullValue,
91 NumberValue(u32),
93 StringValue(String),
95}
96
97#[derive(Debug, Default)]
102pub struct CapturingBackend {
103 tokens: Vec<Token>,
104}
105
106impl CapturingBackend {
107 #[inline]
109 #[must_use]
110 pub fn new() -> Self {
111 Self::default()
112 }
113
114 #[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}