1use alloc::boxed::Box;
9use alloc::string::String;
10use alloc::vec::Vec;
11
12use crate::io::traits::IDestination;
13use crate::nodes::node::Node;
14use crate::stringify::format::{FormatContext, FormatOptions};
15
16pub type SerializeResult = Result<String, String>;
18
19pub type StreamResult = Result<(), String>;
21
22pub trait Serializer {
24 fn can_serialize(&self, node: &Node) -> bool;
26
27 fn serialize(
29 &self,
30 node: &Node,
31 options: &FormatOptions,
32 context: &FormatContext,
33 ) -> SerializeResult;
34
35 fn priority(&self) -> i32 {
37 0
38 }
39}
40
41pub trait FormatWriter {
48 #[allow(dead_code)]
50 fn dest(&mut self) -> &mut dyn IDestination;
51
52 fn write_null(&mut self) -> StreamResult;
54
55 fn write_bool(&mut self, value: bool) -> StreamResult;
57
58 fn write_number(&mut self, num: &crate::nodes::node::Numeric) -> StreamResult;
60
61 fn write_string(&mut self, value: &str) -> StreamResult;
63
64 fn start_array(&mut self, len: usize) -> StreamResult;
66 fn array_value_separator(&mut self, index: usize) -> StreamResult;
67 fn end_array(&mut self) -> StreamResult;
68
69 fn start_set(&mut self, len: usize) -> StreamResult;
72 fn set_value_separator(&mut self, index: usize) -> StreamResult;
73 fn end_set(&mut self) -> StreamResult;
74
75 fn start_mapping(&mut self, len: usize) -> StreamResult;
77 fn write_mapping_key(&mut self, key: &Node) -> StreamResult;
78 fn mapping_key_value_separator(&mut self) -> StreamResult;
79 fn mapping_entry_separator(&mut self, index: usize) -> StreamResult;
80 fn end_mapping(&mut self) -> StreamResult;
81
82 fn write_comment(&mut self, _comment: &str) -> StreamResult {
85 Ok(())
86 }
87
88 fn start_document(&mut self, _index: usize, _total: usize) -> StreamResult {
92 Ok(())
93 }
94
95 fn end_document(&mut self, _index: usize, _total: usize) -> StreamResult {
97 Ok(())
98 }
99}
100
101pub fn walk_node<W: FormatWriter>(writer: &mut W, node: &Node) -> StreamResult {
108 use crate::nodes::node::Node as N;
109
110 match node {
111 N::None => writer.write_null(),
112 N::Boolean(b) => writer.write_bool(*b),
113 N::Str(s, _qt, _style) => writer.write_string(s),
114 N::Number(num) => writer.write_number(num),
115 N::Array(items) => {
116 writer.start_array(items.len())?;
117 for (i, it) in items.iter().enumerate() {
118 if i > 0 {
119 writer.array_value_separator(i)?;
120 }
121 walk_node(writer, it)?;
122 }
123 writer.end_array()
124 }
125 N::Set(items) => {
126 writer.start_set(items.len())?;
127 for (i, it) in items.iter().enumerate() {
128 if i > 0 {
129 writer.set_value_separator(i)?;
130 }
131 walk_node(writer, it)?;
132 }
133 writer.end_set()
134 }
135 N::Mapping(pairs) => {
136 writer.start_mapping(pairs.len())?;
137 for (idx, (k, v)) in pairs.iter().enumerate() {
138 if idx > 0 {
139 writer.mapping_entry_separator(idx)?;
140 }
141 writer.write_mapping_key(k)?;
142 writer.mapping_key_value_separator()?;
143 walk_node(writer, v)?;
144 }
145 writer.end_mapping()
146 }
147 N::Document(nodes) => {
148 if nodes.len() == 1 {
149 writer.start_document(0, 1)?;
150 walk_node(writer, &nodes[0])?;
151 writer.end_document(0, 1)
152 } else {
153 for (i, n) in nodes.iter().enumerate() {
154 writer.start_document(i, nodes.len())?;
155 walk_node(writer, n)?;
156 writer.end_document(i, nodes.len())?;
157 }
158 Ok(())
159 }
160 }
161 N::Tagged(inner, _tag) => walk_node(writer, inner),
162 N::Anchored(inner, _name) => walk_node(writer, inner),
163 N::Alias(_name) => writer.write_null(),
164 N::Documents(docs) => {
165 for (i, d) in docs.iter().enumerate() {
166 writer.start_document(i, docs.len())?;
167 walk_node(writer, d)?;
168 writer.end_document(i, docs.len())?;
169 }
170 Ok(())
171 }
172 N::Comment(c) => writer.write_comment(c),
173 }
174}
175
176pub struct TaggedSerializer {
178 tag: String,
179 serialize_fn: Box<dyn Fn(&Node, &FormatOptions, &FormatContext) -> SerializeResult>,
180}
181
182impl TaggedSerializer {
183 pub fn new<F>(tag: impl Into<String>, serialize_fn: F) -> Self
184 where
185 F: Fn(&Node, &FormatOptions, &FormatContext) -> SerializeResult + 'static,
186 {
187 Self {
188 tag: tag.into(),
189 serialize_fn: Box::new(serialize_fn),
190 }
191 }
192}
193
194impl Serializer for TaggedSerializer {
195 fn can_serialize(&self, node: &Node) -> bool {
196 match node {
197 Node::Tagged(_, tag) => tag == &self.tag,
198 _ => false,
199 }
200 }
201
202 fn serialize(
203 &self,
204 node: &Node,
205 options: &FormatOptions,
206 context: &FormatContext,
207 ) -> SerializeResult {
208 (self.serialize_fn)(node, options, context)
209 }
210
211 fn priority(&self) -> i32 {
212 10 }
214}
215
216pub struct TypeSerializer {
218 serialize_fn: Box<dyn Fn(&Node, &FormatOptions, &FormatContext) -> SerializeResult>,
219 can_serialize_fn: Box<dyn Fn(&Node) -> bool>,
220}
221
222impl TypeSerializer {
223 pub fn new<F, C>(can_serialize: C, serialize_fn: F) -> Self
224 where
225 F: Fn(&Node, &FormatOptions, &FormatContext) -> SerializeResult + 'static,
226 C: Fn(&Node) -> bool + 'static,
227 {
228 Self {
229 serialize_fn: Box::new(serialize_fn),
230 can_serialize_fn: Box::new(can_serialize),
231 }
232 }
233}
234
235impl Serializer for TypeSerializer {
236 fn can_serialize(&self, node: &Node) -> bool {
237 (self.can_serialize_fn)(node)
238 }
239
240 fn serialize(
241 &self,
242 node: &Node,
243 options: &FormatOptions,
244 context: &FormatContext,
245 ) -> SerializeResult {
246 (self.serialize_fn)(node, options, context)
247 }
248}
249
250pub struct SerializerRegistry {
252 serializers: Vec<Box<dyn Serializer>>,
253}
254
255impl SerializerRegistry {
256 pub fn new() -> Self {
257 Self {
258 serializers: alloc::vec::Vec::new(),
259 }
260 }
261
262 pub fn register(&mut self, serializer: Box<dyn Serializer>) {
264 self.serializers.push(serializer);
265 self.serializers
267 .sort_by(|a, b| b.priority().cmp(&a.priority()));
268 }
269
270 pub fn find_serializer(&self, node: &Node) -> Option<&dyn Serializer> {
272 self.serializers
273 .iter()
274 .find(|s| s.can_serialize(node))
275 .map(|s| s.as_ref())
276 }
277
278 pub fn serialize<F>(
280 &self,
281 node: &Node,
282 options: &FormatOptions,
283 context: &FormatContext,
284 default: F,
285 ) -> SerializeResult
286 where
287 F: FnOnce(&Node, &FormatOptions, &FormatContext) -> SerializeResult,
288 {
289 if let Some(serializer) = self.find_serializer(node) {
290 serializer.serialize(node, options, context)
291 } else {
292 default(node, options, context)
293 }
294 }
295}
296
297impl Default for SerializerRegistry {
298 fn default() -> Self {
299 Self::new()
300 }
301}
302
303#[cfg(test)]
304mod tests {
305 use super::*;
306 use crate::nodes::node::Numeric;
307
308 #[test]
309 fn test_tagged_serializer() {
310 let serializer = TaggedSerializer::new("!custom", |node, _opts, _ctx| match node {
311 Node::Tagged(inner, _) => {
312 if let Node::Str(s, _, _) = &**inner {
313 Ok(format!("CUSTOM: {}", s))
314 } else {
315 Err("Expected string".to_string())
316 }
317 }
318 _ => Err("Not a tagged node".to_string()),
319 });
320
321 let node = Node::Tagged(Box::new(Node::from("test")), "!custom".to_string());
322
323 assert!(serializer.can_serialize(&node));
324
325 let opts = FormatOptions::default();
326 let ctx = FormatContext::new();
327 let result = serializer.serialize(&node, &opts, &ctx).unwrap();
328 assert_eq!(result, "CUSTOM: test");
329 }
330
331 #[test]
332 fn test_type_serializer() {
333 let serializer = TypeSerializer::new(
334 |node| matches!(node, Node::Number(Numeric::Integer(n)) if *n > 1000),
335 |node, _opts, _ctx| {
336 if let Node::Number(Numeric::Integer(n)) = node {
337 Ok(format!("{}K", n / 1000))
338 } else {
339 Err("Not a large integer".to_string())
340 }
341 },
342 );
343
344 let small = Node::Number(Numeric::Integer(100));
345 let large = Node::Number(Numeric::Integer(5000));
346
347 assert!(!serializer.can_serialize(&small));
348 assert!(serializer.can_serialize(&large));
349
350 let opts = FormatOptions::default();
351 let ctx = FormatContext::new();
352 let result = serializer.serialize(&large, &opts, &ctx).unwrap();
353 assert_eq!(result, "5K");
354 }
355
356 #[test]
357 fn test_serializer_registry() {
358 let mut registry = SerializerRegistry::new();
359
360 registry.register(Box::new(TypeSerializer::new(
362 |node| matches!(node, Node::Number(Numeric::Integer(n)) if *n > 1000),
363 |node, _opts, _ctx| {
364 if let Node::Number(Numeric::Integer(n)) = node {
365 Ok(format!("{}K", n / 1000))
366 } else {
367 Err("Not a large integer".to_string())
368 }
369 },
370 )));
371
372 let large = Node::Number(Numeric::Integer(5000));
373 let small = Node::Number(Numeric::Integer(100));
374
375 let opts = FormatOptions::default();
376 let ctx = FormatContext::new();
377
378 let result = registry
380 .serialize(&large, &opts, &ctx, |_, _, _| Ok("DEFAULT".to_string()))
381 .unwrap();
382 assert_eq!(result, "5K");
383
384 let result = registry
386 .serialize(&small, &opts, &ctx, |_, _, _| Ok("DEFAULT".to_string()))
387 .unwrap();
388 assert_eq!(result, "DEFAULT");
389 }
390
391 #[test]
392 fn test_priority_ordering() {
393 let mut registry = SerializerRegistry::new();
394
395 registry.register(Box::new(TypeSerializer::new(
397 |_| true,
398 |_, _, _| Ok("LOW".to_string()),
399 )));
400
401 registry.register(Box::new(TaggedSerializer::new("!test", |_, _, _| {
403 Ok("HIGH".to_string())
404 })));
405
406 let node = Node::Tagged(Box::new(Node::from("value")), "!test".to_string());
407
408 let opts = FormatOptions::default();
409 let ctx = FormatContext::new();
410
411 let result = registry
413 .serialize(&node, &opts, &ctx, |_, _, _| Ok("DEFAULT".to_string()))
414 .unwrap();
415 assert_eq!(result, "HIGH");
416 }
417}