dbc_codegen2/ir/
ir_builder.rs1use can_dbc::Dbc as ParsedDbc;
2use can_dbc::Message as ParsedMessage;
3use can_dbc::Signal as ParsedSignal;
4use can_dbc::SignalExtendedValueTypeList as ParsedExtendedValueType;
5use crate::ir::{map_into, SignalValueEnum, ExtendedValueType, Signal, Message, SignalIdx, SignalLayout, SignalLayoutIdx, MessageLayout, MessageLayoutIdx};
6use can_dbc::ValueDescription as ParsedValueDescription;
7
8use std::collections::HashMap;
9
10use crate::DbcFile;
11
12type SignalKey = (can_dbc::MessageId, String);
13
14pub struct IRBuilder {
15 file: DbcFile,
16 can_dbc_messages: Vec<ParsedMessage>,
17
18 value_enum_map: HashMap<SignalKey, SignalValueEnum>,
19 extended_type_map: HashMap<SignalKey, ExtendedValueType>,
20
21 signal_layout_map: HashMap<SignalLayout, SignalLayoutIdx>,
22 message_layout_map: HashMap<MessageLayout, MessageLayoutIdx>,
23}
24
25impl IRBuilder {
26
27 pub fn to_ir(value: ParsedDbc) -> DbcFile {
28 let mut builder = Self::new(value);
29 builder.build();
30 builder.file
31 }
32
33 fn new(value: ParsedDbc) -> Self {
34 let value_enum_map = Self::value_enum_map(value.value_descriptions);
35 let extended_type_map = Self::extended_type_map(value.signal_extended_value_type_list);
36
37 let mut file = DbcFile::default();
38 file.nodes = map_into(value.nodes);
39
40 Self {
41 file,
42 can_dbc_messages: value.messages,
43
44 value_enum_map,
45 extended_type_map,
46
47 signal_layout_map: HashMap::new(),
48 message_layout_map: HashMap::new(),
49 }
50 }
51
52 fn build(&mut self) {
53 for msg in std::mem::take(&mut self.can_dbc_messages) {
54 if msg.name == "VECTOR__INDEPENDENT_SIG_MSG" {
55 continue;
56 }
57
58 self.build_message(msg);
59 }
60 }
61
62 fn build_message(&mut self, msg: ParsedMessage) {
63 let ParsedMessage { id, name, size, transmitter, signals, .. } = msg;
64
65 let mut signal_idxs = Vec::new();
66 let mut signal_layout_idxs = Vec::new();
67
68 for sig in signals {
69 let (sig_idx, layout_idx) = self.build_signal(id, sig);
70
71 signal_idxs.push(sig_idx);
72 signal_layout_idxs.push(layout_idx);
73 }
74
75 let layout_idx = self.build_message_layout(signal_layout_idxs);
76
77 let message = Message::from_parsed(
78 id,
79 name,
80 size,
81 transmitter,
82 signal_idxs,
83 layout_idx,
84 );
85
86 self.file.messages.push(message);
87 }
88
89 fn build_message_layout(
90 &mut self,
91 signal_layout_idxs: Vec<SignalLayoutIdx>,
92 ) -> MessageLayoutIdx {
93 let layout = MessageLayout {
94 signal_layouts: signal_layout_idxs,
95 };
96
97 if let Some(idx) = self.message_layout_map.get(&layout) {
98 return *idx;
99 }
100
101 let idx = MessageLayoutIdx(self.file.message_layouts.len());
102
103 self.file.message_layouts.push(layout.clone());
104 self.message_layout_map.insert(layout, idx);
105
106 idx
107 }
108
109 fn build_signal(
110 &mut self,
111 message_id: can_dbc::MessageId,
112 parsed_sig: ParsedSignal,
113 ) -> (SignalIdx, SignalLayoutIdx) {
114
115 let key = (message_id, parsed_sig.name.clone());
116
117 let layout_idx = self.build_signal_layout(&parsed_sig);
118
119 let mut signal = Signal::from(parsed_sig);
120 signal.layout = layout_idx;
121
122 if let Some(enum_val) = self.value_enum_map.remove(&key) {
123 signal.signal_value_enum = Some(enum_val);
124 }
125
126 if let Some(ext) = self.extended_type_map.remove(&key) {
127 signal.extended_type = ext;
128 }
129
130 let idx = SignalIdx(self.file.signals.len());
131 self.file.signals.push(signal);
132
133 (idx, layout_idx)
134 }
135
136 fn build_signal_layout(&mut self, sig: &ParsedSignal) -> SignalLayoutIdx {
137 let layout = SignalLayout::from(sig);
138
139 if let Some(idx) = self.signal_layout_map.get(&layout) {
140 return *idx;
141 }
142
143 let idx = SignalLayoutIdx(self.file.signal_layouts.len());
144
145 self.file.signal_layouts.push(layout);
146 self.signal_layout_map.insert(layout, idx);
147
148 idx
149 }
150
151 fn value_enum_map(value_descriptions: Vec<ParsedValueDescription>) -> HashMap<SignalKey, SignalValueEnum> {
152 let mut value_enum_map: HashMap<SignalKey, SignalValueEnum> = HashMap::new();
153
154 for value_enum in value_descriptions {
155 if let ParsedValueDescription::Signal {
156 message_id,
157 name,
158 value_descriptions,
159 } = value_enum
160 {
161 let sve = SignalValueEnum::from_parsed( value_descriptions);
162 value_enum_map.insert((message_id, name), sve);
163 }
164 }
165
166 value_enum_map
167 }
168
169 fn extended_type_map(extended_types: Vec<ParsedExtendedValueType>) -> HashMap<SignalKey, ExtendedValueType> {
170 let mut extended_type_map: HashMap<SignalKey, ExtendedValueType> = HashMap::new();
171
172 for ext in extended_types {
173 let ir_ext_type = ExtendedValueType::from(ext.signal_extended_value_type);
174
175 let ParsedExtendedValueType { message_id, signal_name, ..} = ext;
176 extended_type_map.insert((message_id, signal_name),ir_ext_type);
177 }
178
179 extended_type_map
180 }
181}