1#![warn(clippy::all, clippy::pedantic)]
2mod bytes;
3mod errors;
4mod parse;
5mod tests;
6
7pub use crate::errors::YamlParseError;
8
9pub(crate) type Result<T> = std::result::Result<T, YamlParseError>;
10
11use parse::Parser;
12
13use std::{fmt, fmt::Display};
14#[cfg_attr(test, derive(serde::Deserialize, serde::Serialize))]
15#[derive(Clone, Debug, PartialEq, Eq)]
16pub enum Yaml<'a> {
18 Scalar(&'a str),
20
21 Sequence(Vec<Yaml<'a>>),
30
31 Mapping(Vec<Entry<'a>>),
40}
41#[derive(Debug, Clone, Copy, PartialEq)]
42enum PrintStyle {
43 Block,
44 #[allow(unused)]
45 Flow,
46}
47
48fn print_indent(indent: usize, f: &mut fmt::Formatter) -> fmt::Result {
49 write!(f, "{:indent$}", "", indent = indent)
50}
51
52fn print_yaml(
53 node: &Yaml<'_>,
54 indent: usize,
55 f: &mut fmt::Formatter,
56 style: PrintStyle,
57) -> fmt::Result {
58 const INDENT_AMT: usize = 2;
59 match node {
60 Yaml::Scalar(slice) => write!(f, "{}", slice),
61 Yaml::Sequence(seq) => {
62 match style {
63 PrintStyle::Block => {
64 for el in seq.iter() {
65 print_indent(indent, f)?;
66 write!(f, "-")?;
67 match el {
68 Yaml::Scalar(slice) => writeln!(f, " {scal}", scal = slice)?,
69 Yaml::Sequence(..) | Yaml::Mapping(..) => {
70 #[allow(clippy::write_with_newline)]
71 write!(f, "\n")?;
72 print_yaml(el, indent + INDENT_AMT, f, style)?;
73 }
74 }
75 }
76 }
77 PrintStyle::Flow => {
78 write!(f, "[ ")?;
79 let last_idx = seq.len() - 1;
80 for (idx, elem) in seq.iter().enumerate() {
81 if idx == last_idx {
82 write!(f, "{}", elem)?;
83 } else {
84 write!(f, "{}, ", elem)?;
85 }
86 }
87 write!(f, " ]")?;
88 }
89 }
90 Ok(())
91 }
92 Yaml::Mapping(map) => {
93 match style {
94 PrintStyle::Block => {
95 for entry in map.iter() {
96 match &entry.key {
97 Yaml::Scalar(..) => {
98 print_indent(indent, f)?;
99 print_yaml(&entry.key, indent, f, PrintStyle::Block)?;
100 write!(f, " ")?;
101 }
102 Yaml::Sequence(..) | Yaml::Mapping(..) => {
103 print_yaml(&entry.key, indent + INDENT_AMT, f, PrintStyle::Block)?;
104 print_indent(indent, f)?;
105 }
106 }
107 write!(f, ":")?;
108 match &entry.value {
109 Yaml::Scalar(..) => {
110 write!(f, " ")?;
111 print_yaml(&entry.value, indent, f, PrintStyle::Block)?;
112 #[allow(clippy::write_with_newline)]
113 write!(f, "\n")?;
114 }
115 Yaml::Sequence(..) | Yaml::Mapping(..) => {
116 #[allow(clippy::write_with_newline)]
117 write!(f, "\n")?;
118 print_yaml(&entry.value, indent + INDENT_AMT, f, PrintStyle::Block)?
119 }
120 }
121 }
122 }
123 PrintStyle::Flow => {
124 write!(f, "{{")?;
125 let last_idx = map.len() - 1;
126 for (idx, entry) in map.iter().enumerate() {
127 if idx == last_idx {
128 write!(f, "{}", entry)?;
129 } else {
130 write!(f, "{}, ", entry)?;
131 }
132 }
133 write!(f, "}}")?;
134 }
135 }
136 Ok(())
137 }
138 }
139}
140
141impl Display for Yaml<'_> {
142 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
143 print_yaml(&self, 0, f, PrintStyle::Block)
144 }
145}
146#[cfg_attr(test, derive(serde::Deserialize, serde::Serialize))]
147#[derive(Clone, Debug, PartialEq, Eq)]
148pub struct Entry<'a> {
150 #[cfg_attr(test, serde(borrow))]
152 pub key: Yaml<'a>,
153 #[cfg_attr(test, serde(borrow))]
155 pub value: Yaml<'a>,
156}
157
158impl<'a> Entry<'a> {
159 #[allow(clippy::must_use_candidate)]
160 pub fn new(key: Yaml<'a>, value: Yaml<'a>) -> Self {
161 Self { key, value }
162 }
163}
164
165impl<'a> Display for Entry<'a> {
166 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
167 write!(f, "{} : {}", self.key, self.value)
169 }
170}
171
172pub fn parse(input: &str) -> Result<Yaml<'_>> {
177 let mut parser = Parser::new(input)?;
178 parser.parse()
179}