1use std::{borrow::Cow, collections::BTreeMap};
2
3use quick_xml::{
4 Writer,
5 events::{BytesDecl, BytesStart, BytesText, Event, attributes::Attribute},
6};
7
8use crate::{
9 EMLError, EMLErrorKind, EMLResultExt, NS_EML, NS_KR, NS_XAL, NS_XNL, io::QualifiedName,
10};
11
12#[derive(Debug, Clone)]
13pub(crate) struct NsDefinitions {
14 default_namespace_uri: Option<&'static str>,
15 namespace_definitions: BTreeMap<&'static str, &'static str>,
16}
17
18pub(crate) struct EMLWriter {
19 ns_definitions: NsDefinitions,
20 writer: Writer<Vec<u8>>,
21}
22
23impl EMLWriter {
24 fn resolve_namespace_prefix(
36 &self,
37 namespace: &str,
38 is_attribute: bool,
39 ) -> Result<Option<&str>, EMLError> {
40 if self.is_default_namespace(Some(namespace)) {
41 if is_attribute {
42 return Err(EMLErrorKind::AttributeNamespaceError).without_span();
46 } else {
47 return Ok(None);
48 }
49 }
50
51 for (prefix, uri) in &self.ns_definitions.namespace_definitions {
52 if *uri == namespace {
53 return Ok(Some(*prefix));
54 }
55 }
56 Err(EMLErrorKind::UnknownNamespace(namespace.to_string())).without_span()
57 }
58
59 fn format_qname<'b, 'c>(
68 &self,
69 name: &'b QualifiedName<'b, 'c>,
70 is_attribute: bool,
71 ) -> Result<Cow<'b, str>, EMLError> {
72 let namespace_name = name
73 .namespace
74 .as_ref()
75 .map(|n| self.resolve_namespace_prefix(n.as_ref(), is_attribute))
76 .transpose()?
77 .flatten();
78
79 match namespace_name {
80 Some(ns_name) => Ok(Cow::Owned(format!(
81 "{}:{}",
82 ns_name,
83 name.local_name.as_ref()
84 ))),
85 None => Ok(Cow::Borrowed(name.local_name.as_ref())),
86 }
87 }
88
89 fn is_default_namespace(&self, namespace: Option<&str>) -> bool {
91 match (namespace, self.ns_definitions.default_namespace_uri) {
92 (Some(ns), Some(def_ns)) => ns == def_ns,
93 (None, None) => true,
94 _ => false,
95 }
96 }
97
98 fn has_default_namespace(&self) -> bool {
100 self.ns_definitions.default_namespace_uri.is_some()
101 }
102}
103
104pub(crate) struct EMLElementWriter<'a> {
105 start_tag: BytesStart<'a>,
106 writer: &'a mut EMLWriter,
107}
108
109impl<'a> EMLElementWriter<'a> {
110 pub(crate) fn new(
111 writer: &'a mut EMLWriter,
112 name: &'a QualifiedName<'a, 'a>,
113 ) -> Result<Self, EMLError> {
114 let elem_name = writer.format_qname(name, false)?;
115 if name.namespace.is_none() && writer.has_default_namespace() {
116 return Err(EMLErrorKind::ElementNamespaceError).without_span();
119 }
120
121 let start_tag = BytesStart::new(elem_name);
122 Ok(EMLElementWriter { start_tag, writer })
123 }
124
125 pub fn attr<'b, 'c>(
126 mut self,
127 name: impl Into<QualifiedName<'b, 'c>>,
128 value: &str,
129 ) -> Result<Self, EMLError> {
130 let name = name.into();
131 let attr_name = self.writer.format_qname(&name, true)?;
132 self = self.attr_raw((attr_name.as_ref(), value));
133 Ok(self)
134 }
135
136 pub fn attr_opt<'b, 'c>(
137 self,
138 name: impl Into<QualifiedName<'b, 'c>>,
139 value: Option<impl AsRef<str>>,
140 ) -> Result<Self, EMLError> {
141 if let Some(v) = value {
142 self.attr(name, v.as_ref())
143 } else {
144 Ok(self)
145 }
146 }
147
148 fn attr_raw<'b>(mut self, attr: impl Into<Attribute<'b>>) -> Self {
149 self.start_tag.push_attribute(attr);
150 self
151 }
152
153 pub fn content(self) -> Result<EMLElementContentWriter<'a>, EMLError> {
154 self.writer
155 .writer
156 .write_event(Event::Start(self.start_tag.borrow()))
157 .without_span()?;
158 Ok(EMLElementContentWriter {
159 start_tag: self.start_tag,
160 writer: self.writer,
161 })
162 }
163
164 pub fn child_option<'b, 'c, T>(
165 self,
166 name: impl Into<QualifiedName<'b, 'c>>,
167 value: Option<T>,
168 child_writer: impl FnOnce(EMLElementWriter, T) -> Result<(), EMLError>,
169 ) -> Result<EMLElementContentWriter<'a>, EMLError> {
170 self.content()?.child_option(name, value, child_writer)
171 }
172
173 pub fn child<'b, 'c>(
174 self,
175 name: impl Into<QualifiedName<'b, 'c>>,
176 child_writer: impl FnOnce(EMLElementWriter) -> Result<(), EMLError>,
177 ) -> Result<EMLElementContentWriter<'a>, EMLError> {
178 self.content()?.child(name, child_writer)
179 }
180
181 pub fn child_elem<'b, 'c>(
182 self,
183 name: impl Into<QualifiedName<'b, 'c>>,
184 value: &impl EMLWriteElement,
185 ) -> Result<EMLElementContentWriter<'a>, EMLError> {
186 self.content()?.child_elem(name, value)
187 }
188
189 pub fn child_elem_option<'b, 'c>(
190 self,
191 name: impl Into<QualifiedName<'b, 'c>>,
192 value: Option<&impl EMLWriteElement>,
193 ) -> Result<EMLElementContentWriter<'a>, EMLError> {
194 self.content()?.child_elem_option(name, value)
195 }
196
197 pub fn child_elems<'b, 'c>(
198 self,
199 name: impl Into<QualifiedName<'b, 'c>>,
200 children: &[impl EMLWriteElement],
201 ) -> Result<EMLElementContentWriter<'a>, EMLError> {
202 self.content()?.child_elems(name, children)
203 }
204
205 pub fn text(self, text: &str) -> Result<EMLElementContentWriter<'a>, EMLError> {
206 self.content()?.text(text)
207 }
208
209 pub fn empty(self) -> Result<(), EMLError> {
210 self.writer
211 .writer
212 .write_event(Event::Empty(self.start_tag.borrow()))
213 .without_span()?;
214 Ok(())
215 }
216}
217
218pub(crate) struct EMLElementContentWriter<'a> {
219 start_tag: BytesStart<'a>,
220 writer: &'a mut EMLWriter,
221}
222
223impl<'a> EMLElementContentWriter<'a> {
224 pub fn child<'b, 'c>(
225 self,
226 name: impl Into<QualifiedName<'b, 'c>>,
227 child_writer: impl FnOnce(EMLElementWriter) -> Result<(), EMLError>,
228 ) -> Result<Self, EMLError> {
229 let name = name.into();
230 let elem_writer = EMLElementWriter::new(self.writer, &name)?;
231 child_writer(elem_writer)?;
232 Ok(self)
233 }
234
235 pub fn child_option<'b, 'c, T>(
236 self,
237 name: impl Into<QualifiedName<'b, 'c>>,
238 value: Option<T>,
239 child_writer: impl FnOnce(EMLElementWriter, T) -> Result<(), EMLError>,
240 ) -> Result<EMLElementContentWriter<'a>, EMLError> {
241 if let Some(v) = value {
242 self.child(name, |w| child_writer(w, v))
243 } else {
244 Ok(self)
245 }
246 }
247
248 pub fn child_elem<'b, 'c>(
249 self,
250 name: impl Into<QualifiedName<'b, 'c>>,
251 value: &impl EMLWriteElement,
252 ) -> Result<Self, EMLError> {
253 self.child(name, write_eml_element(value))
254 }
255
256 pub fn child_elem_option<'b, 'c>(
257 self,
258 name: impl Into<QualifiedName<'b, 'c>>,
259 value: Option<&impl EMLWriteElement>,
260 ) -> Result<EMLElementContentWriter<'a>, EMLError> {
261 self.child_option(name, value, |writer, value| {
262 write_eml_element(value)(writer)
263 })
264 }
265
266 pub fn child_elems<'b, 'c>(
267 mut self,
268 name: impl Into<QualifiedName<'b, 'c>>,
269 children: &[impl EMLWriteElement],
270 ) -> Result<EMLElementContentWriter<'a>, EMLError> {
271 let name = name.into();
272 for child in children {
273 self = self.child_elem(name.clone(), child)?;
274 }
275 Ok(self)
276 }
277
278 pub fn child_elems_map<'b, 'c, T>(
279 mut self,
280 name: impl Into<QualifiedName<'b, 'c>>,
281 children: impl IntoIterator<Item = T>,
282 child_map: impl Fn(EMLElementWriter, T) -> Result<(), EMLError>,
283 ) -> Result<EMLElementContentWriter<'a>, EMLError> {
284 let name = name.into();
285 for child in children {
286 self = self.child(name.clone(), |writer| child_map(writer, child))?;
287 }
288 Ok(self)
289 }
290
291 pub fn text(self, text: &str) -> Result<Self, EMLError> {
292 self.writer
293 .writer
294 .write_event(Event::Text(BytesText::new(text)))
295 .without_span()?;
296 Ok(self)
297 }
298
299 pub fn finish(self) -> Result<(), EMLError> {
300 self.writer
301 .writer
302 .write_event(quick_xml::events::Event::End(self.start_tag.to_end()))
303 .without_span()?;
304 Ok(())
305 }
306}
307
308pub(crate) trait EMLWriteInternal {
309 fn write_root<'a, 'b>(
310 &self,
311 root_name: Option<impl Into<QualifiedName<'a, 'b>>>,
312 default_namespace_uri: Option<Option<&'static str>>,
313 namespace_definitions: Option<BTreeMap<&'static str, &'static str>>,
314 pretty_print: bool,
315 include_declaration: bool,
316 ) -> Result<Vec<u8>, EMLError>;
317
318 fn write_root_str<'a, 'b>(
319 &self,
320 root_name: Option<impl Into<QualifiedName<'a, 'b>>>,
321 default_namespace_uri: Option<Option<&'static str>>,
322 namespace_definitions: Option<BTreeMap<&'static str, &'static str>>,
323 pretty_print: bool,
324 include_declaration: bool,
325 ) -> Result<String, EMLError>;
326}
327
328impl<T> EMLWriteInternal for T
329where
330 T: EMLWriteElement,
331{
332 fn write_root<'a, 'b>(
333 &self,
334 root_name: Option<impl Into<QualifiedName<'a, 'b>>>,
335 default_namespace_uri: Option<Option<&'static str>>,
336 namespace_definitions: Option<BTreeMap<&'static str, &'static str>>,
337 pretty_print: bool,
338 include_declaration: bool,
339 ) -> Result<Vec<u8>, EMLError> {
340 let root = root_name
342 .map(|v| v.into())
343 .unwrap_or_else(|| QualifiedName::new("EML", Some(NS_EML)));
344 let default_namespace_uri = default_namespace_uri.unwrap_or(Some(NS_EML));
345 let namespace_definitions = namespace_definitions.unwrap_or_else(|| {
346 let mut ns_defs = BTreeMap::new();
347 ns_defs.insert("kr", NS_KR);
348 ns_defs.insert("xal", NS_XAL);
349 ns_defs.insert("xnl", NS_XNL);
350 ns_defs
354 });
355
356 let ns_definitions = NsDefinitions {
357 default_namespace_uri,
358 namespace_definitions,
359 };
360
361 let mut writer = if pretty_print {
362 Writer::new_with_indent(Vec::new(), b' ', 4)
363 } else {
364 Writer::new(Vec::new())
365 };
366
367 if include_declaration {
368 writer
369 .write_event(Event::Decl(BytesDecl::new("1.0", Some("UTF-8"), None)))
370 .without_span()?;
371 }
372 let mut eml_writer = EMLWriter {
373 ns_definitions: ns_definitions.clone(),
374 writer,
375 };
376 let mut element = EMLElementWriter::new(&mut eml_writer, &root)?;
377 if let Some(ns_uri) = ns_definitions.default_namespace_uri {
378 element = element.attr_raw(("xmlns", ns_uri));
379 }
380 for (prefix, uri) in &ns_definitions.namespace_definitions {
381 element = element.attr_raw((format!("xmlns:{}", *prefix).as_str(), *uri));
382 }
383 self.write_eml_element(element)?;
384
385 if pretty_print {
387 eml_writer
388 .writer
389 .write_event(Event::Text(BytesText::new("\n")))
390 .without_span()?;
391 }
392 Ok(eml_writer.writer.into_inner())
393 }
394
395 fn write_root_str<'a, 'b>(
396 &self,
397 root_name: Option<impl Into<QualifiedName<'a, 'b>>>,
398 default_namespace_uri: Option<Option<&'static str>>,
399 namespace_definitions: Option<BTreeMap<&'static str, &'static str>>,
400 pretty_print: bool,
401 include_declaration: bool,
402 ) -> Result<String, EMLError> {
403 String::from_utf8(self.write_root(
404 root_name,
405 default_namespace_uri,
406 namespace_definitions,
407 pretty_print,
408 include_declaration,
409 )?)
410 .without_span()
411 }
412}
413
414pub trait EMLWrite {
421 fn write_eml_root(
423 &self,
424 pretty_print: bool,
425 include_declaration: bool,
426 ) -> Result<Vec<u8>, EMLError>;
427
428 fn write_eml_root_str(
430 &self,
431 pretty_print: bool,
432 include_declaration: bool,
433 ) -> Result<String, EMLError>;
434}
435
436impl<T> EMLWrite for T
437where
438 T: EMLWriteInternal,
439{
440 fn write_eml_root(
441 &self,
442 pretty_print: bool,
443 include_declaration: bool,
444 ) -> Result<Vec<u8>, EMLError> {
445 self.write_root(
446 None::<QualifiedName<'_, '_>>,
447 None,
448 None,
449 pretty_print,
450 include_declaration,
451 )
452 }
453
454 fn write_eml_root_str(
456 &self,
457 pretty_print: bool,
458 include_declaration: bool,
459 ) -> Result<String, EMLError> {
460 self.write_root_str(
461 None::<QualifiedName<'_, '_>>,
462 None,
463 None,
464 pretty_print,
465 include_declaration,
466 )
467 }
468}
469
470pub(crate) trait EMLWriteElement {
471 fn write_eml_element(&self, writer: EMLElementWriter) -> Result<(), EMLError>;
472}
473
474pub(crate) fn write_eml_element(
475 element: &impl EMLWriteElement,
476) -> impl FnOnce(EMLElementWriter) -> Result<(), EMLError> {
477 |writer| element.write_eml_element(writer)
478}
479
480#[cfg(test)]
481pub(crate) fn test_write_eml_element<T: crate::io::EMLElement>(
482 element: &T,
483 namespaces: &[&str],
484) -> Result<String, EMLError> {
485 let mut namespace_definitions = BTreeMap::new();
486 let mut default_namespace_uri = Some(None);
487 for ns in namespaces {
488 use crate::NS_DS;
489
490 match *ns {
491 NS_EML => {
492 default_namespace_uri = Some(Some(NS_EML));
493 }
494 NS_KR => {
495 namespace_definitions.insert("kr", NS_KR);
496 }
497 NS_XAL => {
498 namespace_definitions.insert("xal", NS_XAL);
499 }
500 NS_XNL => {
501 namespace_definitions.insert("xnl", NS_XNL);
502 }
503 NS_DS => {
504 namespace_definitions.insert("ds", NS_DS);
505 }
506 _ => {}
507 }
508 }
509
510 element.write_root_str(
511 Some(T::EML_NAME),
512 default_namespace_uri,
513 Some(namespace_definitions),
514 true,
515 false,
516 )
517}