ephemeris_documents/yaml/
backend.rs1use super::YamlDocument;
4use super::source::{Entry, Tree, Value};
5use crate::annotation::Annotated;
6use crate::backend::{Backend, Editable as _};
7use crate::error::{DocumentError, InternalError, MergeError, YamlError};
8use crate::format::Format;
9use crate::header::Existing;
10use crate::merge::Node as _;
11use crate::path::KeyPath;
12
13#[derive(Debug, Clone, Copy)]
16pub(crate) struct Yaml;
17
18impl Backend for Yaml {
19 type Document = Tree;
20
21 fn parse(&self, source: &str) -> Result<Tree, DocumentError> {
22 Tree::parse(source)
23 }
24
25 fn string_leaf(&self, node: &Entry) -> Result<Option<String>, DocumentError> {
26 Ok(match node.value() {
27 Value::Leaf(leaf) => leaf.decoded().map(str::to_owned),
28 Value::Mapping(_) | Value::Opaque(_) => None,
29 })
30 }
31
32 fn descend<'n>(
33 &self,
34 node: &'n Entry,
35 key: &str,
36 path: &[String],
37 ) -> Result<Option<&'n Entry>, DocumentError> {
38 if node.value().is_unsupported() {
39 return Err(YamlError::UnsupportedLayout {
40 path: KeyPath::from(path),
41 }
42 .into());
43 }
44 Ok(node.child(key))
45 }
46
47 fn explain(&self, current: &Tree, error: MergeError) -> DocumentError {
48 match error {
49 MergeError::TypeConflict { path } if current.is_opaque_at(&path) => {
50 YamlError::UnsupportedLayout { path }.into()
51 }
52 MergeError::TypeConflict { path } => MergeError::TypeConflict { path }.into(),
53 }
54 }
55
56 fn format(&self) -> Format {
57 Format::Yaml
58 }
59
60 fn build(&self, desired: &Annotated) -> Result<Tree, DocumentError> {
61 let canonical = YamlDocument::new(desired).to_string();
62 Tree::parse(&canonical).map_err(|source| InternalError::yaml_rendered(source).into())
63 }
64
65 fn finish(&self, current: &mut Tree, desired: &Tree, existing: Existing) {
67 current.collapse_empty_root();
68 current.apply_header(desired, existing);
69 }
70}
71
72#[cfg(test)]
73mod tests;