Skip to main content

yaml_subset/yaml/
insert.rs

1use super::YamlTypes;
2use super::{AliasedYaml, HashData, HashElement, Yaml};
3use crate::YamlPath;
4use std::collections::BTreeMap;
5use std::ops::Fn;
6
7pub trait Additive: std::ops::Add<Output = Self> + Sized {
8    fn zero() -> Self;
9}
10
11impl Additive for usize {
12    fn zero() -> Self {
13        0
14    }
15}
16
17#[derive(Debug, PartialEq)]
18pub struct MyVec<T>(pub Vec<T>);
19
20impl<T> std::ops::Add<MyVec<T>> for MyVec<T> {
21    type Output = Self;
22    fn add(self, rhs: MyVec<T>) -> Self::Output {
23        Self(self.0.into_iter().chain(rhs.0.into_iter()).collect())
24    }
25}
26
27impl<T> Additive for MyVec<T> {
28    fn zero() -> Self {
29        Self(Vec::new())
30    }
31}
32
33pub trait YamlInsert {
34    fn for_hash<F, R, A: Additive>(&mut self, path: &YamlPath, f: &F, r: &R) -> A
35    where
36        F: Fn(&mut HashElement) -> A,
37        R: Fn(&mut Yaml) -> A;
38
39    fn edit_hash_structure<F>(&mut self, path: &YamlPath, f: &F) -> usize
40    where
41        F: Fn(&mut Vec<HashData>, String, Option<usize>) -> usize;
42
43    /// Find values
44    fn find_values(&mut self, path: &YamlPath) -> MyVec<Yaml> {
45        let f = |e: &mut HashElement| MyVec(vec![e.value.value.clone()]);
46        let r = |hash: &mut Yaml| MyVec(vec![hash.clone()]);
47        self.for_hash(&path, &f, &r)
48    }
49
50    /// Insert AliasedYaml into a hash
51    /// Returns the amount of insertions.
52    /// Can be more than 1 when using indexes or all array elements etc
53    fn insert_into_hash(&mut self, path: &YamlPath, h: &AliasedYaml, overwrite: bool) -> usize {
54        let f = |data: &mut Vec<HashData>, key: String, key_index: Option<usize>| {
55            let value = HashData::Element(HashElement {
56                key,
57                value: h.to_owned(),
58            });
59            if key_index.is_none() {
60                data.push(value);
61                1
62            } else if let Some(index) = key_index {
63                if overwrite {
64                    data[index] = value;
65                    1
66                } else {
67                    0
68                }
69            } else {
70                0
71            }
72        };
73        self.edit_hash_structure(path, &f)
74    }
75
76    fn insert_into_hash_by_call<F>(&mut self, path: &YamlPath, h: F, overwrite: bool) -> usize
77    where
78        F: Fn() -> AliasedYaml,
79    {
80        let f = |data: &mut Vec<HashData>, key: String, key_index: Option<usize>| {
81            let value = HashData::Element(HashElement { key, value: h() });
82            if key_index.is_none() {
83                data.push(value);
84                1
85            } else if let Some(index) = key_index {
86                if overwrite {
87                    data[index] = value;
88                    1
89                } else {
90                    0
91                }
92            } else {
93                0
94            }
95        };
96        self.edit_hash_structure(path, &f)
97    }
98    fn remove_from_hash(&mut self, path: &YamlPath) -> usize {
99        let f = |data: &mut Vec<HashData>, _key: String, key_index: Option<usize>| {
100            if let Some(index) = key_index {
101                data.remove(index);
102                1
103            } else {
104                0
105            }
106        };
107        self.edit_hash_structure(path, &f)
108    }
109    fn rename_field(&mut self, path: &YamlPath, new_name: String) -> usize {
110        let f = |e: &mut HashElement| {
111            e.key = new_name.clone();
112            1
113        };
114        let r = |_hash: &mut Yaml| 0;
115        self.for_hash(&path, &f, &r)
116    }
117    fn to_object(&mut self, path: &YamlPath, object_key: String) -> usize {
118        let f = |e: &mut HashElement| {
119            let val = e.value.clone();
120            let new = AliasedYaml {
121                alias: None,
122                value: Yaml::Hash(vec![HashData::Element(HashElement {
123                    key: object_key.clone(),
124                    value: val,
125                })]),
126            };
127            e.value = new;
128            1
129        };
130        let r = |_hash: &mut Yaml| 0;
131        self.for_hash(&path, &f, &r)
132    }
133    fn move_to_subfield(
134        &mut self,
135        path: &YamlPath,
136        subfield: String,
137        fields_to_move: Vec<String>,
138    ) -> usize {
139        let r = |hash: &mut Yaml| match hash {
140            Yaml::Hash(_data) => {
141                let fields: Vec<_> = fields_to_move
142                    .iter()
143                    .filter_map(|key| hash.key_value_owned(key).map(|val| (key, val)))
144                    .collect();
145                if !fields.is_empty() {
146                    let subfield_value_opt = hash.key_value_mut(&subfield);
147                    let res = if let Some(subfield_value) = subfield_value_opt {
148                        for (key, value) in fields.iter() {
149                            let path = key.parse().unwrap();
150                            subfield_value.insert_into_hash(&path, &value, true);
151                        }
152                        1
153                    } else {
154                        let value = Yaml::Hash(
155                            fields
156                                .clone()
157                                .into_iter()
158                                .map(|(key, value)| {
159                                    HashData::Element(HashElement {
160                                        key: key.clone(),
161                                        value: value.clone(),
162                                    })
163                                })
164                                .collect(),
165                        );
166                        let new = AliasedYaml { alias: None, value };
167                        hash.insert_into_hash(&subfield.parse().unwrap(), &new, false);
168                        1
169                    };
170                    for (key, _) in fields {
171                        hash.remove_from_hash(&key.parse().unwrap());
172                    }
173                    res
174                } else {
175                    0
176                }
177            }
178            _ => 0,
179        };
180        let f = |e: &mut HashElement| {
181            let hash = &mut e.value.value;
182            r(hash)
183        };
184
185        self.for_hash(&path, &f, &r)
186    }
187    fn move_to_map_with_field_as_key(
188        &mut self,
189        path: &YamlPath,
190        old_map_name: String,
191        selector: String,
192        new_map_name: String,
193        keeps: Vec<String>,
194    ) -> usize {
195        let r = |hash: &mut Yaml| match hash {
196            Yaml::Hash(_data) => {
197                if let Some(result) = hash.key_value_owned(&old_map_name) {
198                    if let Yaml::Hash(hash_data) = result.value {
199                        let mut new_hashes: BTreeMap<String, Vec<HashData>> = BTreeMap::new();
200                        let mut old_hashes = Vec::new();
201                        let mut comments = Vec::new();
202                        let mut last_added_to = None;
203                        for mut hash_data in hash_data {
204                            match hash_data {
205                                HashData::Element(ref hash_element) => {
206                                    if let Some(key) =
207                                        hash_element.value.value.key_value_owned(&selector)
208                                    {
209                                        if let Some(s) = key.as_string() {
210                                            if keeps.contains(&s) || s.is_empty() {
211                                                hash_data
212                                                    .remove_from_hash(&selector.parse().unwrap());
213                                                old_hashes.extend(comments.clone());
214                                                comments.clear();
215                                                old_hashes.push(hash_data);
216                                                last_added_to = None
217                                            } else {
218                                                let mut value = hash_element.value.clone();
219                                                value.remove_from_hash(&selector.parse().unwrap());
220
221                                                let new_hash_element =
222                                                    HashData::Element(HashElement {
223                                                        key: hash_element.key.clone(),
224                                                        value,
225                                                    });
226
227                                                if new_hashes.contains_key(&s) {
228                                                    let i = new_hashes.get_mut(&s).unwrap();
229                                                    i.extend(comments.clone());
230                                                    i.push(new_hash_element);
231                                                    comments.clear();
232                                                } else {
233                                                    let mut items = comments.clone();
234                                                    items.push(new_hash_element);
235                                                    new_hashes.insert(s.clone(), items);
236                                                    comments.clear();
237                                                }
238                                                last_added_to = Some(s);
239                                            }
240                                        } else {
241                                            old_hashes.extend(comments.clone());
242                                            comments.clear();
243                                            old_hashes.push(hash_data);
244                                            last_added_to = None
245                                        }
246                                    } else {
247                                        old_hashes.extend(comments.clone());
248                                        comments.clear();
249                                        old_hashes.push(hash_data);
250                                        last_added_to = None
251                                    }
252                                }
253                                HashData::Comment(_) | HashData::InlineComment(_) => {
254                                    comments.push(hash_data)
255                                }
256                            }
257                        }
258                        if let Some(s) = last_added_to {
259                            new_hashes.get_mut(&s).unwrap().extend(comments);
260                        } else {
261                            old_hashes.extend(comments);
262                        }
263                        if !new_hashes.is_empty() {
264                            let new = AliasedYaml {
265                                alias: result.alias.clone(),
266                                value: Yaml::Hash(
267                                    new_hashes
268                                        .into_iter()
269                                        .map(|(key, value)| {
270                                            HashData::Element(HashElement {
271                                                key: key.clone(),
272                                                value: AliasedYaml {
273                                                    alias: None,
274                                                    value: Yaml::Hash(value),
275                                                },
276                                            })
277                                        })
278                                        .collect(),
279                                ),
280                            };
281                            hash.insert_into_hash(&new_map_name.parse().unwrap(), &new, false);
282                            let old = AliasedYaml {
283                                alias: result.alias.clone(),
284                                value: Yaml::Hash(old_hashes),
285                            };
286                            hash.insert_into_hash(&old_map_name.parse().unwrap(), &old, true);
287                            1
288                        } else {
289                            0
290                        }
291                    } else {
292                        0
293                    }
294                } else {
295                    0
296                }
297            }
298            _ => 0,
299        };
300        let f = |e: &mut HashElement| {
301            let hash = &mut e.value.value;
302            r(hash)
303        };
304
305        self.for_hash(&path, &f, &r)
306    }
307}