wolf-graph 0.1.0

Data structures and algorithms for working with graphs with reference or value semantics.
Documentation
use std::collections::BTreeSet;

use crate::{EdgeID, NodeID};

/// A set of node identifiers.
pub type Nodes = BTreeSet<NodeID>;

/// A set of edge identifiers.
pub type Edges = BTreeSet<EdgeID>;

/// An identifier for either a node or an edge.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ElementID {
    Node(NodeID),
    Edge(EdgeID),
}

/// A set of elment (node and edge) identifiers.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Elements {
    pub nodes: Nodes,
    pub edges: Edges,
}

impl Elements {
    pub fn new(nodes: Nodes, edges: Edges) -> Self {
        Self { nodes, edges }
    }

    pub fn from_nodes(nodes: Nodes) -> Self {
        Self::new(nodes, Edges::new())
    }

    pub fn from_edges(edges: Edges) -> Self {
        Self::new(Nodes::new(), edges)
    }

    // Equivalent to Swift's `ExpressibleByArrayLiteral`
    pub fn from_elements(elements: &[ElementID]) -> Self {
        let nodes = elements
            .iter()
            .filter_map(|element| match element {
                ElementID::Node(node) => Some(node),
                _ => None,
            })
            .cloned()
            .collect();
        let edges = elements
            .iter()
            .filter_map(|element| match element {
                ElementID::Edge(edge) => Some(edge),
                _ => None,
            })
            .cloned()
            .collect();
        Self::new(nodes, edges)
    }
}

impl Default for Elements {
    fn default() -> Self {
        Self::new(Nodes::new(), Edges::new())
    }
}

impl From<Nodes> for Elements {
    fn from(nodes: Nodes) -> Self {
        Self::from_nodes(nodes)
    }
}

impl From<Edges> for Elements {
    fn from(edges: Edges) -> Self {
        Self::from_edges(edges)
    }
}

impl From<(Nodes, Edges)> for Elements {
    fn from((nodes, edges): (Nodes, Edges)) -> Self {
        Self::new(nodes, edges)
    }
}

impl From<&Elements> for Elements {
    fn from(elements: &Elements) -> Self {
        elements.clone()
    }
}

impl Elements {
    /// Returns `true` if the set contains an element equal to the value.
    pub fn contains(&self, member: &ElementID) -> bool {
        match member {
            ElementID::Node(node) => self.nodes.contains(node),
            ElementID::Edge(edge) => self.edges.contains(edge),
        }
    }

    /// Inserts a value into the set, returning `true` if the value was not present in the set.
    pub fn insert(&mut self, new_member: ElementID) -> bool {
        match new_member {
            ElementID::Node(node) => self.nodes.insert(node),
            ElementID::Edge(edge) => self.edges.insert(edge),
        }
    }

    /// Inserts all the elements from `other` into `self`.
    pub fn insert_all(&mut self, other: &Elements) {
        self.nodes.extend(other.nodes.iter().cloned());
        self.edges.extend(other.edges.iter().cloned());
    }

    /// Removes a value from the set, returning the value if it was present in the set.
    pub fn remove(&mut self, member: &ElementID) -> bool {
        match member {
            ElementID::Node(node) => self.nodes.remove(node),
            ElementID::Edge(edge) => self.edges.remove(edge),
        }
    }

    /// Removes all the elements in `other` from `self`.
    pub fn remove_all(&mut self, other: &Elements) {
        self.nodes = self.nodes.difference(&other.nodes).cloned().collect();
        self.edges = self.edges.difference(&other.edges).cloned().collect();
    }

    /// Returns the elements representing the union, i.e., all the elements in `self` or `other`.
    pub fn union(&self, other: &Elements) -> Elements {
        Elements::new(
            self.nodes.union(&other.nodes).cloned().collect(),
            self.edges.union(&other.edges).cloned().collect()
        )
    }

    /// Returns the elements representing the intersection, i.e., all the elements in both `self` and `other`.
    pub fn intersection(&self, other: &Elements) -> Elements {
        Elements::new(
            self.nodes.intersection(&other.nodes).cloned().collect(),
            self.edges.intersection(&other.edges).cloned().collect()
        )
    }

    /// Returns the elements representing the difference, i.e., all the elements in `self` but not in `other`.
    pub fn difference(&self, other: &Elements) -> Elements {
        Elements::new(
            self.nodes.difference(&other.nodes).cloned().collect(),
            self.edges.difference(&other.edges).cloned().collect()
        )
    }

    /// Returns the elements representing the symmetric difference, i.e., all the elements in `self` or `other`, but not in both.
    pub fn symmetric_difference(&self, other: &Elements) -> Elements {
        Elements::new(
            self.nodes.symmetric_difference(&other.nodes).cloned().collect(),
            self.edges.symmetric_difference(&other.edges).cloned().collect()
        )
    }

    /// Updates `self` with the union of `self` and `other`.
    pub fn form_union(&mut self, other: &Elements) {
        self.nodes = self.nodes.union(&other.nodes).cloned().collect();
        self.edges = self.edges.union(&other.edges).cloned().collect();
    }

    /// Updates `self` with the intersection of `self` and `other`.
    pub fn form_intersection(&mut self, other: &Elements) {
        self.nodes = self.nodes.intersection(&other.nodes).cloned().collect();
        self.edges = self.edges.intersection(&other.edges).cloned().collect();
    }

    /// Updates `self` with the difference of `self` and `other`.
    pub fn form_difference(&mut self, other: &Elements) {
        self.nodes = self.nodes.difference(&other.nodes).cloned().collect();
        self.edges = self.edges.difference(&other.edges).cloned().collect();
    }

    /// Updates `self` with the symmetric difference of `self` and `other`.
    pub fn form_symmetric_difference(&mut self, other: &Elements) {
        self.nodes = self.nodes.symmetric_difference
            (&other.nodes).cloned().collect();
        self.edges = self.edges.symmetric_difference
            (&other.edges).cloned().collect();
    }

    /// Returns true if `self` has no elements in common with `other`. This is equivalent to checking for an empty intersection.
    pub fn is_disjoint(&self, other: &Elements) -> bool {
        self.nodes.is_disjoint(&other.nodes) && self.edges.is_disjoint(&other.edges)
    }

    /// Returns true if `self` is a subset of `other`, i.e., `other` contains at least all the elements in `self`.
    pub fn is_subset(&self, other: &Elements) -> bool {
        self.nodes.is_subset(&other.nodes) && self.edges.is_subset(&other.edges)
    }

    /// Returns true if `self` is a superset of `other`, i.e., `self` contains at least all the elements in `other`.
    pub fn is_superset(&self, other: &Elements) -> bool {
        self.nodes.is_superset(&other.nodes) && self.edges.is_superset(&other.edges)
    }

    /// Returns the number of elements in `self`.
    pub fn len(&self) -> usize {
        self.nodes.len() + self.edges.len()
    }

    /// Returns `true` if the set contains no elements.
    pub fn is_empty(&self) -> bool {
        self.nodes.is_empty() && self.edges.is_empty()
    }

    /// Removes all elements from the set.
    pub fn clear(&mut self) {
        self.nodes.clear();
        self.edges.clear();
    }

    /// Retains only the elements specified by the predicate.
    pub fn retain<F>(&mut self, mut f: F)
    where
        F: FnMut(&ElementID) -> bool,
    {
        self.nodes.retain(|node| f(&ElementID::Node(node.clone())));
        self.edges.retain(|edge| f(&ElementID::Edge(edge.clone())));
    }
}