From 008457432ac115c29617946cc141de203e8a6dc4 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 | 37 +++++++++++++-- src/patch/peripheral.rs | 8 ++-- src/patch/register.rs | 2 +- src/patch/yaml_ext.rs | 103 +++++++++++++++++++++++++++++++++++----- 5 files changed, 129 insertions(+), 23 deletions(-) diff --git a/src/patch/device.rs b/src/patch/device.rs index c06da2a..555616f 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()?, config) diff --git a/src/patch/mod.rs b/src/patch/mod.rs index ef4121b..6076077 100644 --- a/src/patch/mod.rs +++ b/src/patch/mod.rs @@ -194,11 +194,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) => { @@ -208,7 +208,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"); } } _ => {} @@ -223,11 +223,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"); } _ => {} }, @@ -235,6 +235,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 149f95e..0e7aa29 100644 --- a/src/patch/peripheral.rs +++ b/src/patch/peripheral.rs @@ -330,7 +330,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()?, config) .with_context(|| format!("According to `{rspec}`"))?; @@ -353,7 +353,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()?, config) .with_context(|| format!("According to `{cspec}`"))?; @@ -850,7 +850,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()?, config) .with_context(|| format!("According to `{cspec}`"))?; @@ -859,7 +859,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()?, config) .with_context(|| format!("According to `{rspec}`"))?; diff --git a/src/patch/register.rs b/src/patch/register.rs index 74cf2cd..5c9efbe 100644 --- a/src/patch/register.rs +++ b/src/patch/register.rs @@ -182,7 +182,7 @@ impl RegisterExt for Register { // Handle fields if config.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, config) .with_context(|| format!("Processing field matched to `{fspec}`"))?; diff --git a/src/patch/yaml_ext.rs b/src/patch/yaml_ext.rs index 6771e3e..b8378b0 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")), + })) + } +}