ephemeris_documents/yaml/source/read/
value.rs1use yaml_rt::{CollectionStyle, NodeId, SemanticKind};
4
5use super::fit::Parsed;
6use super::{Bounds, Mapping, Reader, Text, Value};
7use crate::error::DocumentError;
8use crate::path::Segment;
9
10#[derive(Clone, Copy)]
12pub(super) enum Site {
13 Root { line: usize },
15 Entry { colon_end: usize, indent: usize },
18}
19
20impl Site {
21 pub(super) const fn before(self) -> usize {
23 match self {
24 Self::Root { line } => line,
25 Self::Entry {
26 colon_end,
27 indent: _,
28 } => colon_end,
29 }
30 }
31
32 pub(super) const fn flow_indent(self, step: usize) -> usize {
34 match self {
35 Self::Root { line: _ } => 0,
36 Self::Entry {
37 colon_end: _,
38 indent,
39 } => indent.saturating_add(step),
40 }
41 }
42}
43
44impl Reader<'_> {
45 pub(super) fn value(
48 &self,
49 name: &str,
50 node: NodeId,
51 span: Bounds,
52 colon_end: usize,
53 indent: usize,
54 ) -> Result<Parsed<Value>, DocumentError> {
55 if self.mapping_style(node).is_none() {
56 return Ok(self.leaf(colon_end, node, span)?.map(Value::Leaf));
57 }
58 let site = Site::Entry { colon_end, indent };
59 let fit = self
60 .mapping(node, span, site)
61 .map_err(|error| error.under(Segment::Key(name.to_owned())))?;
62 fit.map_or_else(
63 || {
64 self.opaque(site, node, span)
65 .map_err(|error| error.under(Segment::Key(name.to_owned())))
66 },
67 |parsed| Ok(parsed.map(Value::Mapping)),
68 )
69 }
70
71 pub(super) fn mapping_style(&self, node: NodeId) -> Option<CollectionStyle> {
73 let Some(SemanticKind::Mapping { style }) = self.document.semantic_kind(node) else {
74 return None;
75 };
76 Some(style)
77 }
78
79 pub(super) fn mapping(
82 &self,
83 node: NodeId,
84 span: Bounds,
85 site: Site,
86 ) -> Result<Option<Parsed<Mapping>>, DocumentError> {
87 match self.mapping_style(node) {
88 Some(CollectionStyle::Block) => self.block_mapping(node, site),
89 Some(CollectionStyle::Flow) => self.empty_flow_mapping(node, span, site),
90 None => Ok(None),
91 }
92 }
93
94 fn block_mapping(
95 &self,
96 node: NodeId,
97 site: Site,
98 ) -> Result<Option<Parsed<Mapping>>, DocumentError> {
99 match site {
100 Site::Root { line: _ } => Ok(self.block(node, 0)?.map(|parsed| {
101 parsed.map(|block| {
102 Mapping::block(Text::default(), block.entries, block.indent, self.step)
103 })
104 })),
105 Site::Entry { colon_end, indent } => {
106 let opening_end = self.line_end(colon_end);
107 match self.block(node, opening_end)? {
108 Some(Parsed { value: block, end }) if block.indent > indent => {
109 let opening = Text::from(self.slice(colon_end, opening_end)?);
110 Ok(Some(Parsed {
111 value: Mapping::block(opening, block.entries, block.indent, self.step),
112 end,
113 }))
114 }
115 Some(_) | None => Ok(None),
116 }
117 }
118 }
119 }
120
121 fn empty_flow_mapping(
122 &self,
123 node: NodeId,
124 span: Bounds,
125 site: Site,
126 ) -> Result<Option<Parsed<Mapping>>, DocumentError> {
127 let indent = site.flow_indent(self.step);
128 let Some(brace) = self.empty_braces(node, span) else {
129 return Ok(None);
130 };
131 let end = self.line_end(span.end);
132 let mapping = Mapping::empty_flow(
133 Text::from(self.slice(site.before(), brace)?),
134 Text::from(self.slice(brace, span.end)?),
135 Text::from(self.slice(span.end, end)?),
136 indent,
137 self.step,
138 );
139 Ok(Some(Parsed {
140 value: mapping,
141 end,
142 }))
143 }
144}