#![forbid(unsafe_code)]
#![doc = include_str!("../README.md")]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct CoxeterNode {
index: usize,
}
impl CoxeterNode {
#[must_use]
pub const fn new(index: usize) -> Self {
Self { index }
}
#[must_use]
pub const fn index(self) -> usize {
self.index
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CoxeterEdge {
start: usize,
end: usize,
order: Option<usize>,
}
impl CoxeterEdge {
#[must_use]
pub const fn new(start: usize, end: usize, order: Option<usize>) -> Option<Self> {
if start == end {
return None;
}
if let Some(order) = order
&& order < 3
{
return None;
}
Some(Self { start, end, order })
}
#[must_use]
pub const fn endpoints(self) -> (usize, usize) {
(self.start, self.end)
}
#[must_use]
pub const fn order(self) -> Option<usize> {
self.order
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CoxeterDiagram {
nodes: Vec<CoxeterNode>,
edges: Vec<CoxeterEdge>,
}
impl CoxeterDiagram {
#[must_use]
pub fn new(nodes: Vec<CoxeterNode>, edges: Vec<CoxeterEdge>) -> Option<Self> {
if edges.iter().all(|edge| {
nodes.iter().any(|node| node.index() == edge.start)
&& nodes.iter().any(|node| node.index() == edge.end)
}) {
Some(Self { nodes, edges })
} else {
None
}
}
#[must_use]
pub fn nodes(&self) -> &[CoxeterNode] {
&self.nodes
}
#[must_use]
pub fn edges(&self) -> &[CoxeterEdge] {
&self.edges
}
#[must_use]
pub fn node_count(&self) -> usize {
self.nodes.len()
}
#[must_use]
pub fn edge_count(&self) -> usize {
self.edges.len()
}
}
#[cfg(test)]
mod tests {
use super::{CoxeterDiagram, CoxeterEdge, CoxeterNode};
#[test]
fn validates_coxeter_diagrams() {
let nodes = vec![CoxeterNode::new(0), CoxeterNode::new(1)];
let edge = CoxeterEdge::new(0, 1, Some(3)).expect("valid edge");
let diagram = CoxeterDiagram::new(nodes, vec![edge]).expect("valid diagram");
assert_eq!(diagram.node_count(), 2);
assert_eq!(diagram.edge_count(), 1);
assert_eq!(edge.endpoints(), (0, 1));
assert_eq!(CoxeterEdge::new(0, 0, None), None);
}
}