1use 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
94macro_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 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 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}