Skip to main content

use_coxeter/
lib.rs

1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4/// A node in a Coxeter diagram.
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
6pub struct CoxeterNode {
7    index: usize,
8}
9
10impl CoxeterNode {
11    /// Creates a node with an index.
12    #[must_use]
13    pub const fn new(index: usize) -> Self {
14        Self { index }
15    }
16
17    /// Returns the node index.
18    #[must_use]
19    pub const fn index(self) -> usize {
20        self.index
21    }
22}
23
24/// An edge in a Coxeter diagram.
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub struct CoxeterEdge {
27    start: usize,
28    end: usize,
29    order: Option<usize>,
30}
31
32impl CoxeterEdge {
33    /// Creates an edge between distinct nodes with an optional Coxeter order of at least three.
34    #[must_use]
35    pub const fn new(start: usize, end: usize, order: Option<usize>) -> Option<Self> {
36        if start == end {
37            return None;
38        }
39
40        if let Some(order) = order
41            && order < 3
42        {
43            return None;
44        }
45
46        Some(Self { start, end, order })
47    }
48
49    /// Returns the edge endpoints.
50    #[must_use]
51    pub const fn endpoints(self) -> (usize, usize) {
52        (self.start, self.end)
53    }
54
55    /// Returns the optional Coxeter order label.
56    #[must_use]
57    pub const fn order(self) -> Option<usize> {
58        self.order
59    }
60}
61
62/// A Coxeter diagram record.
63#[derive(Debug, Clone, PartialEq, Eq)]
64pub struct CoxeterDiagram {
65    nodes: Vec<CoxeterNode>,
66    edges: Vec<CoxeterEdge>,
67}
68
69impl CoxeterDiagram {
70    /// Creates a diagram whose edge endpoints reference existing node indices.
71    #[must_use]
72    pub fn new(nodes: Vec<CoxeterNode>, edges: Vec<CoxeterEdge>) -> Option<Self> {
73        if edges.iter().all(|edge| {
74            nodes.iter().any(|node| node.index() == edge.start)
75                && nodes.iter().any(|node| node.index() == edge.end)
76        }) {
77            Some(Self { nodes, edges })
78        } else {
79            None
80        }
81    }
82
83    /// Returns the nodes.
84    #[must_use]
85    pub fn nodes(&self) -> &[CoxeterNode] {
86        &self.nodes
87    }
88
89    /// Returns the edges.
90    #[must_use]
91    pub fn edges(&self) -> &[CoxeterEdge] {
92        &self.edges
93    }
94
95    /// Returns the node count.
96    #[must_use]
97    pub fn node_count(&self) -> usize {
98        self.nodes.len()
99    }
100
101    /// Returns the edge count.
102    #[must_use]
103    pub fn edge_count(&self) -> usize {
104        self.edges.len()
105    }
106}
107
108#[cfg(test)]
109mod tests {
110    use super::{CoxeterDiagram, CoxeterEdge, CoxeterNode};
111
112    #[test]
113    fn validates_coxeter_diagrams() {
114        let nodes = vec![CoxeterNode::new(0), CoxeterNode::new(1)];
115        let edge = CoxeterEdge::new(0, 1, Some(3)).expect("valid edge");
116        let diagram = CoxeterDiagram::new(nodes, vec![edge]).expect("valid diagram");
117
118        assert_eq!(diagram.node_count(), 2);
119        assert_eq!(diagram.edge_count(), 1);
120        assert_eq!(edge.endpoints(), (0, 1));
121        assert_eq!(CoxeterEdge::new(0, 0, None), None);
122    }
123}