rssn_advanced/dag/
node.rs1use core::fmt;
7
8use bincode_next::{Decode, Encode};
9
10use super::metadata::NodeMetadata;
11use super::symbol::SymbolKind;
12
13#[derive(Clone, Copy, PartialEq, Eq, Hash, Encode, Decode)]
18pub struct DagNodeId(pub(crate) u32);
19
20impl DagNodeId {
21 #[must_use]
23 pub const fn new(id: u32) -> Self {
24 Self(id)
25 }
26
27 #[must_use]
29 pub const fn value(self) -> u32 {
30 self.0
31 }
32
33 pub const NONE: Self = Self(u32::MAX);
35
36 #[must_use]
38 pub const fn index(self) -> usize {
39 self.0 as usize
40 }
41
42 #[must_use]
44 pub const fn is_none(self) -> bool {
45 self.0 == u32::MAX
46 }
47}
48
49impl fmt::Debug for DagNodeId {
50 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51 if self.is_none() {
52 f.write_str("DagNodeId(NONE)")
53 } else {
54 write!(f, "DagNodeId({})", self.0)
55 }
56 }
57}
58
59impl fmt::Display for DagNodeId {
60 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61 if self.is_none() {
62 f.write_str("∅")
63 } else {
64 write!(f, "#{}", self.0)
65 }
66 }
67}
68
69const INLINE_CHILDREN: usize = 4;
73
74#[derive(Debug, Clone, PartialEq, Eq, Hash, Encode, Decode)]
79pub enum ChildList {
80 Empty,
82 One([DagNodeId; 1]),
84 Two([DagNodeId; 2]),
86 Three([DagNodeId; 3]),
88 Four([DagNodeId; 4]),
90 Many(Vec<DagNodeId>),
92}
93
94impl ChildList {
95 #[must_use]
97 pub fn from_slice(ids: &[DagNodeId]) -> Self {
98 match ids.len() {
99 0 => Self::Empty,
100 1 => Self::One([ids[0]]),
101 2 => Self::Two([ids[0], ids[1]]),
102 3 => Self::Three([ids[0], ids[1], ids[2]]),
103 4 => Self::Four([ids[0], ids[1], ids[2], ids[3]]),
104 _ => Self::Many(ids.to_vec()),
105 }
106 }
107
108 #[must_use]
110 pub const fn len(&self) -> usize {
111 match self {
112 Self::Empty => 0,
113 Self::One(_) => 1,
114 Self::Two(_) => 2,
115 Self::Three(_) => 3,
116 Self::Four(_) => INLINE_CHILDREN,
117 Self::Many(v) => v.len(),
118 }
119 }
120
121 #[must_use]
123 pub const fn is_empty(&self) -> bool {
124 matches!(self, Self::Empty)
125 }
126
127 #[must_use]
129 pub fn as_slice(&self) -> &[DagNodeId] {
130 match self {
131 Self::Empty => &[],
132 Self::One(a) => a,
133 Self::Two(a) => a,
134 Self::Three(a) => a,
135 Self::Four(a) => a,
136 Self::Many(v) => v,
137 }
138 }
139
140 pub fn iter(&self) -> impl Iterator<Item = DagNodeId> + '_ {
142 self.as_slice().iter().copied()
143 }
144}
145
146#[derive(Debug, Clone, Encode, Decode)]
156pub struct DagNode {
157 pub kind: SymbolKind,
159 pub meta: NodeMetadata,
161 pub children: ChildList,
163}
164
165impl DagNode {
166 #[must_use]
168 pub const fn variable(kind: SymbolKind, meta: NodeMetadata) -> Self {
169 Self {
170 kind,
171 meta,
172 children: ChildList::Empty,
173 }
174 }
175
176 #[must_use]
178 pub const fn constant(val: f64, meta: NodeMetadata) -> Self {
179 Self {
180 kind: SymbolKind::Constant(val),
181 meta,
182 children: ChildList::Empty,
183 }
184 }
185
186 #[must_use]
188 pub const fn operator(kind: SymbolKind, meta: NodeMetadata, children: ChildList) -> Self {
189 Self {
190 kind,
191 meta,
192 children,
193 }
194 }
195
196 #[must_use]
198 pub const fn is_leaf(&self) -> bool {
199 self.children.is_empty()
200 }
201}
202
203#[cfg(test)]
204mod tests {
205 use super::*;
206 use crate::dag::metadata::{NodeFlags, NodeHash};
207 use crate::dag::symbol::{OpKind, SymbolId};
208
209 #[test]
210 fn child_list_inline() {
211 let ids = [DagNodeId(0), DagNodeId(1)];
212 let cl = ChildList::from_slice(&ids);
213 assert_eq!(cl.len(), 2);
214 assert_eq!(cl.as_slice(), &ids);
215 }
216
217 #[test]
218 fn child_list_many() {
219 let ids: Vec<DagNodeId> = (0..10).map(DagNodeId).collect();
220 let cl = ChildList::from_slice(&ids);
221 assert_eq!(cl.len(), 10);
222 assert_eq!(cl.as_slice(), &ids);
223 }
224
225 #[test]
226 fn variable_node() {
227 let meta = NodeMetadata::leaf(NodeHash(100));
228 let node = DagNode::variable(SymbolKind::Variable(SymbolId(0)), meta);
229 assert!(node.is_leaf());
230 assert!(!matches!(node.kind, SymbolKind::Constant(_)));
231 }
232
233 #[test]
234 fn constant_node() {
235 let meta = NodeMetadata::leaf(NodeHash(200));
236 let node = DagNode::constant(3.14, meta);
237 assert!(node.is_leaf());
238 assert!(matches!(node.kind, SymbolKind::Constant(v) if (v - 3.14).abs() < f64::EPSILON));
239 }
240
241 #[test]
242 fn operator_node() {
243 let meta = NodeMetadata::operator(NodeHash(300), NodeFlags::commutative_associative());
244 let children = ChildList::from_slice(&[DagNodeId(0), DagNodeId(1)]);
245 let node = DagNode::operator(SymbolKind::Operator(OpKind::Add), meta, children);
246 assert!(!node.is_leaf());
247 assert_eq!(node.children.len(), 2);
248 assert!(node.meta.flags.is_commutative());
249 }
250}