use super::Problem;
use crate::yaml::{Entry, Node, Position, Value};
#[derive(Clone, Copy)]
pub(crate) struct Fields<'a>(&'a [Entry]);
impl<'a> Fields<'a> {
pub(crate) fn get(self, name: &str) -> Option<&'a Entry> {
self.0.iter().find(|entry| entry.key == name)
}
}
pub(crate) trait Strict {
fn fail(&mut self, position: Option<Position>, problem: Problem);
fn entries<'a>(&mut self, node: &'a Node) -> &'a [Entry] {
if let Value::Mapping(entries) = &node.value {
return entries;
}
self.fail(Some(node.position), Problem::Expected("a mapping"));
&[]
}
fn items<'a>(&mut self, node: &'a Node) -> &'a [Node] {
match &node.value {
Value::Sequence(items) => items,
Value::Empty => &[],
_ => {
self.fail(Some(node.position), Problem::Expected("a sequence"));
&[]
}
}
}
fn scalar<'a>(&mut self, node: &'a Node) -> Option<&'a str> {
if let Value::Scalar(scalar) = &node.value {
return Some(&scalar.text);
}
self.fail(Some(node.position), Problem::Expected("a scalar"));
None
}
fn parsed<T>(
&mut self,
node: &Node,
expected: &'static str,
parse: impl Fn(&str) -> Option<T>,
) -> Option<T> {
let text = self.scalar(node)?;
let parsed = parse(text);
if parsed.is_none() {
let value = text.to_owned();
self.fail(Some(node.position), Problem::Invalid { value, expected });
}
parsed
}
fn text(&mut self, node: &Node, expected: &'static str) -> Option<String> {
self.parsed(node, expected, |text| {
(!text.trim().is_empty()).then(|| text.to_owned())
})
}
fn fields<'a>(&mut self, node: &'a Node, allowed: &[&str]) -> Fields<'a> {
let entries = self.entries(node);
for entry in entries {
if !allowed.contains(&entry.key.as_str()) {
let unknown = Problem::UnknownField(entry.key.clone());
self.fail(Some(entry.key_position), unknown);
}
}
Fields(entries)
}
fn required<'a>(
&mut self,
node: &Node,
fields: Fields<'a>,
name: &'static str,
) -> Option<&'a Entry> {
let entry = fields.get(name);
if entry.is_none() {
self.fail(Some(node.position), Problem::MissingField(name));
}
entry
}
}