diff options
author | Benedikt Peetz <benedikt.peetz@b-peetz.de> | 2024-05-09 11:10:36 +0200 |
---|---|---|
committer | Benedikt Peetz <benedikt.peetz@b-peetz.de> | 2024-05-09 11:10:36 +0200 |
commit | f46d845f6c1218b8e38725be1339de28dc15396e (patch) | |
tree | 66476a8c425a0383b9203dedc8fc9a7f1466e223 /sys/nixpkgs/pkgs/lf-make-map/src/mapping/map_tree | |
parent | feat(pkgs/lf-make-map): Ensure that it works (for a depth=1) (diff) | |
download | nixos-config-f46d845f6c1218b8e38725be1339de28dc15396e.tar.gz nixos-config-f46d845f6c1218b8e38725be1339de28dc15396e.zip |
feat(pkgs/lf-make-map): Support depths > 2
Diffstat (limited to 'sys/nixpkgs/pkgs/lf-make-map/src/mapping/map_tree')
3 files changed, 557 insertions, 0 deletions
diff --git a/sys/nixpkgs/pkgs/lf-make-map/src/mapping/map_tree/display.rs b/sys/nixpkgs/pkgs/lf-make-map/src/mapping/map_tree/display.rs new file mode 100644 index 00000000..778ade95 --- /dev/null +++ b/sys/nixpkgs/pkgs/lf-make-map/src/mapping/map_tree/display.rs @@ -0,0 +1,88 @@ +use std::fmt::Display; + +use crate::mapping::{ + map_tree::{Node, NodeValue}, + MapKey, +}; + +use super::MappingTree; + +impl Display for MappingTree { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn write_node( + f: &mut std::fmt::Formatter<'_>, + node: &Node, + indention: String, + location: Vec<MapKey>, + is_last: bool, + is_root: bool, + ) -> std::fmt::Result { + let node_value = match &node.value { + NodeValue::Parent { children: _ } => "<Parent>".to_owned(), + NodeValue::Child { path, extandable } => { + path.to_owned() + if *extandable { " [exten.]" } else { " [stop]" } + } + }; + + let new_idention = indention.clone() + + if is_root { + "" + } else { + match is_last { + true => " ", + false => "│ ", + } + }; + + let bullet = match is_last { + true => String::from("└── "), + false => String::from("├── "), + }; + + if is_root { + write!(f, ": {}\n", node_value)?; + } else { + write!( + f, + "{}{}\x1b[1;33m{}\x1b[0m: {}\n", + indention, + bullet, + MapKey::display(&location), + node_value, + )?; + }; + + match &node.value { + NodeValue::Parent { children } => { + let mut children_vec: Vec<(&MapKey, &Node)> = children.iter().collect(); + children_vec.sort_by(|(a, _), (b, _)| a.key.cmp(&b.key)); + + let mut counter = 1; + for (key, child) in &children_vec { + let mut new_location = location.clone(); + new_location.push((*key).to_owned()); + + write_node( + f, + child, + new_idention.clone(), + new_location.clone(), + counter == children_vec.len(), + false, + )?; + counter += 1; + } + } + NodeValue::Child { path: _, extandable: _ } => { + // Do nothing and stop the recursion + } + } + + Ok(()) + } + + write_node(f, &self.root, String::new(), vec![], false, true)?; + + Ok(()) + } +} diff --git a/sys/nixpkgs/pkgs/lf-make-map/src/mapping/map_tree/iterator.rs b/sys/nixpkgs/pkgs/lf-make-map/src/mapping/map_tree/iterator.rs new file mode 100644 index 00000000..33c27540 --- /dev/null +++ b/sys/nixpkgs/pkgs/lf-make-map/src/mapping/map_tree/iterator.rs @@ -0,0 +1,45 @@ +use crate::mapping::MapKey; + +use super::{MappingTree, Node, NodeValue}; + +pub struct MappingTreeIterator { + children: Vec<(Vec<MapKey>, String)>, +} + +impl MappingTreeIterator { + pub fn new(tree: &MappingTree) -> Self { + let children = extract_child(vec![], &tree.root); + + Self { children } + } +} + +fn extract_child(current_key: Vec<MapKey>, node: &Node) -> Vec<(Vec<MapKey>, String)> { + match &node.value { + NodeValue::Parent { children } => children + .iter() + .map(|(key, value)| { + let mut new_key = current_key.clone(); + new_key.push(key.to_owned()); + + extract_child(new_key, value) + }) + .flatten() + .collect(), + NodeValue::Child { path, extandable } => { + if *extandable { + vec![(current_key, path.to_string())] + } else { + vec![] + } + } + } +} + +impl Iterator for MappingTreeIterator { + type Item = (Vec<MapKey>, String); + + fn next(&mut self) -> Option<Self::Item> { + self.children.pop() + } +} diff --git a/sys/nixpkgs/pkgs/lf-make-map/src/mapping/map_tree/mod.rs b/sys/nixpkgs/pkgs/lf-make-map/src/mapping/map_tree/mod.rs new file mode 100644 index 00000000..44adc483 --- /dev/null +++ b/sys/nixpkgs/pkgs/lf-make-map/src/mapping/map_tree/mod.rs @@ -0,0 +1,424 @@ +use std::{collections::HashMap, mem}; + +use anyhow::{bail, Result}; +use log::debug; + +use self::iterator::MappingTreeIterator; + +use super::MapKey; + +pub mod display; +pub mod iterator; + +/// A prefix tree +#[derive(Debug)] +pub struct MappingTree { + root: Node, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum NodeValue { + Parent { children: HashMap<MapKey, Node> }, + Child { path: String, extandable: bool }, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Node { + value: NodeValue, +} + +impl MappingTree { + pub fn new() -> Self { + Self { + root: Node::new_parent(), + } + } + + pub fn root_node(&self) -> &Node { + &self.root + } + + pub fn iter(&self) -> MappingTreeIterator { + MappingTreeIterator::new(&self) + } + + /// Returns the node at the key, otherwise None + pub fn get(&self, key: &[MapKey]) -> Option<&Node> { + let mut current_node = &self.root; + for ch in key.iter() { + if let NodeValue::Parent { children } = ¤t_node.value { + current_node = children.get(&ch)? + } else { + return None; + } + } + + Some(current_node) + } + + /// Returns the node at the key, otherwise None. The node can be changed + pub fn get_mut(&mut self, key: &[MapKey]) -> Option<&mut Node> { + let mut current_node = &mut self.root; + for ch in key.iter() { + if let NodeValue::Parent { children } = &mut current_node.value { + current_node = children.get_mut(&ch)? + } else { + return None; + } + } + + Some(current_node) + } + + /// Returns the node at the key, otherwise the last node that matched. + pub fn try_get(&self, key: &[MapKey]) -> (&Node, Vec<MapKey>) { + let mut current_node = &self.root; + let mut current_key = vec![]; + + for ch in key.iter() { + if let NodeValue::Parent { children } = ¤t_node.value { + current_node = if let Some(node) = children.get(&ch) { + let (key, _value) = children + .get_key_value(&ch) + .expect("This exists, we checked"); + current_key.push(key.clone()); + + node + } else { + return (current_node, current_key); + }; + } else { + return (current_node, current_key); + } + } + + (current_node, current_key) + } + + pub fn include(&mut self, path: &str) -> Result<()> { + let associated_key = MapKey::new_ones_from_path(path, 1); + self.insert(&associated_key, path) + } + + pub fn insert(&mut self, key: &[MapKey], path: &str) -> Result<()> { + self.insert_node(key, Node::new_child(path.to_owned())) + } + + pub fn interleave(&mut self, key: &[MapKey], node: Node) -> Result<()> { + let want_to_be_parent = self.get_mut(&key).expect("This value exists"); + let (parent_value, _parent_children) = if let NodeValue::Parent { children } = node.value { + ( + NodeValue::Parent { + children: children.clone(), + }, + children, + ) + } else { + unreachable!("This value will be a parent") + }; + + let child_value = mem::replace(&mut want_to_be_parent.value, parent_value); + assert!(matches!( + child_value, + NodeValue::Child { + path: _, + extandable: _ + } + )); + + let child_value = if let NodeValue::Child { path, extandable } = child_value { + NodeValue::Child { + path, + extandable: false, + } + } else { + unreachable!("This is only a child value") + }; + + let child = Node { value: child_value }; + + let mut new_key = key.to_vec(); + new_key.push(MapKey { + key: '.', + part_path: ".".to_owned(), + resolution: 1, + }); + self.insert_node(&new_key, child)?; + Ok(()) + } + + pub fn replace_node(&mut self, key: &[MapKey], node: Node) -> Node { + let parent = self.get_mut(&key[..key.len() - 1]).expect("Must be some"); + + if let NodeValue::Parent { children } = &mut parent.value { + children + .insert(key[key.len() - 1].clone(), node) + .expect("This must exist, otherwise insert would have been used") + } else { + unreachable!("All parent nodes should be parent nodes"); + } + } + + pub fn insert_node(&mut self, key: &[MapKey], node: Node) -> Result<()> { + let (_node, found_key) = self.try_get(key).clone(); + + if found_key != key { + let needed_nodes_key = key + .strip_prefix(&found_key[..]) + .expect("The node's location is a prefix"); + + let needed_nodes_length = needed_nodes_key.iter().count(); + + let mut current_node = self + .get_mut(&found_key[..]) + .expect("This should always exists"); + let mut current_location = found_key.clone(); + let mut counter = 1; + + for ch in needed_nodes_key.iter() { + current_location.push(ch.to_owned()); + + let next_node = if counter == needed_nodes_length { + node.clone() + } else { + Node::new_parent() + }; + + current_node = match ¤t_node.value { + NodeValue::Parent { children } => { + assert_eq!(children.get(&ch), None); + + let children = + if let NodeValue::Parent { children } = &mut current_node.value { + children + } else { + unreachable!("This is a parent, we cheched") + }; + + children.insert(ch.to_owned(), next_node); + children.get_mut(&ch).expect("Was just inserted") + } + NodeValue::Child { + path, + extandable: _, + } => { + // A node that should be a parent was classified + // as child before: + // + // 1. Remove the child node and replace it with a parent one. + // 2. Add the child node to the parent node as child, but with a '.' as MapKey. + // 3. Add the original node also as child to the parent node. + + let mut children = HashMap::new(); + let move_child_node = Node::new_child(path.to_owned()); + + children.insert( + MapKey { + key: '.', + part_path: ".".to_owned(), + resolution: 1, + }, + move_child_node, + ); + children.insert(ch.to_owned(), next_node); + + current_node.value = NodeValue::Parent { children }; + + let children = + if let NodeValue::Parent { children } = &mut current_node.value { + children + } else { + unreachable!("We just inserted the parent value.") + }; + + children.get_mut(&ch).expect("Was just inserted") + } + }; + + counter += 1; + } + } else { + fn reduce_string(a: &str) -> Option<char> { + let first_char = a.chars().take(1).last().expect("Should contain one char"); + + if a.chars().all(|ch| ch == first_char) { + return Some(first_char); + } else { + return None; + } + } + fn check_subset(a: &str, b: &str) -> bool { + if a.len() > b.len() { + let a_prefix: String = a.chars().take(b.len()).collect(); + let a_suffix: String = a.chars().skip(b.len()).collect(); + + if a_prefix == b { + let clean_suffix = reduce_string(&a_suffix); + if let Some(ch) = clean_suffix { + ch == b.chars().last().expect("Will match") + } else { + false + } + } else { + false + } + } else if b.len() > a.len() { + let b_prefix: String = b.chars().take(a.len()).collect(); + let b_suffix: String = b.chars().skip(a.len()).collect(); + + if b_prefix == a { + let clean_suffix = reduce_string(&b_suffix); + if let Some(ch) = clean_suffix { + ch == a.chars().last().expect("Will match") + } else { + false + } + } else { + false + } + } else { + a == b + } + } + + // Another node was already inserted with the same key! + // So we simple increase the resolution of the other node and this node, until their + // keys are not the same anymore. + // This only includes the last segment of the `MapKey` + // + // 1. Change both keys, until they are not equal any more + // 2. Move the wrongly placed node to the new place. + // 3. Insert our node. + let mut foreign_key = vec![found_key.last().expect("This will exist").clone()]; + let mut our_key = vec![key.last().expect("This will exist").clone()]; + + debug!( + "'{}' ('{}') and '{}' ('{}') are the same, try to find a better combination!", + MapKey::display(&our_key), + our_key[0].part_path, + MapKey::display(&foreign_key), + foreign_key[0].part_path, + ); + + // The 'a' and 'b' stuff is here, to ensure that both returning None will not match + // this condition. + if reduce_string(&foreign_key[0].part_path).unwrap_or('a') + == reduce_string(&our_key[0].part_path).unwrap_or('b') + { + bail!( + "\ +The foreign_key ('{}', path_part: '{}' -> '{}') and our_key ('{}', path_part: '{}' -> '{}') \ +have an identical path_part (when duplicated chars are removed)! +I cannot extended them via incrementation. +Please rename the paths to fix this. + ", + MapKey::display(&foreign_key), + &foreign_key[0].part_path, + reduce_string(&foreign_key[0].part_path).expect("Is some here"), + MapKey::display(&our_key), + &our_key[0].part_path, + reduce_string(&our_key[0].part_path).expect("Is some here"), + ); + } + + if check_subset(&foreign_key[0].part_path, &our_key[0].part_path) { + bail!( + "\ +The foreign_key ('{}', path_part: '{}') and our_key ('{}', path_part: '{}') \ +are subsets of one another! +A discrimination through incrementation will not work! +Please rename the paths to fix this. + ", + MapKey::display(&foreign_key), + &foreign_key[0].part_path, + MapKey::display(&our_key), + &our_key[0].part_path, + ); + } + + while our_key == foreign_key { + our_key = our_key[0].increment(our_key[our_key.len() - 1].resolution + 1); + foreign_key = + foreign_key[0].increment(foreign_key[foreign_key.len() - 1].resolution + 1); + debug!( + "Now its: '{}' ('{}') and '{}' ('{}')", + MapKey::display(&our_key), + our_key[0].part_path, + MapKey::display(&foreign_key), + foreign_key[0].part_path, + ); + } + assert_eq!(our_key.len(), foreign_key.len()); + + debug!( + "Found a better one: '{}' ('{}') and '{}' ('{}')", + MapKey::display(&our_key), + our_key[0].part_path, + MapKey::display(&foreign_key), + foreign_key[0].part_path, + ); + + let parent = self + .get_mut(&found_key[..&found_key.len() - 1]) + .expect("This will exist"); + + if let NodeValue::Parent { children } = &mut parent.value { + if let NodeValue::Child { + path: _, + extandable: _, + } = children + .get(found_key.last().expect("Exists")) + .expect("This node also exists") + .value + { + let old = children + .remove(found_key.last().expect("This will exist")) + .expect("This will be there"); + + let full_foreign_key: Vec<_> = found_key + .clone() + .into_iter() + .rev() + .skip(1) + .rev() + .chain(foreign_key.clone().into_iter()) + .collect(); + self.insert_node(&full_foreign_key, old.clone())?; + } + + let full_our_key: Vec<_> = key + .to_vec() + .into_iter() + .rev() + .skip(1) + .rev() + .chain(our_key.clone().into_iter()) + .collect(); + + self.insert_node(&full_our_key, node.clone())?; + } else { + unreachable!("This node will be a parent"); + } + } + + Ok(()) + } +} + +impl Node { + pub fn new_child(path: String) -> Self { + Self { + value: NodeValue::Child { + path, + extandable: true, + }, + } + } + pub fn new_parent() -> Self { + Self { + value: NodeValue::Parent { + children: HashMap::new(), + }, + } + } +} |