yaml_edit/
mapping_view.rs1use crate::as_yaml::YamlNode;
49
50pub trait MappingView {
56 fn get(&self, key: &dyn crate::AsYaml) -> Option<YamlNode>;
61
62 fn contains_key(&self, key: &dyn crate::AsYaml) -> bool {
64 self.get(key).is_some()
65 }
66
67 fn len(&self) -> usize {
69 self.iter().count()
70 }
71
72 fn is_empty(&self) -> bool {
74 self.iter().next().is_none()
75 }
76
77 fn keys<'a>(&'a self) -> Box<dyn Iterator<Item = YamlNode> + 'a> {
79 Box::new(self.iter().map(|(k, _)| k))
80 }
81
82 fn values<'a>(&'a self) -> Box<dyn Iterator<Item = YamlNode> + 'a> {
84 Box::new(self.iter().map(|(_, v)| v))
85 }
86
87 fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = (YamlNode, YamlNode)> + 'a>;
89}
90
91impl MappingView for crate::yaml::Mapping {
92 fn get(&self, key: &dyn crate::AsYaml) -> Option<YamlNode> {
93 crate::yaml::Mapping::get(self, key)
94 }
95
96 fn contains_key(&self, key: &dyn crate::AsYaml) -> bool {
97 crate::yaml::Mapping::contains_key(self, key)
98 }
99
100 fn len(&self) -> usize {
101 crate::yaml::Mapping::len(self)
102 }
103
104 fn is_empty(&self) -> bool {
105 crate::yaml::Mapping::is_empty(self)
106 }
107
108 fn keys<'a>(&'a self) -> Box<dyn Iterator<Item = YamlNode> + 'a> {
109 Box::new(crate::yaml::Mapping::keys(self))
110 }
111
112 fn values<'a>(&'a self) -> Box<dyn Iterator<Item = YamlNode> + 'a> {
113 Box::new(crate::yaml::Mapping::values(self))
114 }
115
116 fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = (YamlNode, YamlNode)> + 'a> {
117 Box::new(crate::yaml::Mapping::iter(self))
118 }
119}
120
121impl MappingView for crate::anchor_resolution::MergedMapping<'_> {
122 fn get(&self, key: &dyn crate::AsYaml) -> Option<YamlNode> {
123 crate::anchor_resolution::MergedMapping::get(self, key)
124 }
125
126 fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = (YamlNode, YamlNode)> + 'a> {
127 Box::new(crate::anchor_resolution::MergedMapping::iter(self))
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134 use crate::anchor_resolution::{
135 DocumentMergedExt, DocumentResolvedExt, MappingMergedExt, MergedMapping,
136 };
137 use crate::Document;
138 use std::str::FromStr;
139
140 fn collect_keys<M: MappingView + ?Sized>(view: &M) -> Vec<String> {
143 view.keys()
144 .map(|k| k.as_scalar().map(|s| s.as_string()).unwrap_or_default())
145 .collect()
146 }
147
148 fn doc(text: &str) -> Document {
149 Document::from_str(text).expect("parse")
150 }
151
152 #[test]
153 fn generic_works_on_plain_mapping() {
154 let d = doc("a: 1\nb: 2\nc: 3\n");
155 let root = d.as_mapping().unwrap();
156 assert_eq!(collect_keys(&root), vec!["a", "b", "c"]);
157 assert_eq!(<crate::yaml::Mapping as MappingView>::len(&root), 3);
158 }
159
160 #[test]
161 fn generic_works_on_merged_mapping() {
162 let yaml = "\
163d: &d
164 a: 1
165 b: 2
166m:
167 <<: *d
168 c: 3
169";
170 let d = doc(yaml);
171 let reg = d.build_anchor_registry();
172 let m = d.as_mapping().unwrap().get_mapping("m").unwrap();
173 let merged = m.merged(®);
174
175 assert_eq!(collect_keys(&merged), vec!["c", "a", "b"]);
177 assert_eq!(<MergedMapping as MappingView>::len(&merged), 3);
178 }
179
180 #[test]
181 fn trait_get_and_contains() {
182 let yaml = "\
183d: &d
184 x: 1
185m:
186 <<: *d
187 y: 2
188";
189 let d = doc(yaml);
190 let reg = d.build_anchor_registry();
191 let m = d.as_mapping().unwrap().get_mapping("m").unwrap();
192 let merged = m.merged(®);
193
194 let view: &dyn MappingView = &merged;
195 assert!(view.contains_key(&"x"));
196 assert!(view.contains_key(&"y"));
197 assert!(!view.contains_key(&"z"));
198 assert_eq!(view.get(&"x").unwrap().to_i64(), Some(1));
199 }
200
201 #[test]
202 fn trait_object_safety() {
203 let d = doc("a: 1\n");
205 let root = d.as_mapping().unwrap();
206 let view: &dyn MappingView = &root;
207 assert_eq!(view.len(), 1);
208 }
209
210 #[test]
211 fn is_empty_via_trait() {
212 let d = doc("{}\n");
213 let root = d.as_mapping().unwrap();
214 let view: &dyn MappingView = &root;
215 assert!(view.is_empty());
216 }
217
218 #[test]
219 fn values_iter_via_trait() {
220 let d = doc("a: 1\nb: 2\n");
221 let root = d.as_mapping().unwrap();
222 let view: &dyn MappingView = &root;
223 let nums: Vec<i64> = view.values().filter_map(|v| v.to_i64()).collect();
224 assert_eq!(nums, vec![1, 2]);
225 }
226
227 #[test]
228 fn merged_view_via_document_extension() {
229 let yaml = "\
231d: &d
232 k: 42
233m:
234 <<: *d
235";
236 let d = doc(yaml);
237 let owned = d.merged().unwrap();
238 let m = owned.as_mapping().get_merged("m").unwrap();
239 let view: &dyn MappingView = &m;
241 assert_eq!(view.get(&"k").unwrap().to_i64(), Some(42));
242 }
243}