From c7b218fade56e2d5434db5a0003daf15db4dea65 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sat, 11 Nov 2023 14:57:07 +0300 Subject: [PATCH] do not merge rules --- src/patch/device.rs | 2 +- src/patch/mod.rs | 40 +++++++++++++--- src/patch/peripheral.rs | 8 ++-- src/patch/register.rs | 2 +- src/patch/yaml_ext.rs | 103 +++++++++++++++++++++++++++++++++++----- 5 files changed, 131 insertions(+), 24 deletions(-) diff --git a/src/patch/device.rs b/src/patch/device.rs index 365ba1e6..c79d6258 100644 --- a/src/patch/device.rs +++ b/src/patch/device.rs @@ -151,7 +151,7 @@ impl DeviceExt for Device { // Now process all peripherals for (periphspec, val) in device { - let periphspec = periphspec.str()?; + let periphspec = periphspec.key()?; if !periphspec.starts_with('_') { //val["_path"] = device["_path"]; // TODO: check self.process_peripheral(periphspec, val.hash()?, update_fields) diff --git a/src/patch/mod.rs b/src/patch/mod.rs index fc111c05..1a1c3f34 100644 --- a/src/patch/mod.rs +++ b/src/patch/mod.rs @@ -97,6 +97,7 @@ fn abspath(frompath: &Path, relpath: &Path) -> Result { /// Recursively loads any included YAML files. pub fn yaml_includes(parent: &mut Hash) -> Result> { let y_path = "_path".to_yaml(); + let _include = "_include".to_yaml(); let mut included = vec![]; let self_path = PathBuf::from(parent.get(&y_path).unwrap().str()?); let inc = parent.get_vec("_include")?.unwrap_or(&Vec::new()).clone(); @@ -123,7 +124,7 @@ pub fn yaml_includes(parent: &mut Hash) -> Result> { for (pspec, val) in child.iter_mut() { if !pspec.str()?.starts_with('_') { match val { - Yaml::Hash(val) if val.contains_key(&"_include".to_yaml()) => { + Yaml::Hash(val) if val.contains_key(&_include) => { val.insert(y_path.clone(), ypath.clone()); included.extend(yaml_includes(val)?); } @@ -145,11 +146,11 @@ fn update_dict(parent: &mut Hash, child: &Hash) -> Result<()> { for (key, val) in child.iter() { match key { Yaml::String(key) if key == "_path" || key == "_include" => continue, - key if parent.contains_key(key) => { + Yaml::String(k) if parent.contains_key(key) && k.starts_with("_") => { if let Entry::Occupied(mut e) = parent.entry(key.clone()) { match e.get_mut() { el if el == val => { - println!("In {key:?}: dublicate rule {val:?}, ignored"); + println!("In {k}: dublicate rule {val:?}, ignored"); } Yaml::Array(a) => match val { Yaml::Array(val) => { @@ -159,7 +160,7 @@ fn update_dict(parent: &mut Hash, child: &Hash) -> Result<()> { if !a.contains(val) { a.push(val.clone()); } else { - println!("In {key:?}: dublicate rule {val:?}, ignored"); + println!("In {k}: dublicate rule {val:?}, ignored"); } } _ => {} @@ -174,11 +175,11 @@ fn update_dict(parent: &mut Hash, child: &Hash) -> Result<()> { a.insert(0, s.clone()); e.insert(Yaml::Array(a)); } else { - println!("In {key:?}: dublicate rule {s:?}, ignored"); + println!("In {k}: dublicate rule {s:?}, ignored"); } } s2 if matches!(s2, Yaml::String(_)) => { - println!("In {key:?}: conflicting rules {s:?} and {s2:?}, ignored"); + println!("In {k}: conflicting rules {s:?} and {s2:?}, ignored"); } _ => {} }, @@ -186,6 +187,33 @@ fn update_dict(parent: &mut Hash, child: &Hash) -> Result<()> { } } } + Yaml::String(_) if parent.contains_key(key) => { + let mut i = 0; + loop { + let key = Yaml::Array(vec![key.clone(), Yaml::Integer(i)]); + if !parent.contains_key(&key) { + parent.insert(key, val.clone()); + break; + } + i += 1; + } + } + Yaml::Array(a) + if parent.contains_key(key) + && matches!(a.as_slice(), [Yaml::String(_), Yaml::Integer(_)]) => + { + if let [k @ Yaml::String(_), Yaml::Integer(_)] = a.as_slice() { + let mut i = 0; + loop { + let key = Yaml::Array(vec![k.clone(), Yaml::Integer(i)]); + if !parent.contains_key(&key) { + parent.insert(key, val.clone()); + break; + } + i += 1; + } + } + } _ => { parent.insert(key.clone(), val.clone()); } diff --git a/src/patch/peripheral.rs b/src/patch/peripheral.rs index 535256ac..442d9dfe 100644 --- a/src/patch/peripheral.rs +++ b/src/patch/peripheral.rs @@ -335,7 +335,7 @@ impl PeripheralExt for Peripheral { // Handle registers for (rspec, register) in pmod { - let rspec = rspec.str()?; + let rspec = rspec.key()?; if !rspec.starts_with('_') { self.process_register(rspec, register.hash()?, update_fields) .with_context(|| format!("According to `{rspec}`"))?; @@ -358,7 +358,7 @@ impl PeripheralExt for Peripheral { // Handle clusters for (cspec, cluster) in pmod.hash_iter("_clusters") { - let cspec = cspec.str()?; + let cspec = cspec.key()?; if !cspec.starts_with('_') { self.process_cluster(cspec, cluster.hash()?, update_fields) .with_context(|| format!("According to `{cspec}`"))?; @@ -840,7 +840,7 @@ impl ClusterExt for Cluster { // Handle clusters for (cspec, cluster) in pmod.hash_iter("_clusters") { - let cspec = cspec.str()?; + let cspec = cspec.key()?; if !cspec.starts_with('_') { self.process_cluster(cspec, cluster.hash()?, update_fields) .with_context(|| format!("According to `{cspec}`"))?; @@ -849,7 +849,7 @@ impl ClusterExt for Cluster { // Handle registers for (rspec, register) in pmod { - let rspec = rspec.str()?; + let rspec = rspec.key()?; if !rspec.starts_with('_') { self.process_register(rspec, register.hash()?, update_fields) .with_context(|| format!("According to `{rspec}`"))?; diff --git a/src/patch/register.rs b/src/patch/register.rs index 54bb9eb7..c7e0e0fa 100644 --- a/src/patch/register.rs +++ b/src/patch/register.rs @@ -172,7 +172,7 @@ impl RegisterExt for Register { // Handle fields if update_fields { for (fspec, field) in rmod { - let fspec = fspec.str()?; + let fspec = fspec.key()?; if !fspec.starts_with('_') { self.process_field(pname, fspec, field) .with_context(|| format!("Processing field matched to `{fspec}`"))?; diff --git a/src/patch/yaml_ext.rs b/src/patch/yaml_ext.rs index 6771e3e8..d02a5037 100644 --- a/src/patch/yaml_ext.rs +++ b/src/patch/yaml_ext.rs @@ -12,6 +12,8 @@ pub enum YamlError { NotVec(Yaml), #[error("Value is not a string: {0:?}")] NotStr(Yaml), + #[error("Value is not a supported hash key: {0:?}")] + NotKey(Yaml), #[error("Value is not integer: {0:?}")] NotInt(Yaml), #[error("Value is not boolean: {0:?}")] @@ -23,6 +25,7 @@ pub trait AsType { fn hash(&self) -> Result<&Hash, YamlError>; fn vec(&self) -> Result<&Vec, YamlError>; fn str(&self) -> Result<&str, YamlError>; + fn key(&self) -> Result<&str, YamlError>; fn i64(&self) -> Result; fn bool(&self) -> Result; } @@ -44,6 +47,19 @@ impl AsType for Yaml { fn str(&self) -> Result<&str, YamlError> { self.as_str().ok_or_else(|| YamlError::NotStr(self.clone())) } + fn key(&self) -> Result<&str, YamlError> { + match self { + Yaml::String(k) => Ok(k), + Yaml::Array(a) if matches!(a.as_slice(), [Yaml::String(_), Yaml::Integer(_)]) => { + if let [Yaml::String(k), Yaml::Integer(_)] = a.as_slice() { + Ok(k) + } else { + unreachable!() + } + } + _ => Err(YamlError::NotKey(self.clone())), + } + } fn i64(&self) -> Result { parse_i64(self).ok_or_else(|| YamlError::NotInt(self.clone())) } @@ -148,26 +164,29 @@ impl<'a> Iterator for OverStringIter<'a> { type HashIter<'a> = OptIter>; -pub trait GetVal { - fn get_bool(&self, k: &str) -> Result>; - fn get_i64(&self, k: &str) -> Result>; - fn get_u64(&self, k: &str) -> Result> { +pub trait GetVal +where + K: ?Sized, +{ + fn get_bool(&self, k: &K) -> Result>; + fn get_i64(&self, k: &K) -> Result>; + fn get_u64(&self, k: &K) -> Result> { self.get_i64(k).map(|v| v.map(|v| v as u64)) } - fn get_u32(&self, k: &str) -> Result> { + fn get_u32(&self, k: &K) -> Result> { self.get_i64(k).map(|v| v.map(|v| v as u32)) } - fn get_str(&self, k: &str) -> Result>; - fn get_string(&self, k: &str) -> Result> { + fn get_str(&self, k: &K) -> Result>; + fn get_string(&self, k: &K) -> Result> { self.get_str(k).map(|v| v.map(From::from)) } - fn get_hash(&self, k: &str) -> Result>; - fn hash_iter<'a>(&'a self, k: &str) -> HashIter<'a>; - fn get_vec(&self, k: &str) -> Result>>; - fn str_vec_iter<'a>(&'a self, k: &str) -> Result>>; + fn get_hash(&self, k: &K) -> Result>; + fn hash_iter<'a>(&'a self, k: &K) -> HashIter<'a>; + fn get_vec(&self, k: &K) -> Result>>; + fn str_vec_iter<'a>(&'a self, k: &K) -> Result>>; } -impl GetVal for Hash { +impl GetVal for Hash { fn get_bool(&self, k: &str) -> Result> { match self.get(&k.to_yaml()) { None => Ok(None), @@ -230,3 +249,63 @@ impl GetVal for Hash { })) } } + +impl GetVal for Hash { + fn get_bool(&self, k: &Yaml) -> Result> { + match self.get(&k) { + None => Ok(None), + Some(v) => v + .bool() + .with_context(|| format!("Under key `{k:?}`")) + .map(Some), + } + } + fn get_i64(&self, k: &Yaml) -> Result> { + match self.get(&k) { + None => Ok(None), + Some(v) => v + .i64() + .with_context(|| format!("Under key `{k:?}`")) + .map(Some), + } + } + fn get_str(&self, k: &Yaml) -> Result> { + match self.get(&k) { + None => Ok(None), + Some(v) => v + .str() + .with_context(|| format!("Under key `{k:?}`")) + .map(Some), + } + } + fn get_hash(&self, k: &Yaml) -> Result> { + match self.get(&k) { + None => Ok(None), + Some(v) => v + .hash() + .with_context(|| format!("Under key `{k:?}`")) + .map(Some), + } + } + fn hash_iter<'a>(&'a self, k: &Yaml) -> HashIter<'a> { + HashIter::new(self.get(&k).and_then(Yaml::as_hash).map(|h| h.iter())) + } + fn get_vec(&self, k: &Yaml) -> Result>> { + match self.get(&k) { + None => Ok(None), + Some(v) => v + .vec() + .with_context(|| format!("Under key `{k:?}`")) + .map(Some), + } + } + fn str_vec_iter<'a>(&'a self, k: &Yaml) -> Result>> { + Ok(OptIter::new(match self.get(&k) { + None => None, + Some(y) if matches!(y, Yaml::String(_) | Yaml::Array(_)) => { + Some(OverStringIter(y, None)) + } + _ => return Err(anyhow!("`{k:?}` requires string value or array of strings")), + })) + } +}