cameleon_genapi/parser/
struct_reg.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use tracing::debug;
6
7use crate::{
8    builder::{CacheStoreBuilder, NodeStoreBuilder, ValueStoreBuilder},
9    elem_type::{AccessMode, BitMask, CachingMode, Endianness, IntegerRepresentation, Sign},
10    node_base::{NodeAttributeBase, NodeElementBase},
11    register_base::RegisterBase,
12    store::NodeId,
13    MaskedIntRegNode,
14};
15
16use super::{
17    elem_name::{
18        ACCESS_MODE, CACHEABLE, ENDIANNESS, POLLING_TIME, P_INVALIDATOR, P_SELECTED,
19        REPRESENTATION, SIGN, STREAMABLE, STRUCT_ENTRY, STRUCT_REG, UNIT,
20    },
21    xml, Parse,
22};
23
24#[derive(Debug, Clone)]
25pub(super) struct StructRegNode {
26    register_base: RegisterBase,
27
28    endianness: Endianness,
29    entries: Vec<StructEntryNode>,
30}
31
32impl StructRegNode {
33    #[must_use]
34    pub(super) fn into_masked_int_regs(
35        self,
36        cache_builder: &mut impl CacheStoreBuilder,
37    ) -> Vec<MaskedIntRegNode> {
38        let register_base = self.register_base;
39        let endianness = self.endianness;
40        self.entries
41            .into_iter()
42            .map(|ent| ent.into_masked_int_reg(register_base.clone(), endianness, cache_builder))
43            .collect()
44    }
45}
46
47impl Parse for StructRegNode {
48    #[tracing::instrument(level = "trace", skip(node_builder, value_builder, cache_builder))]
49    fn parse(
50        node: &mut xml::Node,
51        node_builder: &mut impl NodeStoreBuilder,
52        value_builder: &mut impl ValueStoreBuilder,
53        cache_builder: &mut impl CacheStoreBuilder,
54    ) -> Self {
55        debug!("start parsing `StructRegNode`");
56        debug_assert_eq!(node.tag_name(), STRUCT_REG);
57
58        let register_base = node.parse(node_builder, value_builder, cache_builder);
59
60        let endianness = node
61            .parse_if(ENDIANNESS, node_builder, value_builder, cache_builder)
62            .unwrap_or_default();
63        let mut entries = vec![];
64        while let Some(mut entry_node) = node.next() {
65            let entry = entry_node.parse(node_builder, value_builder, cache_builder);
66            entries.push(entry);
67        }
68
69        Self {
70            register_base,
71            endianness,
72            entries,
73        }
74    }
75}
76
77#[derive(Debug, Clone)]
78struct StructEntryNode {
79    attr_base: NodeAttributeBase,
80    elem_base: NodeElementBase,
81
82    p_invalidators: Vec<NodeId>,
83    access_mode: AccessMode,
84    cacheable: CachingMode,
85    polling_time: Option<u64>,
86    streamable: bool,
87    bit_mask: BitMask,
88    sign: Sign,
89    unit: Option<String>,
90    representation: IntegerRepresentation,
91    p_selected: Vec<NodeId>,
92}
93
94/// See "2.8.7 StructReg" in GenICam Standard v2.1.1.
95macro_rules! merge_impl {
96    ($lhs:ident, $rhs:ident, $name:ident) => {
97        if $rhs.$name.is_some() {
98            $lhs.$name = $rhs.$name;
99        }
100    };
101
102    ($lhs:ident, $rhs:ident, $name:ident, default) => {
103        #[allow(clippy::default_trait_access)]
104        if $rhs.$name != Default::default() {
105            $lhs.$name = $rhs.$name;
106        }
107    };
108
109    ($lhs:ident, $rhs:ident, $name:ident, vec) => {
110        if $rhs.$name.is_empty() {
111            $lhs.$name = $rhs.$name.clone();
112        }
113    };
114}
115
116impl StructEntryNode {
117    fn into_masked_int_reg(
118        self,
119        mut register_base: RegisterBase,
120        endianness: Endianness,
121        cache_builder: &mut impl CacheStoreBuilder,
122    ) -> MaskedIntRegNode {
123        let attr_base = self.attr_base;
124        let elem_base = &mut register_base.elem_base;
125
126        elem_base.merge(self.elem_base);
127        merge_impl!(register_base, self, streamable, default);
128        // `AccessMode::RO` is the default value of AccessMode.
129        if self.access_mode != AccessMode::RO {
130            register_base.access_mode = self.access_mode;
131        }
132        merge_impl!(register_base, self, cacheable, default);
133        merge_impl!(register_base, self, polling_time);
134        merge_impl!(register_base, self, p_invalidators, vec);
135
136        register_base.store_invalidators(attr_base.id, cache_builder);
137        MaskedIntRegNode {
138            attr_base,
139            register_base,
140            bit_mask: self.bit_mask,
141            sign: self.sign,
142            endianness,
143            unit: self.unit,
144            representation: self.representation,
145            p_selected: self.p_selected,
146        }
147    }
148}
149
150impl NodeElementBase {
151    fn merge(&mut self, rhs: Self) {
152        merge_impl!(self, rhs, tooltip);
153        merge_impl!(self, rhs, description);
154        merge_impl!(self, rhs, display_name);
155        merge_impl!(self, rhs, visibility, default);
156        merge_impl!(self, rhs, docu_url);
157        merge_impl!(self, rhs, is_deprecated, default);
158        merge_impl!(self, rhs, event_id);
159        merge_impl!(self, rhs, p_is_implemented);
160        merge_impl!(self, rhs, p_is_available);
161        merge_impl!(self, rhs, p_is_locked);
162        merge_impl!(self, rhs, p_block_polling);
163        // `AccessMode::RW` is the default value of ImposedAccessMode.
164        if rhs.imposed_access_mode != AccessMode::RW {
165            self.imposed_access_mode = rhs.imposed_access_mode;
166        }
167
168        merge_impl!(self, rhs, p_errors, vec);
169        merge_impl!(self, rhs, p_alias);
170        merge_impl!(self, rhs, p_cast_alias);
171    }
172}
173
174impl Parse for StructEntryNode {
175    fn parse(
176        node: &mut xml::Node,
177        node_builder: &mut impl NodeStoreBuilder,
178        value_builder: &mut impl ValueStoreBuilder,
179        cache_builder: &mut impl CacheStoreBuilder,
180    ) -> Self {
181        debug_assert_eq!(node.tag_name(), STRUCT_ENTRY);
182
183        let attr_base = node.parse(node_builder, value_builder, cache_builder);
184        let elem_base = node.parse(node_builder, value_builder, cache_builder);
185
186        let p_invalidators =
187            node.parse_while(P_INVALIDATOR, node_builder, value_builder, cache_builder);
188        let access_mode = node
189            .parse_if(ACCESS_MODE, node_builder, value_builder, cache_builder)
190            .unwrap_or(AccessMode::RO);
191        let cacheable = node
192            .parse_if(CACHEABLE, node_builder, value_builder, cache_builder)
193            .unwrap_or_default();
194        let polling_time = node.parse_if(POLLING_TIME, node_builder, value_builder, cache_builder);
195        let streamable = node
196            .parse_if(STREAMABLE, node_builder, value_builder, cache_builder)
197            .unwrap_or_default();
198        let bit_mask = node.parse(node_builder, value_builder, cache_builder);
199        let sign = node
200            .parse_if(SIGN, node_builder, value_builder, cache_builder)
201            .unwrap_or_default();
202        let unit = node.parse_if(UNIT, node_builder, value_builder, cache_builder);
203        let representation = node
204            .parse_if(REPRESENTATION, node_builder, value_builder, cache_builder)
205            .unwrap_or_default();
206        let p_selected = node.parse_while(P_SELECTED, node_builder, value_builder, cache_builder);
207
208        Self {
209            attr_base,
210            elem_base,
211            p_invalidators,
212            access_mode,
213            cacheable,
214            polling_time,
215            streamable,
216            bit_mask,
217            sign,
218            unit,
219            representation,
220            p_selected,
221        }
222    }
223}
224
225#[cfg(test)]
226mod tests {
227    use crate::interface::INode;
228
229    use super::{super::utils::tests::parse_default, *};
230
231    #[test]
232    fn test_to_masked_int_regs() {
233        let xml = r#"
234            <StructReg Comment="Struct Reg Comment">
235                <ToolTip>Struct Reg ToolTip</ToolTip>
236                <Address>0x10000</Address>
237                <Length>4</Length>
238                <pPort>Device</pPort>
239                <Endianess>BigEndian</Endianess>
240
241                <StructEntry Name="StructEntry0">
242                    <ToolTip>StructEntry0 ToolTip</ToolTip>
243                    <ImposedAccessMode>RO</ImposedAccessMode>
244                    <pInvalidator>Invalidator0</pInvalidator>
245                    <pInvalidator>Invalidator1</pInvalidator>
246                    <AccessMode>RW</AccessMode>
247                    <Cachable>WriteAround</Cachable>
248                    <PollingTime>1000</PollingTime>
249                    <Streamable>Yes</Streamable>
250                    <LSB>10</LSB>
251                    <MSB>1</MSB>
252                    <Sign>Signed</Sign>
253                    <Unit>Hz</Unit>
254                    <Representation>Logarithmic</Representation>
255                    <pSelected>Selected0</pSelected>
256                    <pSelected>Selected1</pSelected>
257                </StructEntry>
258
259                <StructEntry Name="StructEntry1">
260                    <Bit>24</Bit>
261                </StructEntry>
262
263            </StructReg>
264            "#;
265        let (node, mut node_builder, _, mut cache_builder): (StructRegNode, _, _, _) =
266            parse_default(xml);
267        let masked_int_regs: Vec<_> = node.into_masked_int_regs(&mut cache_builder);
268
269        assert_eq!(masked_int_regs.len(), 2);
270
271        let masked_int_reg0 = &masked_int_regs[0];
272        assert_eq!(
273            masked_int_reg0.node_base().id(),
274            node_builder.get_or_intern("StructEntry0")
275        );
276        assert_eq!(
277            masked_int_reg0.node_base().imposed_access_mode(),
278            AccessMode::RO
279        );
280        assert_eq!(
281            masked_int_reg0.node_base().tooltip().unwrap(),
282            "StructEntry0 ToolTip"
283        );
284        assert_eq!(
285            masked_int_reg0.register_base().access_mode(),
286            AccessMode::RW,
287        );
288
289        let masked_int_reg1 = &masked_int_regs[1];
290        assert_eq!(
291            masked_int_reg1.node_base().id(),
292            node_builder.get_or_intern("StructEntry1")
293        );
294        assert_eq!(
295            masked_int_reg1.node_base().imposed_access_mode(),
296            AccessMode::RW
297        );
298        assert_eq!(
299            masked_int_reg1.node_base().tooltip().unwrap(),
300            "Struct Reg ToolTip"
301        );
302        assert_eq!(
303            masked_int_reg1.register_base().access_mode(),
304            AccessMode::RO,
305        );
306    }
307}