1use yaml_rust::Yaml;
2
3use crate::{
4 source_raw::FileItem, Key, Property, PropertyError, PropertySource, Res, SubKey, SubKeys,
5};
6
7pub(crate) struct YamlValue {
8 item: FileItem,
9 name: String,
10 value: Vec<Yaml>,
11}
12
13impl YamlValue {
14 pub(crate) fn new(item: FileItem) -> Res<Self> {
15 Ok(Self {
16 name: item.name(),
17 value: yaml_rust::YamlLoader::load_from_str(&item.load()?)?,
18 item,
19 })
20 }
21}
22
23fn sub_value<'a>(mut val: &'a Yaml, key: &Key<'_>) -> Option<&'a Yaml> {
24 for n in key.iter() {
25 match n {
26 SubKey::S(n) => match val {
27 Yaml::Hash(t) => val = t.get(&Yaml::String(n.to_string()))?,
28 _ => return None,
29 },
30 SubKey::I(n) => match val {
31 Yaml::Array(vs) => val = vs.get(*n)?,
32 _ => return None,
33 },
34 }
35 }
36 Some(val)
37}
38
39impl PropertySource for YamlValue {
40 fn name(&self) -> &str {
41 &self.name
42 }
43
44 fn get_property(&self, key: &Key<'_>) -> Option<Property<'_>> {
45 for v in &self.value {
46 if let Some(v) = sub_value(v, key) {
47 return match v {
48 Yaml::String(vs) => Some(Property::S(vs)),
49 Yaml::Integer(vs) => Some(Property::I(*vs)),
50 Yaml::Real(vs) => Some(Property::S(vs)),
51 Yaml::Boolean(vs) => Some(Property::B(*vs)),
52 _ => continue,
53 };
54 }
55 }
56 None
57 }
58
59 fn get_sub_keys<'a>(&'a self, key: &Key<'_>, sub_keys: &mut SubKeys<'a>) {
60 for v in &self.value {
61 if let Some(v) = sub_value(v, key) {
62 match v {
63 Yaml::Hash(t) => t.keys().for_each(|f| {
64 if let Some(v) = f.as_str() {
65 sub_keys.insert(v);
66 }
67 }),
68 Yaml::Array(vs) => sub_keys.insert(vs.len()),
69 _ => continue,
70 }
71 }
72 }
73 }
74
75 fn is_empty(&self) -> bool {
76 for v in &self.value {
77 return match v {
78 Yaml::Hash(t) => t.is_empty(),
79 _ => continue,
80 };
81 }
82 false
83 }
84
85 fn reload_source(&self) -> Result<Option<Box<dyn PropertySource>>, PropertyError> {
86 Ok(Some(Box::new(YamlValue::new(self.item.clone())?)))
87 }
88}