1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
use crate::error::{self, Error, ErrorImpl};
use crate::Value;
use std::collections::{HashMap, HashSet};
impl Value {
/// Recursively replace all [`Alias`](Value::Alias) nodes with copies of the
/// values referenced by their anchors.
///
/// ```
/// use serde_yaml_gtc::{Value, from_str_value};
///
/// let yaml = "a: &anchor 1\nb: *anchor";
/// let value: Value = from_str_value(yaml).unwrap();
/// assert_eq!(value["b"], Value::Number(1.into(), None));
/// ```
pub fn resolve_aliases(&mut self) -> Result<(), Error> {
fn collect_anchors(value: &Value, anchors: &mut HashMap<String, Value>) {
match value {
Value::Null(anchor)
| Value::Bool(_, anchor)
| Value::Number(_, anchor)
| Value::String(_, anchor) => {
if let Some(name) = anchor {
anchors.insert(name.clone(), value.clone());
}
}
Value::Sequence(seq) => {
if let Some(name) = &seq.anchor {
anchors.insert(name.clone(), value.clone());
}
for item in &seq.elements {
collect_anchors(item, anchors);
}
}
Value::Mapping(map) => {
if let Some(name) = &map.anchor {
anchors.insert(name.clone(), value.clone());
}
for (k, v) in map {
collect_anchors(k, anchors);
collect_anchors(v, anchors);
}
}
Value::Tagged(tagged) => collect_anchors(&tagged.value, anchors),
Value::Alias(_) => {}
}
}
fn resolve(
value: &mut Value,
anchors: &HashMap<String, Value>,
visiting: &mut HashSet<String>,
) -> Result<(), Error> {
match value {
Value::Alias(name) => {
let alias = name.clone();
if !visiting.insert(alias.clone()) {
return Err(error::new(ErrorImpl::MergeRecursion));
}
let mut replacement = match anchors.get(&alias) {
Some(v) => v.clone(),
None => return Err(error::new(ErrorImpl::UnresolvedAlias)),
};
resolve(&mut replacement, anchors, visiting)?;
strip_anchors(&mut replacement);
*value = replacement;
visiting.remove(&alias);
Ok(())
}
Value::Sequence(seq) => {
for item in &mut seq.elements {
resolve(item, anchors, visiting)?;
}
Ok(())
}
Value::Mapping(map) => {
for v in map.values_mut() {
resolve(v, anchors, visiting)?;
}
Ok(())
}
Value::Tagged(tagged) => resolve(&mut tagged.value, anchors, visiting),
_ => Ok(()),
}
}
fn strip_anchors(value: &mut Value) {
match value {
Value::Null(anchor)
| Value::Bool(_, anchor)
| Value::Number(_, anchor)
| Value::String(_, anchor) => {
*anchor = None;
}
Value::Sequence(seq) => {
seq.anchor = None;
for v in &mut seq.elements {
strip_anchors(v);
}
}
Value::Mapping(map) => {
map.anchor = None;
for v in map.values_mut() {
strip_anchors(v);
}
}
Value::Tagged(tagged) => strip_anchors(&mut tagged.value),
Value::Alias(_) => {}
}
}
let mut anchors = HashMap::new();
collect_anchors(self, &mut anchors);
let mut visiting = HashSet::new();
resolve(self, &anchors, &mut visiting)
}
}