sise/
serialize_tree.rs

1use alloc::vec::Vec;
2
3use crate::{Serializer, TreeNode};
4
5/// Serializes a tree of nodes into `serializer`.
6///
7/// # Example
8///
9/// ```
10/// use sise::sise_tree;
11///
12/// let tree = sise_tree!(["example", ["1", "2", "3"], ["a", "b", "c"]]);
13///
14/// let style = sise::SerializerStyle {
15///     line_break: "\n",
16///     indentation: " ",
17/// };
18///
19/// let mut result = String::new();
20/// let mut serializer = sise::Serializer::new(style, &mut result);
21///
22/// sise::serialize_tree(&mut serializer, &tree, usize::MAX);
23/// // Don't forget to finish the serializer
24/// serializer.finish(false);
25///
26/// let expected_result = "(example (1 2 3) (a b c))";
27/// assert_eq!(result, expected_result);
28/// ```
29///
30/// If you use multi-line style, atoms at the beginning of a list
31/// will be placed in the same line as the openning `(`:
32///
33/// ```
34/// use sise::sise_tree;
35///
36/// let tree = sise_tree!(["example", ["1", "2", "3"], ["a", "b", "c"]]);
37///
38/// let style = sise::SerializerStyle {
39///     line_break: "\n",
40///     indentation: " ",
41/// };
42///
43/// let mut result = String::new();
44/// let mut serializer = sise::Serializer::new(style, &mut result);
45///
46/// sise::serialize_tree(&mut serializer, &tree, 0);
47/// // Don't forget to finish the serializer
48/// serializer.finish(true);
49///
50/// let expected_result = "(example\n (1\n  2\n  3\n )\n (a\n  b\n  c\n )\n)\n";
51/// assert_eq!(result, expected_result);
52/// ```
53///
54/// It does not consume the serializer, so it can also be used to serialize
55/// a sub-tree:
56///
57/// ```
58/// use sise::sise_tree;
59///
60/// let tree = sise_tree!(["1", "2", "3"]);
61///
62/// let style = sise::SerializerStyle {
63///     line_break: "\n",
64///     indentation: " ",
65/// };
66///
67/// let mut result = String::new();
68/// let mut serializer = sise::Serializer::new(style, &mut result);
69///
70/// // Serialize the head
71/// serializer.begin_list(usize::MAX);
72/// serializer.put_atom("head", usize::MAX);
73///
74/// // Serialize the subtree
75/// sise::serialize_tree(&mut serializer, &tree, usize::MAX);
76///
77/// // Serialize the tail
78/// serializer.put_atom("tail", usize::MAX);
79/// serializer.end_list();
80/// serializer.finish(false);
81///
82/// let expected_result = "(head (1 2 3) tail)";
83/// assert_eq!(result, expected_result);
84/// ```
85pub fn serialize_tree(
86    serializer: &mut Serializer<'_, '_>,
87    root_node: &TreeNode,
88    break_line_at: usize,
89) {
90    enum State<'a> {
91        Beginning(&'a TreeNode),
92        Writing {
93            stack: Vec<core::slice::Iter<'a, TreeNode>>,
94            current_list: core::slice::Iter<'a, TreeNode>,
95            list_beginning: bool,
96        },
97        Finished,
98    }
99
100    let mut state = State::Beginning(root_node);
101
102    loop {
103        match state {
104            State::Beginning(node) => match node {
105                TreeNode::Atom(atom) => {
106                    serializer.put_atom(atom, break_line_at);
107                    state = State::Finished;
108                }
109                TreeNode::List(list) => {
110                    serializer.begin_list(break_line_at);
111                    state = State::Writing {
112                        stack: Vec::new(),
113                        current_list: list.iter(),
114                        list_beginning: true,
115                    };
116                }
117            },
118            State::Writing {
119                ref mut stack,
120                ref mut current_list,
121                ref mut list_beginning,
122            } => {
123                if let Some(node) = current_list.next() {
124                    match node {
125                        TreeNode::Atom(atom) => {
126                            if *list_beginning {
127                                serializer.put_atom(atom, usize::MAX);
128                            } else {
129                                serializer.put_atom(atom, break_line_at);
130                            }
131                            *list_beginning = false;
132                        }
133                        TreeNode::List(list) => {
134                            serializer.begin_list(break_line_at);
135                            stack.push(core::mem::replace(current_list, list.iter()));
136                            *list_beginning = true;
137                        }
138                    }
139                } else {
140                    serializer.end_list();
141                    if let Some(parent_list) = stack.pop() {
142                        *current_list = parent_list;
143                        *list_beginning = false;
144                    } else {
145                        state = State::Finished;
146                    }
147                }
148            }
149            State::Finished => return,
150        }
151    }
152}