1use crate::ast::*;
4use crate::error::TransformationError;
5
6pub type TResult = Result<Element, TransformationError>;
8
9pub type TListResult = Result<Vec<Element>, TransformationError>;
11
12pub type TFuncInplace<S> = Fn(Element, S) -> TResult;
14
15pub type TFunc<S> = Fn(&Element, &[&Element], S) -> TResult;
17
18pub fn apply_func_clone<S: Copy>(
20 func: &TFunc<S>,
21 content: &[Element],
22 path: &[&Element],
23 settings: S,
24) -> TListResult {
25 let mut result = vec![];
26 for child in content {
27 result.push(func(child, path, settings)?);
28 }
29 Ok(result)
30}
31
32pub fn apply_func_drain<S: Copy>(
34 func: &TFuncInplace<S>,
35 content: &mut Vec<Element>,
36 settings: S,
37) -> TListResult {
38 let mut result = vec![];
39 for child in content.drain(..) {
40 result.push(func(child, settings)?);
41 }
42 Ok(result)
43}
44
45pub fn recurse_inplace<S: Copy>(func: &TFuncInplace<S>, root: Element, settings: S) -> TResult {
47 recurse_inplace_template(func, root, settings, &apply_func_drain)
48}
49
50pub fn recurse_inplace_template<S: Copy>(
52 func: &TFuncInplace<S>,
53 mut root: Element,
54 settings: S,
55 content_func: &Fn(&TFuncInplace<S>, &mut Vec<Element>, S) -> TListResult,
56) -> TResult {
57 match root {
58 Element::Document(ref mut e) => {
59 let mut temp = content_func(func, &mut e.content, settings)?;
60 e.content.append(&mut temp);
61 }
62 Element::Formatted(ref mut e) => {
63 let mut temp = content_func(func, &mut e.content, settings)?;
64 e.content.append(&mut temp);
65 }
66 Element::Paragraph(ref mut e) => {
67 let mut temp = content_func(func, &mut e.content, settings)?;
68 e.content.append(&mut temp);
69 }
70 Element::ListItem(ref mut e) => {
71 let mut temp = content_func(func, &mut e.content, settings)?;
72 e.content.append(&mut temp);
73 }
74 Element::List(ref mut e) => {
75 let mut temp = content_func(func, &mut e.content, settings)?;
76 e.content.append(&mut temp);
77 }
78 Element::TableCell(ref mut e) => {
79 let mut temp = content_func(func, &mut e.content, settings)?;
80 e.content.append(&mut temp);
81 }
82 Element::HtmlTag(ref mut e) => {
83 let mut temp = content_func(func, &mut e.content, settings)?;
84 e.content.append(&mut temp);
85 }
86 Element::Gallery(ref mut e) => {
87 let mut temp = content_func(func, &mut e.content, settings)?;
88 e.content.append(&mut temp);
89 }
90 Element::Heading(ref mut e) => {
91 let mut content = content_func(func, &mut e.content, settings)?;
92 let mut caption = content_func(func, &mut e.caption, settings)?;
93 e.caption.append(&mut caption);
94 e.content.append(&mut content);
95 }
96 Element::Template(ref mut e) => {
97 let mut name = content_func(func, &mut e.name, settings)?;
98 let mut content = content_func(func, &mut e.content, settings)?;
99 e.name.append(&mut name);
100 e.content.append(&mut content);
101 }
102 Element::TemplateArgument(ref mut e) => {
103 let mut value = content_func(func, &mut e.value, settings)?;
104 e.value.append(&mut value);
105 }
106 Element::InternalReference(ref mut e) => {
107 let mut target = content_func(func, &mut e.target, settings)?;
108 let mut caption = content_func(func, &mut e.caption, settings)?;
109
110 let mut new_options = vec![];
111 for mut option in e.options.drain(..) {
112 new_options.push(content_func(func, &mut option, settings)?);
113 }
114
115 e.target.append(&mut target);
116 e.options.append(&mut new_options);
117 e.caption.append(&mut caption);
118 }
119 Element::ExternalReference(ref mut e) => {
120 let mut caption = content_func(func, &mut e.caption, settings)?;
121 e.caption.append(&mut caption);
122 }
123 Element::Table(ref mut e) => {
124 let mut caption = content_func(func, &mut e.caption, settings)?;
125 let mut rows = content_func(func, &mut e.rows, settings)?;
126 e.caption.append(&mut caption);
127 e.rows.append(&mut rows);
128 }
129 Element::TableRow(ref mut e) => {
130 let mut cells = content_func(func, &mut e.cells, settings)?;
131 e.cells.append(&mut cells);
132 }
133 Element::Text(_) | Element::Comment(_) | Element::Error(_) => (),
134 };
135 Ok(root)
136}
137
138pub fn recurse_clone<S: Copy>(
140 func: &TFunc<S>,
141 root: &Element,
142 path: &[&Element],
143 settings: S,
144) -> TResult {
145 recurse_clone_template(func, root, path, settings, &apply_func_clone)
146}
147
148pub fn recurse_clone_template<S: Copy>(
150 func: &TFunc<S>,
151 root: &Element,
152 path: &[&Element],
153 settings: S,
154 content_func: &Fn(&TFunc<S>, &[Element], &[&Element], S) -> TListResult,
155) -> TResult {
156 let mut path = path.to_owned();
157 path.push(root);
158 let new = match *root {
159 Element::Document(ref e) => Element::Document(Document {
160 position: e.position.clone(),
161 content: content_func(func, &e.content, &path, settings)?,
162 }),
163 Element::Heading(ref e) => Element::Heading(Heading {
164 position: e.position.clone(),
165 depth: e.depth,
166 caption: content_func(func, &e.caption, &path, settings)?,
167 content: content_func(func, &e.content, &path, settings)?,
168 }),
169 Element::Formatted(ref e) => Element::Formatted(Formatted {
170 position: e.position.clone(),
171 markup: e.markup,
172 content: content_func(func, &e.content, &path, settings)?,
173 }),
174 Element::Paragraph(ref e) => Element::Paragraph(Paragraph {
175 position: e.position.clone(),
176 content: content_func(func, &e.content, &path, settings)?,
177 }),
178 Element::Template(ref e) => Element::Template(Template {
179 position: e.position.clone(),
180 name: content_func(func, &e.name, &path, settings)?,
181 content: content_func(func, &e.content, &path, settings)?,
182 }),
183 Element::TemplateArgument(ref e) => Element::TemplateArgument(TemplateArgument {
184 position: e.position.clone(),
185 name: e.name.clone(),
186 value: content_func(func, &e.value, &path, settings)?,
187 }),
188 Element::InternalReference(ref e) => {
189 let mut new_options = vec![];
190 for option in &e.options {
191 new_options.push(content_func(func, &option, &path, settings)?);
192 }
193
194 Element::InternalReference(InternalReference {
195 position: e.position.clone(),
196 target: content_func(func, &e.target, &path, settings)?,
197 options: new_options,
198 caption: content_func(func, &e.caption, &path, settings)?,
199 })
200 }
201 Element::ExternalReference(ref e) => Element::ExternalReference(ExternalReference {
202 position: e.position.clone(),
203 target: e.target.clone(),
204 caption: content_func(func, &e.caption, &path, settings)?,
205 }),
206 Element::ListItem(ref e) => Element::ListItem(ListItem {
207 position: e.position.clone(),
208 depth: e.depth,
209 kind: e.kind,
210 content: content_func(func, &e.content, &path, settings)?,
211 }),
212 Element::List(ref e) => Element::List(List {
213 position: e.position.clone(),
214 content: content_func(func, &e.content, &path, settings)?,
215 }),
216 Element::Table(ref e) => Element::Table(Table {
217 position: e.position.clone(),
218 attributes: e.attributes.clone(),
219 caption: content_func(func, &e.caption, &path, settings)?,
220 caption_attributes: e.caption_attributes.clone(),
221 rows: content_func(func, &e.rows, &path, settings)?,
222 }),
223 Element::TableRow(ref e) => Element::TableRow(TableRow {
224 position: e.position.clone(),
225 attributes: e.attributes.clone(),
226 cells: content_func(func, &e.cells, &path, settings)?,
227 }),
228 Element::TableCell(ref e) => Element::TableCell(TableCell {
229 position: e.position.clone(),
230 header: e.header,
231 attributes: e.attributes.clone(),
232 content: content_func(func, &e.content, &path, settings)?,
233 }),
234 Element::Comment(ref e) => Element::Comment(e.clone()),
235 Element::Text(ref e) => Element::Text(e.clone()),
236 Element::Error(ref e) => Element::Error(e.clone()),
237 Element::HtmlTag(ref e) => Element::HtmlTag(HtmlTag {
238 position: e.position.clone(),
239 name: e.name.clone(),
240 attributes: e.attributes.clone(),
241 content: content_func(func, &e.content, &path, settings)?,
242 }),
243 Element::Gallery(ref e) => Element::Gallery(Gallery {
244 position: e.position.clone(),
245 attributes: e.attributes.clone(),
246 content: content_func(func, &e.content, &path, settings)?,
247 }),
248 };
249 path.pop();
250 Ok(new)
251}