use crate::as_yaml::YamlNode;
pub trait MappingView {
fn get(&self, key: &dyn crate::AsYaml) -> Option<YamlNode>;
fn contains_key(&self, key: &dyn crate::AsYaml) -> bool {
self.get(key).is_some()
}
fn len(&self) -> usize {
self.iter().count()
}
fn is_empty(&self) -> bool {
self.iter().next().is_none()
}
fn keys<'a>(&'a self) -> Box<dyn Iterator<Item = YamlNode> + 'a> {
Box::new(self.iter().map(|(k, _)| k))
}
fn values<'a>(&'a self) -> Box<dyn Iterator<Item = YamlNode> + 'a> {
Box::new(self.iter().map(|(_, v)| v))
}
fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = (YamlNode, YamlNode)> + 'a>;
}
impl MappingView for crate::yaml::Mapping {
fn get(&self, key: &dyn crate::AsYaml) -> Option<YamlNode> {
crate::yaml::Mapping::get(self, key)
}
fn contains_key(&self, key: &dyn crate::AsYaml) -> bool {
crate::yaml::Mapping::contains_key(self, key)
}
fn len(&self) -> usize {
crate::yaml::Mapping::len(self)
}
fn is_empty(&self) -> bool {
crate::yaml::Mapping::is_empty(self)
}
fn keys<'a>(&'a self) -> Box<dyn Iterator<Item = YamlNode> + 'a> {
Box::new(crate::yaml::Mapping::keys(self))
}
fn values<'a>(&'a self) -> Box<dyn Iterator<Item = YamlNode> + 'a> {
Box::new(crate::yaml::Mapping::values(self))
}
fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = (YamlNode, YamlNode)> + 'a> {
Box::new(crate::yaml::Mapping::iter(self))
}
}
impl MappingView for crate::anchor_resolution::MergedMapping<'_> {
fn get(&self, key: &dyn crate::AsYaml) -> Option<YamlNode> {
crate::anchor_resolution::MergedMapping::get(self, key)
}
fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = (YamlNode, YamlNode)> + 'a> {
Box::new(crate::anchor_resolution::MergedMapping::iter(self))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::anchor_resolution::{
DocumentMergedExt, DocumentResolvedExt, MappingMergedExt, MergedMapping,
};
use crate::Document;
use std::str::FromStr;
fn collect_keys<M: MappingView + ?Sized>(view: &M) -> Vec<String> {
view.keys()
.map(|k| k.as_scalar().map(|s| s.as_string()).unwrap_or_default())
.collect()
}
fn doc(text: &str) -> Document {
Document::from_str(text).expect("parse")
}
#[test]
fn generic_works_on_plain_mapping() {
let d = doc("a: 1\nb: 2\nc: 3\n");
let root = d.as_mapping().unwrap();
assert_eq!(collect_keys(&root), vec!["a", "b", "c"]);
assert_eq!(<crate::yaml::Mapping as MappingView>::len(&root), 3);
}
#[test]
fn generic_works_on_merged_mapping() {
let yaml = "\
d: &d
a: 1
b: 2
m:
<<: *d
c: 3
";
let d = doc(yaml);
let reg = d.build_anchor_registry();
let m = d.as_mapping().unwrap().get_mapping("m").unwrap();
let merged = m.merged(®);
assert_eq!(collect_keys(&merged), vec!["c", "a", "b"]);
assert_eq!(<MergedMapping as MappingView>::len(&merged), 3);
}
#[test]
fn trait_get_and_contains() {
let yaml = "\
d: &d
x: 1
m:
<<: *d
y: 2
";
let d = doc(yaml);
let reg = d.build_anchor_registry();
let m = d.as_mapping().unwrap().get_mapping("m").unwrap();
let merged = m.merged(®);
let view: &dyn MappingView = &merged;
assert!(view.contains_key(&"x"));
assert!(view.contains_key(&"y"));
assert!(!view.contains_key(&"z"));
assert_eq!(view.get(&"x").unwrap().to_i64(), Some(1));
}
#[test]
fn trait_object_safety() {
let d = doc("a: 1\n");
let root = d.as_mapping().unwrap();
let view: &dyn MappingView = &root;
assert_eq!(view.len(), 1);
}
#[test]
fn is_empty_via_trait() {
let d = doc("{}\n");
let root = d.as_mapping().unwrap();
let view: &dyn MappingView = &root;
assert!(view.is_empty());
}
#[test]
fn values_iter_via_trait() {
let d = doc("a: 1\nb: 2\n");
let root = d.as_mapping().unwrap();
let view: &dyn MappingView = &root;
let nums: Vec<i64> = view.values().filter_map(|v| v.to_i64()).collect();
assert_eq!(nums, vec![1, 2]);
}
#[test]
fn merged_view_via_document_extension() {
let yaml = "\
d: &d
k: 42
m:
<<: *d
";
let d = doc(yaml);
let owned = d.merged().unwrap();
let m = owned.as_mapping().get_merged("m").unwrap();
let view: &dyn MappingView = &m;
assert_eq!(view.get(&"k").unwrap().to_i64(), Some(42));
}
}