viva_genapi/nodes.rs
1//! Node type definitions for the GenApi node system.
2
3use std::cell::RefCell;
4use std::collections::HashMap;
5
6use viva_genapi_xml::{AccessMode, Addressing, BitField, ByteOrder, EnumEntryDecl, FloatEncoding};
7pub use viva_genapi_xml::{NodeMeta, PredicateRefs, Representation, SkOutput, Visibility};
8
9use crate::swissknife::AstNode;
10
11/// Node kinds supported by the Tier-1 subset.
12#[derive(Debug)]
13pub enum Node {
14 /// Signed integer feature stored in a fixed-width register block.
15 Integer(IntegerNode),
16 /// Floating point feature with optional scale/offset conversion.
17 Float(FloatNode),
18 /// Enumeration feature mapping integers to symbolic names.
19 Enum(EnumNode),
20 /// Boolean feature represented as an integer register.
21 Boolean(BooleanNode),
22 /// Command feature triggering a device-side action when written.
23 Command(CommandNode),
24 /// Category organising related features.
25 Category(CategoryNode),
26 /// SwissKnife expression producing a computed value.
27 SwissKnife(SkNode),
28 /// Converter transforming raw values to/from float values via formulas.
29 Converter(ConverterNode),
30 /// IntConverter transforming raw values to/from integer values via formulas.
31 IntConverter(IntConverterNode),
32 /// StringReg for string-typed register access.
33 String(StringNode),
34}
35
36impl Node {
37 /// Return the GenICam node type name (e.g. "Integer", "Float", "Enumeration").
38 pub fn kind_name(&self) -> &'static str {
39 match self {
40 Node::Integer(_) => "Integer",
41 Node::Float(_) => "Float",
42 Node::Enum(_) => "Enumeration",
43 Node::Boolean(_) => "Boolean",
44 Node::Command(_) => "Command",
45 Node::Category(_) => "Category",
46 Node::SwissKnife(_) => "SwissKnife",
47 Node::Converter(_) => "Converter",
48 Node::IntConverter(_) => "IntConverter",
49 Node::String(_) => "StringReg",
50 }
51 }
52
53 /// Return the access mode of the node, if applicable.
54 pub fn access_mode(&self) -> Option<viva_genapi_xml::AccessMode> {
55 match self {
56 Node::Integer(n) => Some(n.access),
57 Node::Float(n) => Some(n.access),
58 Node::Enum(n) => Some(n.access),
59 Node::Boolean(n) => Some(n.access),
60 Node::Command(_) => Some(viva_genapi_xml::AccessMode::WO),
61 Node::Category(_) => None,
62 Node::SwissKnife(_) => Some(viva_genapi_xml::AccessMode::RO),
63 Node::Converter(_) => Some(viva_genapi_xml::AccessMode::RO),
64 Node::IntConverter(_) => Some(viva_genapi_xml::AccessMode::RO),
65 Node::String(n) => Some(n.access),
66 }
67 }
68
69 /// Return the node name.
70 pub fn name(&self) -> &str {
71 match self {
72 Node::Integer(n) => &n.name,
73 Node::Float(n) => &n.name,
74 Node::Enum(n) => &n.name,
75 Node::Boolean(n) => &n.name,
76 Node::Command(n) => &n.name,
77 Node::Category(n) => &n.name,
78 Node::SwissKnife(n) => &n.name,
79 Node::Converter(n) => &n.name,
80 Node::IntConverter(n) => &n.name,
81 Node::String(n) => &n.name,
82 }
83 }
84
85 /// Return the shared metadata for this node.
86 pub fn meta(&self) -> &NodeMeta {
87 match self {
88 Node::Integer(n) => &n.meta,
89 Node::Float(n) => &n.meta,
90 Node::Enum(n) => &n.meta,
91 Node::Boolean(n) => &n.meta,
92 Node::Command(n) => &n.meta,
93 Node::Category(n) => &n.meta,
94 Node::SwissKnife(n) => &n.meta,
95 Node::Converter(n) => &n.meta,
96 Node::IntConverter(n) => &n.meta,
97 Node::String(n) => &n.meta,
98 }
99 }
100
101 /// Return the visibility level of this node.
102 pub fn visibility(&self) -> Visibility {
103 self.meta().visibility
104 }
105
106 /// Return the description of this node, if any.
107 pub fn description(&self) -> Option<&str> {
108 self.meta().description.as_deref()
109 }
110
111 /// Return the tooltip of this node, if any.
112 pub fn tooltip(&self) -> Option<&str> {
113 self.meta().tooltip.as_deref()
114 }
115
116 /// Return the display name of this node, if any.
117 pub fn display_name(&self) -> Option<&str> {
118 self.meta().display_name.as_deref()
119 }
120
121 /// Return the recommended representation for this node, if any.
122 pub fn representation(&self) -> Option<Representation> {
123 self.meta().representation
124 }
125
126 /// Return the predicate references (`pIsImplemented`, `pIsAvailable`,
127 /// `pIsLocked`) declared on this node.
128 pub fn predicates(&self) -> &PredicateRefs {
129 match self {
130 Node::Integer(n) => &n.predicates,
131 Node::Float(n) => &n.predicates,
132 Node::Enum(n) => &n.predicates,
133 Node::Boolean(n) => &n.predicates,
134 Node::Command(n) => &n.predicates,
135 Node::Category(n) => &n.predicates,
136 Node::SwissKnife(n) => &n.predicates,
137 Node::Converter(n) => &n.predicates,
138 Node::IntConverter(n) => &n.predicates,
139 Node::String(n) => &n.predicates,
140 }
141 }
142
143 pub(crate) fn invalidate_cache(&self) {
144 match self {
145 Node::Integer(node) => {
146 node.cache.replace(None);
147 node.raw_cache.replace(None);
148 }
149 Node::Float(node) => {
150 node.cache.replace(None);
151 }
152 Node::Enum(node) => node.invalidate(),
153 Node::Boolean(node) => {
154 node.cache.replace(None);
155 node.raw_cache.replace(None);
156 }
157 Node::SwissKnife(node) => {
158 node.cache.replace(None);
159 }
160 Node::Converter(node) => {
161 node.cache.replace(None);
162 }
163 Node::IntConverter(node) => {
164 node.cache.replace(None);
165 }
166 Node::String(node) => {
167 node.cache.replace(None);
168 }
169 Node::Command(_) | Node::Category(_) => {}
170 }
171 }
172}
173
174/// Integer feature metadata extracted from the XML description.
175#[derive(Debug)]
176pub struct IntegerNode {
177 /// Unique feature name.
178 pub name: String,
179 /// Shared metadata (visibility, description, tooltip, etc.).
180 pub meta: NodeMeta,
181 /// Register addressing metadata (absent when delegated via `pvalue`).
182 pub addressing: Option<Addressing>,
183 /// Nominal register length in bytes.
184 pub len: u32,
185 /// Declared access rights.
186 pub access: AccessMode,
187 /// Minimum permitted user value.
188 pub min: i64,
189 /// Maximum permitted user value.
190 pub max: i64,
191 /// Optional increment step the value must respect.
192 pub inc: Option<i64>,
193 /// Optional engineering unit such as "us".
194 pub unit: Option<String>,
195 /// Optional bitfield metadata restricting active bits.
196 pub bitfield: Option<BitField>,
197 /// Selector nodes controlling the visibility of this node.
198 pub selectors: Vec<String>,
199 /// Selector gating rules in the form `(selector, allowed values)`.
200 pub selected_if: Vec<(String, Vec<String>)>,
201 /// Node providing the value (delegates read/write).
202 pub pvalue: Option<String>,
203 /// Node providing the dynamic maximum.
204 pub p_max: Option<String>,
205 /// Node providing the dynamic minimum.
206 pub p_min: Option<String>,
207 /// Static value for constant nodes.
208 pub value: Option<i64>,
209 /// Predicate refs gating implementation / availability / lock state.
210 pub predicates: PredicateRefs,
211 pub(crate) cache: RefCell<Option<i64>>,
212 pub(crate) raw_cache: RefCell<Option<Vec<u8>>>,
213}
214
215/// Floating point feature metadata.
216#[derive(Debug)]
217pub struct FloatNode {
218 pub name: String,
219 /// Shared metadata (visibility, description, tooltip, etc.).
220 pub meta: NodeMeta,
221 /// Register addressing metadata (absent when delegated via `pvalue`).
222 pub addressing: Option<Addressing>,
223 pub access: AccessMode,
224 pub min: f64,
225 pub max: f64,
226 pub unit: Option<String>,
227 /// Optional rational scale `(numerator, denominator)` applied to the raw value.
228 pub scale: Option<(i64, i64)>,
229 /// Optional offset added after scaling.
230 pub offset: Option<f64>,
231 pub selectors: Vec<String>,
232 pub selected_if: Vec<(String, Vec<String>)>,
233 /// Node providing the value (delegates read/write).
234 pub pvalue: Option<String>,
235 /// How the register payload is encoded (IEEE 754 or scaled integer).
236 pub encoding: FloatEncoding,
237 /// Byte order of the register payload.
238 pub byte_order: ByteOrder,
239 /// Predicate refs gating implementation / availability / lock state.
240 pub predicates: PredicateRefs,
241 pub(crate) cache: RefCell<Option<f64>>,
242}
243
244/// Enumeration feature metadata and mapping tables.
245#[derive(Debug)]
246pub struct EnumNode {
247 pub name: String,
248 /// Shared metadata (visibility, description, tooltip, etc.).
249 pub meta: NodeMeta,
250 /// Register addressing metadata (absent when delegated via `pvalue`).
251 pub addressing: Option<Addressing>,
252 pub access: AccessMode,
253 /// Node providing the integer value (delegates register read/write).
254 pub pvalue: Option<String>,
255 pub entries: Vec<EnumEntryDecl>,
256 pub default: Option<String>,
257 pub selectors: Vec<String>,
258 pub selected_if: Vec<(String, Vec<String>)>,
259 pub providers: Vec<String>,
260 /// Predicate refs gating implementation / availability / lock state.
261 pub predicates: PredicateRefs,
262 pub(crate) value_cache: RefCell<Option<String>>,
263 pub(crate) mapping_cache: RefCell<Option<EnumMapping>>,
264}
265
266#[derive(Debug, Clone)]
267pub(crate) struct EnumMapping {
268 pub by_value: HashMap<i64, String>,
269 pub by_name: HashMap<String, i64>,
270}
271
272impl EnumNode {
273 pub(crate) fn invalidate(&self) {
274 self.value_cache.replace(None);
275 self.mapping_cache.replace(None);
276 }
277}
278
279/// Boolean feature metadata.
280#[derive(Debug)]
281pub struct BooleanNode {
282 pub name: String,
283 /// Shared metadata (visibility, description, tooltip, etc.).
284 pub meta: NodeMeta,
285 /// Register addressing metadata (absent when delegated via `pvalue`).
286 pub addressing: Option<Addressing>,
287 pub len: u32,
288 pub access: AccessMode,
289 /// Optional bitfield (absent for pValue-backed booleans).
290 pub bitfield: Option<BitField>,
291 pub selectors: Vec<String>,
292 pub selected_if: Vec<(String, Vec<String>)>,
293 /// Node providing the value (delegates read/write).
294 pub pvalue: Option<String>,
295 /// On value for pValue-backed booleans.
296 pub on_value: Option<i64>,
297 /// Off value for pValue-backed booleans.
298 pub off_value: Option<i64>,
299 /// Predicate refs gating implementation / availability / lock state.
300 pub predicates: PredicateRefs,
301 pub(crate) cache: RefCell<Option<bool>>,
302 pub(crate) raw_cache: RefCell<Option<Vec<u8>>>,
303}
304
305/// SwissKnife node evaluating an arithmetic expression referencing other nodes.
306///
307/// Integer outputs follow round-to-nearest semantics with ties towards zero
308/// after the expression has been evaluated as `f64`.
309#[derive(Debug)]
310pub struct SkNode {
311 /// Unique feature name.
312 pub name: String,
313 /// Shared metadata (visibility, description, tooltip, etc.).
314 pub meta: NodeMeta,
315 /// Desired output type as declared in the XML.
316 pub output: SkOutput,
317 /// Parsed expression AST.
318 pub ast: AstNode,
319 /// Mapping of variable identifiers to provider node names.
320 pub vars: Vec<(String, String)>,
321 /// Predicate refs gating implementation / availability.
322 pub predicates: PredicateRefs,
323 /// Cached value alongside the generation it was computed in.
324 pub cache: RefCell<Option<(f64, u64)>>,
325}
326
327/// Command feature metadata.
328#[derive(Debug)]
329pub struct CommandNode {
330 pub name: String,
331 /// Shared metadata (visibility, description, tooltip, etc.).
332 pub meta: NodeMeta,
333 /// Fixed register address (absent when delegated via `pvalue`).
334 pub address: Option<u64>,
335 pub len: u32,
336 /// Node providing the command register.
337 pub pvalue: Option<String>,
338 /// Value to write when executing the command.
339 pub command_value: Option<i64>,
340 /// Predicate refs gating implementation / availability / lock state.
341 pub predicates: PredicateRefs,
342}
343
344/// Category node describing child feature names.
345#[derive(Debug)]
346pub struct CategoryNode {
347 pub name: String,
348 /// Shared metadata (visibility, description, tooltip, etc.).
349 pub meta: NodeMeta,
350 pub children: Vec<String>,
351 /// Predicate refs gating implementation / availability.
352 pub predicates: PredicateRefs,
353}
354
355/// Converter node transforming raw values to/from float values via formulas.
356///
357/// Converters use two formulas:
358/// - `formula_to`: converts from raw register value to user-facing float (reading)
359/// - `formula_from`: converts from user-facing float to raw register value (writing)
360#[derive(Debug)]
361pub struct ConverterNode {
362 /// Unique feature name.
363 pub name: String,
364 /// Shared metadata (visibility, description, tooltip, etc.).
365 pub meta: NodeMeta,
366 /// Name of the node providing the raw register value.
367 pub p_value: String,
368 /// Parsed AST for the formula converting raw → user value.
369 pub ast_to: AstNode,
370 /// Parsed AST for the formula converting user → raw value.
371 pub ast_from: AstNode,
372 /// Variable mappings for formula_to (reading).
373 pub vars_to: Vec<(String, String)>,
374 /// Variable mappings for formula_from (writing).
375 pub vars_from: Vec<(String, String)>,
376 /// Optional engineering unit.
377 pub unit: Option<String>,
378 /// Desired output type.
379 pub output: SkOutput,
380 /// Predicate refs gating implementation / availability / lock state.
381 pub predicates: PredicateRefs,
382 /// Cached user-facing value alongside the generation it was computed in.
383 pub cache: RefCell<Option<(f64, u64)>>,
384}
385
386/// IntConverter node transforming raw values to/from integer values via formulas.
387#[derive(Debug)]
388pub struct IntConverterNode {
389 /// Unique feature name.
390 pub name: String,
391 /// Shared metadata (visibility, description, tooltip, etc.).
392 pub meta: NodeMeta,
393 /// Name of the node providing the raw register value.
394 pub p_value: String,
395 /// Parsed AST for the formula converting raw → user value.
396 pub ast_to: AstNode,
397 /// Parsed AST for the formula converting user → raw value.
398 pub ast_from: AstNode,
399 /// Variable mappings for formula_to (reading).
400 pub vars_to: Vec<(String, String)>,
401 /// Variable mappings for formula_from (writing).
402 pub vars_from: Vec<(String, String)>,
403 /// Optional engineering unit.
404 pub unit: Option<String>,
405 /// Predicate refs gating implementation / availability / lock state.
406 pub predicates: PredicateRefs,
407 /// Cached user-facing value alongside the generation it was computed in.
408 pub cache: RefCell<Option<(i64, u64)>>,
409}
410
411/// StringReg node for string-typed register access.
412#[derive(Debug)]
413pub struct StringNode {
414 /// Unique feature name.
415 pub name: String,
416 /// Shared metadata (visibility, description, tooltip, etc.).
417 pub meta: NodeMeta,
418 /// Register addressing metadata.
419 pub addressing: Addressing,
420 /// Declared access rights.
421 pub access: AccessMode,
422 /// Predicate refs gating implementation / availability / lock state.
423 pub predicates: PredicateRefs,
424 /// Cached string value alongside the generation it was computed in.
425 pub cache: RefCell<Option<(String, u64)>>,
426}