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}