ephemeris_documents/yaml/
source.rs1mod leaf;
4mod mapping;
5mod opaque;
6mod read;
7mod text;
8
9use std::fmt;
10
11use yaml_rt::YamlDoc;
12
13use self::leaf::Leaf;
14pub(crate) use self::mapping::{Entry, Mapping};
15pub(crate) use self::opaque::Opaque;
16use self::read::Reader;
17use self::text::Text;
18use crate::backend::Editable;
19use crate::error::{DocumentError, YamlError};
20use crate::header::Applied;
21use crate::path::{KeyPath, Segment};
22
23#[derive(Debug, Clone, PartialEq, Eq)]
30pub(crate) struct Tree {
31 header: Text,
32 root: Entry,
33 footer: Text,
34}
35
36impl Tree {
37 pub(crate) fn parse(text: &str) -> Result<Self, DocumentError> {
43 let document = YamlDoc::parse(text).map_err(DocumentError::yaml_parse)?;
44 match document.document_count() {
45 0 | 1 => Reader::new(text, &document).tree(),
46 count => Err(YamlError::MultipleDocuments { count }.into()),
47 }
48 }
49
50 pub(super) fn new(header: Text, root: Value, footer: Text) -> Self {
51 Self {
52 header,
53 root: Entry::root(root),
54 footer,
55 }
56 }
57
58 pub(crate) fn is_opaque_at(&self, path: &KeyPath) -> bool {
60 let mut entry = &self.root;
61 for segment in path.segments() {
62 let child = match segment {
63 Segment::Key(key) => entry.value().mapping().and_then(|mapping| mapping.get(key)),
64 Segment::Index(_) => None,
65 };
66 let Some(child) = child else {
67 return false;
68 };
69 entry = child;
70 }
71 entry.value().is_unsupported()
72 }
73
74 pub(crate) fn collapse_empty_root(&mut self) {
76 if let Some(mapping) = self.root.value_mut().mapping_mut()
77 && mapping.keys().next().is_none()
78 {
79 mapping.collapse();
80 }
81 }
82
83 pub(super) fn into_mapping(self) -> Option<Mapping> {
85 match self.root.into_value() {
86 Value::Mapping(mapping) => Some(mapping),
87 Value::Leaf(_) | Value::Opaque(_) => None,
88 }
89 }
90}
91
92impl Editable for Tree {
93 type Node = Entry;
94
95 fn header_text(&self) -> &str {
96 self.header.as_str()
97 }
98
99 fn leading(&self) -> (&str, &str) {
100 ("", self.header.as_str())
101 }
102
103 fn set_leading(&mut self, applied: Applied<'_>) {
104 self.header = Text::from(applied.into_text());
105 }
106
107 fn root(&self) -> &Entry {
108 &self.root
109 }
110
111 fn root_mut(&mut self) -> &mut Entry {
112 &mut self.root
113 }
114}
115
116impl fmt::Display for Tree {
117 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118 write!(f, "{}{}{}", self.header, self.root, self.footer)
119 }
120}
121
122#[derive(Debug, Clone, PartialEq, Eq)]
124pub(crate) enum Value {
125 Mapping(Mapping),
127 Leaf(Leaf),
130 Opaque(Opaque),
134}
135
136impl Value {
137 pub(crate) fn mapping(&self) -> Option<&Mapping> {
140 match self {
141 Self::Mapping(mapping) => Some(mapping),
142 Self::Opaque(opaque) => opaque.mapping(),
143 Self::Leaf(_) => None,
144 }
145 }
146
147 pub(crate) fn mapping_mut(&mut self) -> Option<&mut Mapping> {
149 match self {
150 Self::Mapping(mapping) => Some(mapping),
151 Self::Opaque(opaque) => opaque.mapping_mut(),
152 Self::Leaf(_) => None,
153 }
154 }
155
156 pub(crate) const fn is_unsupported(&self) -> bool {
158 matches!(self, Self::Opaque(opaque) if opaque.is_unsupported())
159 }
160
161 fn comment(&self) -> Option<&str> {
163 match self {
164 Self::Mapping(mapping) => mapping.comment(),
165 Self::Leaf(leaf) => leaf.comment(),
166 Self::Opaque(opaque) => opaque.comment(),
167 }
168 }
169
170 fn keep_comment(&mut self, comment: &str) {
172 match self {
173 Self::Mapping(mapping) => mapping.keep_comment(comment),
174 Self::Leaf(leaf) => leaf.keep_comment(comment),
175 Self::Opaque(_) => {}
176 }
177 }
178
179 fn terminate(&mut self) {
180 match self {
181 Self::Mapping(mapping) => mapping.terminate(),
182 Self::Leaf(leaf) => leaf.terminate(),
183 Self::Opaque(opaque) => opaque.terminate(),
184 }
185 }
186}
187
188impl fmt::Display for Value {
189 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
190 match self {
191 Self::Mapping(mapping) => mapping.fmt(f),
192 Self::Leaf(leaf) => leaf.fmt(f),
193 Self::Opaque(opaque) => opaque.fmt(f),
194 }
195 }
196}
197
198#[cfg(test)]
199mod tests;