capability_skeleton/skeleton_node.rs
1// ---------------- [ File: capability-skeleton/src/skeleton_node.rs ]
2crate::ix!();
3
4impl Default for SkeletonNode {
5 fn default() -> Self {
6 Self::LeafHolder {
7 id: 0,
8 parent_id: None,
9 leaf_count: 0,
10 capstone: false,
11 name: String::new(),
12 original_key: String::new(),
13 ordering: None,
14 }
15 }
16}
17
18/// A single node in our skeleton, identified by:
19/// - **id** (u16)
20/// - optional **parent_id**
21/// - a mandatory **name**
22/// - an optional **original_key** (defaults to `name` if unset)
23/// - an optional **ordering** (sub-branch ordering)
24///
25/// We store it as an **enum** with three variants corresponding to how sub-branches (if any) are used:
26///
27/// 1) **Dispatch**: has child nodes but **no** leaves. Semantically, we pick exactly **one** branch
28/// among its children (like an enum).
29///
30/// 2) **Aggregate**: has child nodes but **no** leaves. Semantically, we include **all** branches
31/// simultaneously (like a struct).
32///
33/// 3) **LeafHolder**: has no child nodes but **does** store a `leaf_count` (the number of leaves),
34/// plus a `capstone` flag if relevant. No children are directly attached—only leaves.
35///
36/// The BFS or measurement logic can still do `node.child_ids()`—this returns `&[]` if it’s a `LeafHolder`
37/// (no children) or the actual child list if it’s `Dispatch` or `Aggregate`.
38/// Similarly, `node.leaf_count()` is zero for `Dispatch`/`Aggregate` and nonzero only for `LeafHolder`.
39#[derive(SaveLoad, Debug, Clone, PartialEq, Serialize, Deserialize)]
40#[serde(tag = "node_variant")] // to round-trip via TOML/JSON
41pub enum SkeletonNode {
42
43 /// **Dispatch**: no leaves, but has child nodes.
44 /// Semantically we pick exactly one sub-branch at runtime.
45 Dispatch {
46 /// Unique numeric ID for BFS, etc.
47 #[serde(default)]
48 id: u16,
49
50 /// Optional parent in numeric form
51 #[serde(default)]
52 parent_id: Option<u16>,
53
54 /// A list of child node IDs
55 #[serde(default)]
56 child_ids: Vec<u16>,
57
58 /// Required name. Must not be empty
59 #[serde(default)]
60 name: String,
61
62 /// Defaults to `name` if not explicitly set
63 #[serde(default)]
64 original_key: String,
65
66 /// Sub-branch ordering approach
67 #[serde(default)]
68 ordering: Option<SubBranchOrdering>,
69 },
70
71 /// **Aggregate**: has children but no leaves.
72 /// Semantically, we include **all** sub-branches simultaneously.
73 Aggregate {
74 /// Unique numeric ID
75 #[serde(default)]
76 id: u16,
77
78 /// Optional parent
79 #[serde(default)]
80 parent_id: Option<u16>,
81
82 /// Child node IDs
83 #[serde(default)]
84 child_ids: Vec<u16>,
85
86 /// Required name
87 #[serde(default)]
88 name: String,
89
90 /// Defaults to `name` if unset
91 #[serde(default)]
92 original_key: String,
93
94 /// Sub-branch ordering
95 #[serde(default)]
96 ordering: Option<SubBranchOrdering>,
97 },
98
99 /// **LeafHolder**: no children, but does store a `leaf_count` plus an optional `capstone`.
100 LeafHolder {
101 /// Numeric ID
102 #[serde(default)]
103 id: u16,
104
105 /// Optional parent
106 #[serde(default)]
107 parent_id: Option<u16>,
108
109 /// Number of leaves for BFS/measurement
110 #[serde(default)]
111 leaf_count: u16,
112
113 /// Whether this node is special or “capstone”
114 #[serde(default)]
115 capstone: bool,
116
117 /// Required name
118 #[serde(default)]
119 name: String,
120
121 /// Original key if it differs from name
122 #[serde(default)]
123 original_key: String,
124
125 /// Ordering (not always relevant for leaves, but we keep it for uniformity)
126 #[serde(default)]
127 ordering: Option<SubBranchOrdering>,
128 },
129}