about summary refs log tree commit diff stats
path: root/sys/nixpkgs/pkgs/lf-make-map/src/mapping/map_tree
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2024-05-09 11:10:36 +0200
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2024-05-09 11:10:36 +0200
commitf46d845f6c1218b8e38725be1339de28dc15396e (patch)
tree66476a8c425a0383b9203dedc8fc9a7f1466e223 /sys/nixpkgs/pkgs/lf-make-map/src/mapping/map_tree
parentfeat(pkgs/lf-make-map): Ensure that it works (for a depth=1) (diff)
downloadnixos-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')
-rw-r--r--sys/nixpkgs/pkgs/lf-make-map/src/mapping/map_tree/display.rs88
-rw-r--r--sys/nixpkgs/pkgs/lf-make-map/src/mapping/map_tree/iterator.rs45
-rw-r--r--sys/nixpkgs/pkgs/lf-make-map/src/mapping/map_tree/mod.rs424
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 } = &current_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 } = &current_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 &current_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(),
+            },
+        }
+    }
+}