Skip to main content

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, EnumEntryDecl};
7pub use viva_genapi_xml::{NodeMeta, 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    pub(crate) fn invalidate_cache(&self) {
127        match self {
128            Node::Integer(node) => {
129                node.cache.replace(None);
130                node.raw_cache.replace(None);
131            }
132            Node::Float(node) => {
133                node.cache.replace(None);
134            }
135            Node::Enum(node) => node.invalidate(),
136            Node::Boolean(node) => {
137                node.cache.replace(None);
138                node.raw_cache.replace(None);
139            }
140            Node::SwissKnife(node) => {
141                node.cache.replace(None);
142            }
143            Node::Converter(node) => {
144                node.cache.replace(None);
145            }
146            Node::IntConverter(node) => {
147                node.cache.replace(None);
148            }
149            Node::String(node) => {
150                node.cache.replace(None);
151            }
152            Node::Command(_) | Node::Category(_) => {}
153        }
154    }
155}
156
157/// Integer feature metadata extracted from the XML description.
158#[derive(Debug)]
159pub struct IntegerNode {
160    /// Unique feature name.
161    pub name: String,
162    /// Shared metadata (visibility, description, tooltip, etc.).
163    pub meta: NodeMeta,
164    /// Register addressing metadata (absent when delegated via `pvalue`).
165    pub addressing: Option<Addressing>,
166    /// Nominal register length in bytes.
167    pub len: u32,
168    /// Declared access rights.
169    pub access: AccessMode,
170    /// Minimum permitted user value.
171    pub min: i64,
172    /// Maximum permitted user value.
173    pub max: i64,
174    /// Optional increment step the value must respect.
175    pub inc: Option<i64>,
176    /// Optional engineering unit such as "us".
177    pub unit: Option<String>,
178    /// Optional bitfield metadata restricting active bits.
179    pub bitfield: Option<BitField>,
180    /// Selector nodes controlling the visibility of this node.
181    pub selectors: Vec<String>,
182    /// Selector gating rules in the form `(selector, allowed values)`.
183    pub selected_if: Vec<(String, Vec<String>)>,
184    /// Node providing the value (delegates read/write).
185    pub pvalue: Option<String>,
186    /// Node providing the dynamic maximum.
187    pub p_max: Option<String>,
188    /// Node providing the dynamic minimum.
189    pub p_min: Option<String>,
190    /// Static value for constant nodes.
191    pub value: Option<i64>,
192    pub(crate) cache: RefCell<Option<i64>>,
193    pub(crate) raw_cache: RefCell<Option<Vec<u8>>>,
194}
195
196/// Floating point feature metadata.
197#[derive(Debug)]
198pub struct FloatNode {
199    pub name: String,
200    /// Shared metadata (visibility, description, tooltip, etc.).
201    pub meta: NodeMeta,
202    /// Register addressing metadata (absent when delegated via `pvalue`).
203    pub addressing: Option<Addressing>,
204    pub access: AccessMode,
205    pub min: f64,
206    pub max: f64,
207    pub unit: Option<String>,
208    /// Optional rational scale `(numerator, denominator)` applied to the raw value.
209    pub scale: Option<(i64, i64)>,
210    /// Optional offset added after scaling.
211    pub offset: Option<f64>,
212    pub selectors: Vec<String>,
213    pub selected_if: Vec<(String, Vec<String>)>,
214    /// Node providing the value (delegates read/write).
215    pub pvalue: Option<String>,
216    pub(crate) cache: RefCell<Option<f64>>,
217}
218
219/// Enumeration feature metadata and mapping tables.
220#[derive(Debug)]
221pub struct EnumNode {
222    pub name: String,
223    /// Shared metadata (visibility, description, tooltip, etc.).
224    pub meta: NodeMeta,
225    /// Register addressing metadata (absent when delegated via `pvalue`).
226    pub addressing: Option<Addressing>,
227    pub access: AccessMode,
228    /// Node providing the integer value (delegates register read/write).
229    pub pvalue: Option<String>,
230    pub entries: Vec<EnumEntryDecl>,
231    pub default: Option<String>,
232    pub selectors: Vec<String>,
233    pub selected_if: Vec<(String, Vec<String>)>,
234    pub providers: Vec<String>,
235    pub(crate) value_cache: RefCell<Option<String>>,
236    pub(crate) mapping_cache: RefCell<Option<EnumMapping>>,
237}
238
239#[derive(Debug, Clone)]
240pub(crate) struct EnumMapping {
241    pub by_value: HashMap<i64, String>,
242    pub by_name: HashMap<String, i64>,
243}
244
245impl EnumNode {
246    pub(crate) fn invalidate(&self) {
247        self.value_cache.replace(None);
248        self.mapping_cache.replace(None);
249    }
250}
251
252/// Boolean feature metadata.
253#[derive(Debug)]
254pub struct BooleanNode {
255    pub name: String,
256    /// Shared metadata (visibility, description, tooltip, etc.).
257    pub meta: NodeMeta,
258    /// Register addressing metadata (absent when delegated via `pvalue`).
259    pub addressing: Option<Addressing>,
260    pub len: u32,
261    pub access: AccessMode,
262    /// Optional bitfield (absent for pValue-backed booleans).
263    pub bitfield: Option<BitField>,
264    pub selectors: Vec<String>,
265    pub selected_if: Vec<(String, Vec<String>)>,
266    /// Node providing the value (delegates read/write).
267    pub pvalue: Option<String>,
268    /// On value for pValue-backed booleans.
269    pub on_value: Option<i64>,
270    /// Off value for pValue-backed booleans.
271    pub off_value: Option<i64>,
272    pub(crate) cache: RefCell<Option<bool>>,
273    pub(crate) raw_cache: RefCell<Option<Vec<u8>>>,
274}
275
276/// SwissKnife node evaluating an arithmetic expression referencing other nodes.
277///
278/// Integer outputs follow round-to-nearest semantics with ties towards zero
279/// after the expression has been evaluated as `f64`.
280#[derive(Debug)]
281pub struct SkNode {
282    /// Unique feature name.
283    pub name: String,
284    /// Shared metadata (visibility, description, tooltip, etc.).
285    pub meta: NodeMeta,
286    /// Desired output type as declared in the XML.
287    pub output: SkOutput,
288    /// Parsed expression AST.
289    pub ast: AstNode,
290    /// Mapping of variable identifiers to provider node names.
291    pub vars: Vec<(String, String)>,
292    /// Cached value alongside the generation it was computed in.
293    pub cache: RefCell<Option<(f64, u64)>>,
294}
295
296/// Command feature metadata.
297#[derive(Debug)]
298pub struct CommandNode {
299    pub name: String,
300    /// Shared metadata (visibility, description, tooltip, etc.).
301    pub meta: NodeMeta,
302    /// Fixed register address (absent when delegated via `pvalue`).
303    pub address: Option<u64>,
304    pub len: u32,
305    /// Node providing the command register.
306    pub pvalue: Option<String>,
307    /// Value to write when executing the command.
308    pub command_value: Option<i64>,
309}
310
311/// Category node describing child feature names.
312#[derive(Debug)]
313pub struct CategoryNode {
314    pub name: String,
315    /// Shared metadata (visibility, description, tooltip, etc.).
316    pub meta: NodeMeta,
317    pub children: Vec<String>,
318}
319
320/// Converter node transforming raw values to/from float values via formulas.
321///
322/// Converters use two formulas:
323/// - `formula_to`: converts from raw register value to user-facing float (reading)
324/// - `formula_from`: converts from user-facing float to raw register value (writing)
325#[derive(Debug)]
326pub struct ConverterNode {
327    /// Unique feature name.
328    pub name: String,
329    /// Shared metadata (visibility, description, tooltip, etc.).
330    pub meta: NodeMeta,
331    /// Name of the node providing the raw register value.
332    pub p_value: String,
333    /// Parsed AST for the formula converting raw → user value.
334    pub ast_to: AstNode,
335    /// Parsed AST for the formula converting user → raw value.
336    pub ast_from: AstNode,
337    /// Variable mappings for formula_to (reading).
338    pub vars_to: Vec<(String, String)>,
339    /// Variable mappings for formula_from (writing).
340    pub vars_from: Vec<(String, String)>,
341    /// Optional engineering unit.
342    pub unit: Option<String>,
343    /// Desired output type.
344    pub output: SkOutput,
345    /// Cached user-facing value alongside the generation it was computed in.
346    pub cache: RefCell<Option<(f64, u64)>>,
347}
348
349/// IntConverter node transforming raw values to/from integer values via formulas.
350#[derive(Debug)]
351pub struct IntConverterNode {
352    /// Unique feature name.
353    pub name: String,
354    /// Shared metadata (visibility, description, tooltip, etc.).
355    pub meta: NodeMeta,
356    /// Name of the node providing the raw register value.
357    pub p_value: String,
358    /// Parsed AST for the formula converting raw → user value.
359    pub ast_to: AstNode,
360    /// Parsed AST for the formula converting user → raw value.
361    pub ast_from: AstNode,
362    /// Variable mappings for formula_to (reading).
363    pub vars_to: Vec<(String, String)>,
364    /// Variable mappings for formula_from (writing).
365    pub vars_from: Vec<(String, String)>,
366    /// Optional engineering unit.
367    pub unit: Option<String>,
368    /// Cached user-facing value alongside the generation it was computed in.
369    pub cache: RefCell<Option<(i64, u64)>>,
370}
371
372/// StringReg node for string-typed register access.
373#[derive(Debug)]
374pub struct StringNode {
375    /// Unique feature name.
376    pub name: String,
377    /// Shared metadata (visibility, description, tooltip, etc.).
378    pub meta: NodeMeta,
379    /// Register addressing metadata.
380    pub addressing: Addressing,
381    /// Declared access rights.
382    pub access: AccessMode,
383    /// Cached string value alongside the generation it was computed in.
384    pub cache: RefCell<Option<(String, u64)>>,
385}