1#![forbid(unsafe_code)]
2use std::collections::HashSet;
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
22pub struct NodeId(usize);
23
24impl NodeId {
25 #[must_use]
26 pub const fn new(value: usize) -> Self {
27 Self(value)
28 }
29
30 #[must_use]
31 pub const fn value(&self) -> usize {
32 self.0
33 }
34}
35
36#[must_use]
37pub fn node_ids(count: usize) -> Vec<NodeId> {
38 (0..count).map(NodeId::new).collect()
39}
40
41#[must_use]
42pub fn contains_node(nodes: &[NodeId], node: NodeId) -> bool {
43 nodes.contains(&node)
44}
45
46#[must_use]
47pub fn unique_nodes(nodes: &[NodeId]) -> Vec<NodeId> {
48 let mut seen = HashSet::with_capacity(nodes.len());
49 let mut unique = Vec::with_capacity(nodes.len());
50
51 for &node in nodes {
52 if seen.insert(node) {
53 unique.push(node);
54 }
55 }
56
57 unique
58}
59
60#[cfg(test)]
61mod tests {
62 use super::{contains_node, node_ids, unique_nodes, NodeId};
63
64 #[test]
65 fn creates_node_ids() {
66 let nodes = node_ids(4);
67
68 assert_eq!(
69 nodes,
70 vec![
71 NodeId::new(0),
72 NodeId::new(1),
73 NodeId::new(2),
74 NodeId::new(3)
75 ]
76 );
77 assert_eq!(NodeId::new(7).value(), 7);
78 }
79
80 #[test]
81 fn checks_containment() {
82 let nodes = [NodeId::new(1), NodeId::new(3)];
83
84 assert!(contains_node(&nodes, NodeId::new(3)));
85 assert!(!contains_node(&nodes, NodeId::new(2)));
86 }
87
88 #[test]
89 fn deduplicates_nodes_while_preserving_first_occurrence_order() {
90 let unique = unique_nodes(&[
91 NodeId::new(2),
92 NodeId::new(1),
93 NodeId::new(2),
94 NodeId::new(1),
95 NodeId::new(3),
96 ]);
97
98 assert_eq!(unique, vec![NodeId::new(2), NodeId::new(1), NodeId::new(3)]);
99 }
100}