dbc_codegen/
lib.rs

1//! CAN DBC code generator for Rust
2//!
3//! DBC files are descriptions of CAN frames.
4//! See [this post](https://www.kvaser.com/developer-blog/an-introduction-j1939-and-dbc-files/)
5//! for an introduction.
6
7#![deny(missing_docs)]
8#![deny(clippy::arithmetic_side_effects)]
9
10use anyhow::{anyhow, ensure, Context, Result};
11use can_dbc::{Message, MultiplexIndicator, Signal, ValDescription, ValueDescription, DBC};
12use heck::{ToPascalCase, ToSnakeCase};
13use pad::PadAdapter;
14use std::{
15    collections::{BTreeMap, BTreeSet},
16    io::{BufWriter, Write},
17};
18
19mod includes;
20mod keywords;
21mod pad;
22
23/// Write Rust structs matching DBC input description to `out` buffer
24pub fn codegen(dbc_name: &str, dbc_content: &[u8], out: impl Write, debug: bool) -> Result<()> {
25    let dbc = can_dbc::DBC::from_slice(dbc_content).map_err(|e| {
26        let msg = "Could not parse dbc file";
27        if debug {
28            anyhow!("{}: {:#?}", msg, e)
29        } else {
30            anyhow!("{}", msg)
31        }
32    })?;
33    if debug {
34        eprintln!("{:#?}", dbc);
35    }
36    let mut w = BufWriter::new(out);
37
38    writeln!(&mut w, "// Generated code!")?;
39    writeln!(
40        &mut w,
41        "#![allow(unused_comparisons, unreachable_patterns)]"
42    )?;
43    writeln!(&mut w, "#![allow(clippy::let_and_return, clippy::eq_op)]")?;
44    writeln!(
45        &mut w,
46        "#![allow(clippy::excessive_precision, clippy::manual_range_contains, clippy::absurd_extreme_comparisons)]"
47    )?;
48    writeln!(&mut w, "#![deny(clippy::arithmetic_side_effects)]")?;
49    writeln!(&mut w)?;
50    writeln!(&mut w, "//! Message definitions from file `{:?}`", dbc_name)?;
51    writeln!(&mut w, "//!")?;
52    writeln!(&mut w, "//! - Version: `{:?}`", dbc.version())?;
53    writeln!(&mut w)?;
54    writeln!(&mut w, "use core::ops::BitOr;")?;
55    writeln!(&mut w, "use bitvec::prelude::*;")?;
56    writeln!(w, r##"#[cfg(feature = "arb")]"##)?;
57    writeln!(&mut w, "use arbitrary::{{Arbitrary, Unstructured}};")?;
58    writeln!(&mut w)?;
59
60    render_dbc(&mut w, &dbc).context("could not generate Rust code")?;
61
62    writeln!(&mut w)?;
63    writeln!(&mut w, "/// This is just to make testing easier")?;
64    writeln!(&mut w, "#[allow(dead_code)]")?;
65    writeln!(&mut w, "fn main() {{}}")?;
66    writeln!(&mut w)?;
67    w.write_all(include_bytes!("./includes/errors.rs"))?;
68    w.write_all(include_bytes!("./includes/arbitrary_helpers.rs"))?;
69    writeln!(&mut w)?;
70
71    Ok(())
72}
73
74fn render_dbc(mut w: impl Write, dbc: &DBC) -> Result<()> {
75    render_root_enum(&mut w, dbc)?;
76
77    for msg in get_relevant_messages(dbc) {
78        render_message(&mut w, msg, dbc)
79            .with_context(|| format!("write message `{}`", msg.message_name()))?;
80        writeln!(w)?;
81    }
82
83    Ok(())
84}
85
86fn render_root_enum(mut w: impl Write, dbc: &DBC) -> Result<()> {
87    writeln!(w, "/// All messages")?;
88    writeln!(w, "#[derive(Clone)]")?;
89    writeln!(w, r##"#[cfg_attr(feature = "debug", derive(Debug))]"##)?;
90    writeln!(w, "pub enum Messages {{")?;
91    {
92        let mut w = PadAdapter::wrap(&mut w);
93        for msg in get_relevant_messages(dbc) {
94            writeln!(w, "/// {}", msg.message_name())?;
95            writeln!(w, "{0}({0}),", type_name(msg.message_name()))?;
96        }
97    }
98    writeln!(&mut w, "}}")?;
99    writeln!(&mut w)?;
100
101    writeln!(w, "impl Messages {{")?;
102    {
103        let mut w = PadAdapter::wrap(&mut w);
104        writeln!(&mut w, "/// Read message from CAN frame")?;
105        writeln!(w, "#[inline(never)]")?;
106        writeln!(
107            &mut w,
108            "pub fn from_can_message(id: u32, payload: &[u8]) -> Result<Self, CanError> {{",
109        )?;
110        {
111            let mut w = PadAdapter::wrap(&mut w);
112            writeln!(&mut w)?;
113            writeln!(&mut w, "let res = match id {{")?;
114            {
115                let mut w = PadAdapter::wrap(&mut w);
116                for msg in get_relevant_messages(dbc) {
117                    writeln!(
118                        w,
119                        "{} => Messages::{1}({1}::try_from(payload)?),",
120                        msg.message_id().0,
121                        type_name(msg.message_name())
122                    )?;
123                }
124                writeln!(w, r#"n => return Err(CanError::UnknownMessageId(n)),"#)?;
125            }
126            writeln!(&mut w, "}};")?;
127            writeln!(&mut w, "Ok(res)")?;
128        }
129
130        writeln!(&mut w, "}}")?;
131    }
132    writeln!(&mut w, "}}")?;
133    writeln!(&mut w)?;
134
135    Ok(())
136}
137
138fn render_message(mut w: impl Write, msg: &Message, dbc: &DBC) -> Result<()> {
139    writeln!(w, "/// {}", msg.message_name())?;
140    writeln!(w, "///")?;
141    writeln!(w, "/// - ID: {0} (0x{0:x})", msg.message_id().0)?;
142    writeln!(w, "/// - Size: {} bytes", msg.message_size())?;
143    if let can_dbc::Transmitter::NodeName(transmitter) = msg.transmitter() {
144        writeln!(w, "/// - Transmitter: {}", transmitter)?;
145    }
146    if let Some(comment) = dbc.message_comment(*msg.message_id()) {
147        writeln!(w, "///")?;
148        for line in comment.trim().lines() {
149            writeln!(w, "/// {}", line)?;
150        }
151    }
152    writeln!(w, "#[derive(Clone, Copy)]")?;
153    writeln!(w, "pub struct {} {{", type_name(msg.message_name()))?;
154    {
155        let mut w = PadAdapter::wrap(&mut w);
156        writeln!(w, "raw: [u8; {}],", msg.message_size())?;
157    }
158    writeln!(w, "}}")?;
159    writeln!(w)?;
160
161    writeln!(w, "impl {} {{", type_name(msg.message_name()))?;
162    {
163        let mut w = PadAdapter::wrap(&mut w);
164
165        writeln!(
166            &mut w,
167            "pub const MESSAGE_ID: u32 = {};",
168            msg.message_id().0
169        )?;
170        writeln!(w)?;
171
172        for signal in msg
173            .signals()
174            .iter()
175            .filter(|sig| signal_to_rust_type(sig) != "bool")
176        {
177            let typ = signal_to_rust_type(signal);
178            writeln!(
179                &mut w,
180                "pub const {sig}_MIN: {typ} = {min}_{typ};",
181                sig = field_name(signal.name()).to_uppercase(),
182                typ = typ,
183                min = signal.min,
184            )?;
185
186            writeln!(
187                &mut w,
188                "pub const {sig}_MAX: {typ} = {max}_{typ};",
189                sig = field_name(signal.name()).to_uppercase(),
190                typ = typ,
191                max = signal.max,
192            )?;
193        }
194        writeln!(w)?;
195
196        writeln!(
197            &mut w,
198            "/// Construct new {} from values",
199            msg.message_name()
200        )?;
201        let args: Vec<String> = msg
202            .signals()
203            .iter()
204            .filter_map(|signal| {
205                if *signal.multiplexer_indicator() == MultiplexIndicator::Plain
206                    || *signal.multiplexer_indicator() == MultiplexIndicator::Multiplexor
207                {
208                    Some(format!(
209                        "{}: {}",
210                        field_name(signal.name()),
211                        signal_to_rust_type(signal)
212                    ))
213                } else {
214                    None
215                }
216            })
217            .collect();
218        writeln!(
219            &mut w,
220            "pub fn new({}) -> Result<Self, CanError> {{",
221            args.join(", ")
222        )?;
223        {
224            let mut w = PadAdapter::wrap(&mut w);
225            writeln!(
226                &mut w,
227                "let mut res = Self {{ raw: [0u8; {}] }};",
228                msg.message_size()
229            )?;
230            for signal in msg.signals().iter() {
231                if *signal.multiplexer_indicator() == MultiplexIndicator::Plain {
232                    writeln!(&mut w, "res.set_{0}({0})?;", field_name(signal.name()))?;
233                }
234
235                if *signal.multiplexer_indicator() == MultiplexIndicator::Multiplexor {
236                    writeln!(&mut w, "res.set_{0}({0})?;", field_name(signal.name()))?;
237                }
238            }
239            writeln!(&mut w, "Ok(res)")?;
240        }
241        writeln!(&mut w, "}}")?;
242        writeln!(w)?;
243
244        writeln!(&mut w, "/// Access message payload raw value")?;
245        writeln!(
246            &mut w,
247            "pub fn raw(&self) -> &[u8; {}] {{",
248            msg.message_size()
249        )?;
250        {
251            let mut w = PadAdapter::wrap(&mut w);
252            writeln!(&mut w, "&self.raw")?;
253        }
254        writeln!(&mut w, "}}")?;
255        writeln!(w)?;
256
257        for signal in msg.signals().iter() {
258            match signal.multiplexer_indicator() {
259                MultiplexIndicator::Plain => render_signal(&mut w, signal, dbc, msg)
260                    .with_context(|| format!("write signal impl `{}`", signal.name()))?,
261                MultiplexIndicator::Multiplexor => render_multiplexor_signal(&mut w, signal, msg)?,
262                MultiplexIndicator::MultiplexedSignal(_) => {}
263                MultiplexIndicator::MultiplexorAndMultiplexedSignal(_) => {}
264            }
265        }
266    }
267
268    writeln!(w, "}}")?;
269    writeln!(w)?;
270
271    writeln!(
272        w,
273        "impl core::convert::TryFrom<&[u8]> for {} {{",
274        type_name(msg.message_name())
275    )?;
276    {
277        let mut w = PadAdapter::wrap(&mut w);
278        writeln!(&mut w, "type Error = CanError;")?;
279        writeln!(w)?;
280        writeln!(w, "#[inline(always)]")?;
281        writeln!(
282            &mut w,
283            "fn try_from(payload: &[u8]) -> Result<Self, Self::Error> {{"
284        )?;
285        {
286            let mut w = PadAdapter::wrap(&mut w);
287            writeln!(
288                &mut w,
289                r#"if payload.len() != {} {{ return Err(CanError::InvalidPayloadSize); }}"#,
290                msg.message_size()
291            )?;
292            writeln!(&mut w, "let mut raw = [0u8; {}];", msg.message_size())?;
293            writeln!(
294                &mut w,
295                "raw.copy_from_slice(&payload[..{}]);",
296                msg.message_size()
297            )?;
298            writeln!(&mut w, "Ok(Self {{ raw }})")?;
299        }
300        writeln!(&mut w, "}}")?;
301    }
302    writeln!(w, "}}")?;
303    writeln!(w)?;
304
305    render_debug_impl(&mut w, msg)?;
306
307    render_arbitrary(&mut w, msg)?;
308
309    let enums_for_this_message = dbc.value_descriptions().iter().filter_map(|x| {
310        if let ValueDescription::Signal {
311            message_id,
312            signal_name,
313            value_descriptions,
314        } = x
315        {
316            if message_id != msg.message_id() {
317                return None;
318            }
319            let signal = dbc.signal_by_name(*message_id, signal_name).unwrap();
320            Some((signal, value_descriptions))
321        } else {
322            None
323        }
324    });
325    for (signal, variants) in enums_for_this_message {
326        write_enum(&mut w, signal, msg, variants.as_slice())?;
327    }
328
329    let multiplexor_signal = msg
330        .signals()
331        .iter()
332        .find(|s| *s.multiplexer_indicator() == MultiplexIndicator::Multiplexor);
333
334    if let Some(multiplexor_signal) = multiplexor_signal {
335        render_multiplexor_enums(w, dbc, msg, multiplexor_signal)?;
336    }
337
338    Ok(())
339}
340
341fn render_signal(mut w: impl Write, signal: &Signal, dbc: &DBC, msg: &Message) -> Result<()> {
342    writeln!(w, "/// {}", signal.name())?;
343    if let Some(comment) = dbc.signal_comment(*msg.message_id(), signal.name()) {
344        writeln!(w, "///")?;
345        for line in comment.trim().lines() {
346            writeln!(w, "/// {}", line)?;
347        }
348    }
349    writeln!(w, "///")?;
350    writeln!(w, "/// - Min: {}", signal.min)?;
351    writeln!(w, "/// - Max: {}", signal.max)?;
352    writeln!(w, "/// - Unit: {:?}", signal.unit())?;
353    writeln!(w, "/// - Receivers: {}", signal.receivers().join(", "))?;
354    writeln!(w, "#[inline(always)]")?;
355    if let Some(variants) = dbc.value_descriptions_for_signal(*msg.message_id(), signal.name()) {
356        let type_name = enum_name(msg, signal);
357
358        writeln!(
359            w,
360            "pub fn {}(&self) -> {} {{",
361            field_name(signal.name()),
362            type_name,
363        )?;
364        {
365            let match_on_raw_type = match signal_to_rust_type(signal).as_str() {
366                "bool" => |x: f64| format!("{}", x),
367                // "f32" => |x: f64| format!("x if approx_eq!(f32, x, {}_f32, ulps = 2)", x),
368                _ => |x: f64| format!("{}", x),
369            };
370            let mut w = PadAdapter::wrap(&mut w);
371            let read_fn = match signal.byte_order() {
372                can_dbc::ByteOrder::LittleEndian => {
373                    let (start_bit, end_bit) = le_start_end_bit(signal, msg)?;
374
375                    format!(
376                        "self.raw.view_bits::<Lsb0>()[{start}..{end}].load_le::<{typ}>()",
377                        typ = signal_to_rust_uint(signal),
378                        start = start_bit,
379                        end = end_bit,
380                    )
381                }
382                can_dbc::ByteOrder::BigEndian => {
383                    let (start_bit, end_bit) = be_start_end_bit(signal, msg)?;
384
385                    format!(
386                        "self.raw.view_bits::<Msb0>()[{start}..{end}].load_be::<{typ}>()",
387                        typ = signal_to_rust_uint(signal),
388                        start = start_bit,
389                        end = end_bit
390                    )
391                }
392            };
393
394            writeln!(&mut w, r#"let signal = {};"#, read_fn)?;
395            writeln!(&mut w)?;
396            writeln!(&mut w, "match signal {{")?;
397            {
398                let mut w = PadAdapter::wrap(&mut w);
399                for variant in variants {
400                    let literal = match_on_raw_type(*variant.a());
401                    writeln!(
402                        &mut w,
403                        "{} => {}::{},",
404                        literal,
405                        type_name,
406                        enum_variant_name(variant.b())
407                    )?;
408                }
409                writeln!(
410                    &mut w,
411                    "_ => {}::_Other(self.{}_raw()),",
412                    type_name,
413                    field_name(signal.name())
414                )?;
415            }
416            writeln!(&mut w, "}}")?;
417        }
418        writeln!(&mut w, "}}")?;
419        writeln!(w)?;
420    } else {
421        writeln!(
422            w,
423            "pub fn {}(&self) -> {} {{",
424            field_name(signal.name()),
425            signal_to_rust_type(signal)
426        )?;
427        {
428            let mut w = PadAdapter::wrap(&mut w);
429            writeln!(&mut w, "self.{}_raw()", field_name(signal.name()))?;
430        }
431        writeln!(&mut w, "}}")?;
432        writeln!(w)?;
433    }
434
435    writeln!(w, "/// Get raw value of {}", signal.name())?;
436    writeln!(w, "///")?;
437    writeln!(w, "/// - Start bit: {}", signal.start_bit)?;
438    writeln!(w, "/// - Signal size: {} bits", signal.signal_size)?;
439    writeln!(w, "/// - Factor: {}", signal.factor)?;
440    writeln!(w, "/// - Offset: {}", signal.offset)?;
441    writeln!(w, "/// - Byte order: {:?}", signal.byte_order())?;
442    writeln!(w, "/// - Value type: {:?}", signal.value_type())?;
443    writeln!(w, "#[inline(always)]")?;
444    writeln!(
445        w,
446        "pub fn {}_raw(&self) -> {} {{",
447        field_name(signal.name()),
448        signal_to_rust_type(signal)
449    )?;
450    {
451        let mut w = PadAdapter::wrap(&mut w);
452        signal_from_payload(&mut w, signal, msg).context("signal from payload")?;
453    }
454    writeln!(&mut w, "}}")?;
455    writeln!(w)?;
456
457    render_set_signal(&mut w, signal, msg)?;
458
459    Ok(())
460}
461
462fn render_set_signal(mut w: impl Write, signal: &Signal, msg: &Message) -> Result<()> {
463    writeln!(&mut w, "/// Set value of {}", signal.name())?;
464    writeln!(w, "#[inline(always)]")?;
465
466    // To avoid accidentially changing the multiplexor value without changing
467    // the signals accordingly this fn is kept private for multiplexors.
468    let visibility = if *signal.multiplexer_indicator() == MultiplexIndicator::Multiplexor {
469        ""
470    } else {
471        "pub "
472    };
473
474    writeln!(
475        w,
476        "{}fn set_{}(&mut self, value: {}) -> Result<(), CanError> {{",
477        visibility,
478        field_name(signal.name()),
479        signal_to_rust_type(signal)
480    )?;
481
482    {
483        let mut w = PadAdapter::wrap(&mut w);
484
485        if signal.signal_size != 1 {
486            writeln!(w, r##"#[cfg(feature = "range_checked")]"##)?;
487            writeln!(
488                w,
489                r##"if value < {min}_{typ} || {max}_{typ} < value {{"##,
490                typ = signal_to_rust_type(signal),
491                min = signal.min(),
492                max = signal.max(),
493            )?;
494            {
495                let mut w = PadAdapter::wrap(&mut w);
496                writeln!(
497                    w,
498                    r##"return Err(CanError::ParameterOutOfRange {{ message_id: {message_id} }});"##,
499                    message_id = msg.message_id().0,
500                )?;
501            }
502            writeln!(w, r"}}")?;
503        }
504        signal_to_payload(&mut w, signal, msg).context("signal to payload")?;
505    }
506
507    writeln!(&mut w, "}}")?;
508    writeln!(w)?;
509
510    Ok(())
511}
512
513fn render_set_signal_multiplexer(
514    mut w: impl Write,
515    multiplexor: &Signal,
516    msg: &Message,
517    switch_index: u64,
518) -> Result<()> {
519    writeln!(&mut w, "/// Set value of {}", multiplexor.name())?;
520    writeln!(w, "#[inline(always)]")?;
521    writeln!(
522        w,
523        "pub fn set_{enum_variant_wrapper}(&mut self, value: {enum_variant}) -> Result<(), CanError> {{",
524        enum_variant_wrapper = multiplexed_enum_variant_wrapper_name(switch_index).to_snake_case(),
525        enum_variant = multiplexed_enum_variant_name(msg, multiplexor, switch_index)?,
526    )?;
527
528    {
529        let mut w = PadAdapter::wrap(&mut w);
530
531        writeln!(&mut w, "let b0 = BitArray::<_, LocalBits>::new(self.raw);")?;
532        writeln!(&mut w, "let b1 = BitArray::<_, LocalBits>::new(value.raw);")?;
533        writeln!(&mut w, "self.raw = b0.bitor(b1).into_inner();")?;
534        writeln!(
535            &mut w,
536            "self.set_{}({})?;",
537            field_name(multiplexor.name()),
538            switch_index
539        )?;
540        writeln!(&mut w, "Ok(())",)?;
541    }
542
543    writeln!(&mut w, "}}")?;
544    writeln!(w)?;
545
546    Ok(())
547}
548
549fn render_multiplexor_signal(mut w: impl Write, signal: &Signal, msg: &Message) -> Result<()> {
550    writeln!(w, "/// Get raw value of {}", signal.name())?;
551    writeln!(w, "///")?;
552    writeln!(w, "/// - Start bit: {}", signal.start_bit)?;
553    writeln!(w, "/// - Signal size: {} bits", signal.signal_size)?;
554    writeln!(w, "/// - Factor: {}", signal.factor)?;
555    writeln!(w, "/// - Offset: {}", signal.offset)?;
556    writeln!(w, "/// - Byte order: {:?}", signal.byte_order())?;
557    writeln!(w, "/// - Value type: {:?}", signal.value_type())?;
558    writeln!(w, "#[inline(always)]")?;
559    writeln!(
560        w,
561        "pub fn {}_raw(&self) -> {} {{",
562        field_name(signal.name()),
563        signal_to_rust_type(signal)
564    )?;
565    {
566        let mut w = PadAdapter::wrap(&mut w);
567        signal_from_payload(&mut w, signal, msg).context("signal from payload")?;
568    }
569    writeln!(&mut w, "}}")?;
570    writeln!(w)?;
571
572    writeln!(
573        w,
574        "pub fn {}(&mut self) -> Result<{}, CanError> {{",
575        field_name(signal.name()),
576        multiplex_enum_name(msg, signal)?
577    )?;
578
579    let multiplexer_indexes: BTreeSet<u64> = msg
580        .signals()
581        .iter()
582        .filter_map(|s| {
583            if let MultiplexIndicator::MultiplexedSignal(index) = s.multiplexer_indicator() {
584                Some(index)
585            } else {
586                None
587            }
588        })
589        .cloned()
590        .collect();
591
592    {
593        let mut w = PadAdapter::wrap(&mut w);
594        writeln!(&mut w, "match self.{}_raw() {{", field_name(signal.name()))?;
595
596        {
597            let mut w = PadAdapter::wrap(&mut w);
598            for multiplexer_index in multiplexer_indexes.iter() {
599                writeln!(
600                    &mut w,
601                    "{idx} => Ok({enum_name}::{multiplexed_wrapper_name}({multiplexed_name}{{ raw: self.raw }})),",
602                    idx = multiplexer_index,
603                    enum_name = multiplex_enum_name(msg, signal)?,
604                    multiplexed_wrapper_name = multiplexed_enum_variant_wrapper_name(*multiplexer_index),
605                    multiplexed_name =
606                        multiplexed_enum_variant_name(msg, signal, *multiplexer_index)?
607                )?;
608            }
609            writeln!(
610                &mut w,
611                "multiplexor => Err(CanError::InvalidMultiplexor {{ message_id: {}, multiplexor: multiplexor.into() }}),",
612                msg.message_id().0
613            )?;
614        }
615
616        writeln!(w, "}}")?;
617    }
618    writeln!(w, "}}")?;
619
620    render_set_signal(&mut w, signal, msg)?;
621
622    let mut multiplexed_signals = BTreeMap::new();
623    for signal in msg.signals() {
624        if let MultiplexIndicator::MultiplexedSignal(switch_index) = signal.multiplexer_indicator()
625        {
626            multiplexed_signals
627                .entry(switch_index)
628                .and_modify(|v: &mut Vec<&Signal>| v.push(signal))
629                .or_insert_with(|| vec![signal]);
630        }
631    }
632
633    for switch_index in multiplexer_indexes {
634        render_set_signal_multiplexer(&mut w, signal, msg, switch_index)?;
635    }
636
637    Ok(())
638}
639
640fn be_start_end_bit(signal: &Signal, msg: &Message) -> Result<(u64, u64)> {
641    let err = "calculating start bit";
642
643    let x = signal.start_bit.checked_div(8).context(err)?;
644    let x = x.checked_mul(8).context(err)?;
645
646    let y = signal.start_bit.checked_rem(8).context(err)?;
647    let y = 7u64.checked_sub(y).context(err)?;
648
649    let start_bit = x.checked_add(y).context(err)?;
650    let end_bit = start_bit
651        .checked_add(signal.signal_size)
652        .context("calculating last bit position")?;
653
654    let msg_bits = msg.message_size().checked_mul(8).unwrap();
655
656    ensure!(
657        start_bit <= msg_bits,
658        "signal starts at {}, but message is only {} bits",
659        start_bit,
660        msg_bits
661    );
662    ensure!(
663        end_bit <= msg_bits,
664        "signal ends at {}, but message is only {} bits",
665        end_bit,
666        msg_bits
667    );
668    Ok((start_bit, end_bit))
669}
670
671fn le_start_end_bit(signal: &Signal, msg: &Message) -> Result<(u64, u64)> {
672    let msg_bits = msg.message_size().checked_mul(8).unwrap();
673    let start_bit = signal.start_bit;
674    ensure!(
675        start_bit <= msg_bits,
676        "signal starts at {}, but message is only {} bits",
677        start_bit,
678        msg_bits
679    );
680
681    let end_bit = signal
682        .start_bit
683        .checked_add(signal.signal_size)
684        .context("overflow calculating last bit position")?;
685    ensure!(
686        end_bit <= msg_bits,
687        "signal ends at {}, but message is only {} bits",
688        end_bit,
689        msg_bits
690    );
691    Ok((start_bit, end_bit))
692}
693
694fn signal_from_payload(mut w: impl Write, signal: &Signal, msg: &Message) -> Result<()> {
695    let read_fn = match signal.byte_order() {
696        can_dbc::ByteOrder::LittleEndian => {
697            let (start_bit, end_bit) = le_start_end_bit(signal, msg)?;
698
699            format!(
700                "self.raw.view_bits::<Lsb0>()[{start}..{end}].load_le::<{typ}>()",
701                typ = signal_to_rust_uint(signal),
702                start = start_bit,
703                end = end_bit,
704            )
705        }
706        can_dbc::ByteOrder::BigEndian => {
707            let (start_bit, end_bit) = be_start_end_bit(signal, msg)?;
708
709            format!(
710                "self.raw.view_bits::<Msb0>()[{start}..{end}].load_be::<{typ}>()",
711                typ = signal_to_rust_uint(signal),
712                start = start_bit,
713                end = end_bit
714            )
715        }
716    };
717
718    writeln!(&mut w, r#"let signal = {};"#, read_fn)?;
719    writeln!(&mut w)?;
720
721    if *signal.value_type() == can_dbc::ValueType::Signed {
722        writeln!(
723            &mut w,
724            "let signal  = {}::from_ne_bytes(signal.to_ne_bytes());",
725            signal_to_rust_int(signal)
726        )?;
727    };
728
729    if signal.signal_size == 1 {
730        writeln!(&mut w, "signal == 1")?;
731    } else if signal_is_float_in_rust(signal) {
732        // Scaling is always done on floats
733        writeln!(&mut w, "let factor = {}_f32;", signal.factor)?;
734        writeln!(&mut w, "let offset = {}_f32;", signal.offset)?;
735        writeln!(&mut w, "(signal as f32) * factor + offset")?;
736    } else {
737        writeln!(&mut w, "signal")?;
738    }
739    Ok(())
740}
741
742fn signal_to_payload(mut w: impl Write, signal: &Signal, msg: &Message) -> Result<()> {
743    if signal.signal_size == 1 {
744        // Map boolean to byte so we can pack it
745        writeln!(&mut w, "let value = value as u8;")?;
746    } else if signal_is_float_in_rust(signal) {
747        // Massage value into an int
748        writeln!(&mut w, "let factor = {}_f32;", signal.factor)?;
749        writeln!(&mut w, "let offset = {}_f32;", signal.offset)?;
750        writeln!(
751            &mut w,
752            "let value = ((value - offset) / factor) as {};",
753            signal_to_rust_int(signal)
754        )?;
755        writeln!(&mut w)?;
756    }
757
758    if *signal.value_type() == can_dbc::ValueType::Signed {
759        writeln!(
760            &mut w,
761            "let value = {}::from_ne_bytes(value.to_ne_bytes());",
762            signal_to_rust_uint(signal)
763        )?;
764    };
765
766    match signal.byte_order() {
767        can_dbc::ByteOrder::LittleEndian => {
768            let (start_bit, end_bit) = le_start_end_bit(signal, msg)?;
769            writeln!(
770                &mut w,
771                r#"self.raw.view_bits_mut::<Lsb0>()[{start_bit}..{end_bit}].store_le(value);"#,
772                start_bit = start_bit,
773                end_bit = end_bit,
774            )?;
775        }
776        can_dbc::ByteOrder::BigEndian => {
777            let (start_bit, end_bit) = be_start_end_bit(signal, msg)?;
778            writeln!(
779                &mut w,
780                r#"self.raw.view_bits_mut::<Msb0>()[{start_bit}..{end_bit}].store_be(value);"#,
781                start_bit = start_bit,
782                end_bit = end_bit,
783            )?;
784        }
785    };
786
787    writeln!(&mut w, "Ok(())")?;
788    Ok(())
789}
790
791fn write_enum(
792    mut w: impl Write,
793    signal: &Signal,
794    msg: &Message,
795    variants: &[ValDescription],
796) -> Result<()> {
797    let type_name = enum_name(msg, signal);
798    let signal_rust_type = signal_to_rust_type(signal);
799
800    writeln!(w, "/// Defined values for {}", signal.name())?;
801    writeln!(w, "#[derive(Clone, Copy, PartialEq)]")?;
802    writeln!(w, r##"#[cfg_attr(feature = "debug", derive(Debug))]"##)?;
803    writeln!(w, "pub enum {} {{", type_name)?;
804    {
805        let mut w = PadAdapter::wrap(&mut w);
806        for variant in variants {
807            writeln!(w, "{},", enum_variant_name(variant.b()))?;
808        }
809        writeln!(w, "_Other({}),", signal_rust_type)?;
810    }
811    writeln!(w, "}}")?;
812    writeln!(w)?;
813
814    writeln!(w, "impl From<{type_name}> for {signal_rust_type} {{")?;
815    {
816        let match_on_raw_type = match signal_to_rust_type(signal).as_str() {
817            "bool" => |x: f64| format!("{}", (x as i64) == 1),
818            "f32" => |x: f64| format!("{}_f32", x),
819            _ => |x: f64| format!("{}", x as i64),
820        };
821
822        let mut w = PadAdapter::wrap(&mut w);
823        writeln!(w, "fn from(val: {type_name}) -> {signal_rust_type} {{")?;
824        {
825            let mut w = PadAdapter::wrap(&mut w);
826
827            writeln!(&mut w, "match val {{")?;
828            {
829                let mut w = PadAdapter::wrap(&mut w);
830                for variant in variants {
831                    let literal = match_on_raw_type(*variant.a());
832                    writeln!(
833                        &mut w,
834                        "{}::{} => {},",
835                        type_name,
836                        enum_variant_name(variant.b()),
837                        literal,
838                    )?;
839                }
840                writeln!(&mut w, "{}::_Other(x) => x,", type_name,)?;
841            }
842            writeln!(w, "}}")?;
843        }
844        writeln!(w, "}}")?;
845    }
846    writeln!(w, "}}")?;
847    writeln!(w)?;
848    Ok(())
849}
850
851fn signal_to_rust_int(signal: &Signal) -> String {
852    let sign = match signal.value_type() {
853        can_dbc::ValueType::Signed => "i",
854        can_dbc::ValueType::Unsigned => "u",
855    };
856
857    let size = match *signal.signal_size() {
858        n if n <= 8 => "8",
859        n if n <= 16 => "16",
860        n if n <= 32 => "32",
861        _ => "64",
862    };
863
864    format!("{}{}", sign, size)
865}
866
867fn signal_to_rust_uint(signal: &Signal) -> String {
868    let size = match *signal.signal_size() {
869        n if n <= 8 => "8",
870        n if n <= 16 => "16",
871        n if n <= 32 => "32",
872        _ => "64",
873    };
874
875    format!("u{}", size)
876}
877
878#[allow(clippy::float_cmp)]
879fn signal_is_float_in_rust(signal: &Signal) -> bool {
880    *signal.offset() != 0.0 || *signal.factor() != 1.0
881}
882
883fn signal_to_rust_type(signal: &Signal) -> String {
884    if signal.signal_size == 1 {
885        String::from("bool")
886    } else if signal_is_float_in_rust(signal) {
887        // If there is any scaling needed, go for float
888        String::from("f32")
889    } else {
890        signal_to_rust_int(signal)
891    }
892}
893
894fn type_name(x: &str) -> String {
895    if keywords::is_keyword(x) || !x.starts_with(|c: char| c.is_ascii_alphabetic()) {
896        format!("X{}", x.to_pascal_case())
897    } else {
898        x.to_pascal_case()
899    }
900}
901
902fn field_name(x: &str) -> String {
903    if keywords::is_keyword(x) || !x.starts_with(|c: char| c.is_ascii_alphabetic()) {
904        format!("x{}", x.to_snake_case())
905    } else {
906        x.to_snake_case()
907    }
908}
909
910fn enum_name(msg: &Message, signal: &Signal) -> String {
911    // this turns signal `_4DRIVE` into `4drive`
912    let signal_name = signal
913        .name()
914        .trim_start_matches(|c: char| c.is_ascii_punctuation());
915
916    format!(
917        "{}{}",
918        enum_variant_name(msg.message_name()),
919        signal_name.to_pascal_case()
920    )
921}
922
923fn enum_variant_name(x: &str) -> String {
924    if keywords::is_keyword(x) || !x.starts_with(|c: char| c.is_ascii_alphabetic()) {
925        format!("X{}", x.to_pascal_case())
926    } else {
927        x.to_pascal_case()
928    }
929}
930
931fn multiplexed_enum_variant_wrapper_name(switch_index: u64) -> String {
932    format!("M{}", switch_index)
933}
934
935fn multiplex_enum_name(msg: &Message, multiplexor: &Signal) -> Result<String> {
936    ensure!(
937        matches!(
938            multiplexor.multiplexer_indicator(),
939            MultiplexIndicator::Multiplexor
940        ),
941        "signal {:?} is not the multiplexor",
942        multiplexor
943    );
944    Ok(format!(
945        "{}{}",
946        msg.message_name().to_pascal_case(),
947        multiplexor.name().to_pascal_case()
948    ))
949}
950
951fn multiplexed_enum_variant_name(
952    msg: &Message,
953    multiplexor: &Signal,
954    switch_index: u64,
955) -> Result<String> {
956    ensure!(
957        matches!(
958            multiplexor.multiplexer_indicator(),
959            MultiplexIndicator::Multiplexor
960        ),
961        "signal {:?} is not the multiplexor",
962        multiplexor
963    );
964
965    Ok(format!(
966        "{}{}M{}",
967        msg.message_name().to_pascal_case(),
968        multiplexor.name().to_pascal_case(),
969        switch_index
970    ))
971}
972
973fn render_debug_impl(mut w: impl Write, msg: &Message) -> Result<()> {
974    let typ = type_name(msg.message_name());
975    writeln!(w, r##"#[cfg(feature = "debug")]"##)?;
976    writeln!(w, r##"impl core::fmt::Debug for {} {{"##, typ)?;
977    {
978        let mut w = PadAdapter::wrap(&mut w);
979        writeln!(
980            w,
981            "fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {{"
982        )?;
983        {
984            let mut w = PadAdapter::wrap(&mut w);
985            writeln!(w, r#"if f.alternate() {{"#)?;
986            {
987                let mut w = PadAdapter::wrap(&mut w);
988                writeln!(w, r#"f.debug_struct("{}")"#, typ)?;
989                {
990                    let mut w = PadAdapter::wrap(&mut w);
991                    for signal in msg.signals() {
992                        if *signal.multiplexer_indicator() == MultiplexIndicator::Plain {
993                            writeln!(
994                                w,
995                                r#".field("{field_name}", &self.{field_name}())"#,
996                                field_name = field_name(signal.name()),
997                            )?;
998                        }
999                    }
1000                }
1001                writeln!(w, r#".finish()"#)?;
1002            }
1003            writeln!(w, r#"}} else {{"#)?;
1004            {
1005                let mut w = PadAdapter::wrap(&mut w);
1006                writeln!(w, r#"f.debug_tuple("{}").field(&self.raw).finish()"#, typ)?;
1007            }
1008            writeln!(w, "}}")?;
1009        }
1010        writeln!(w, "}}")?;
1011    }
1012    writeln!(w, "}}")?;
1013    writeln!(w)?;
1014    Ok(())
1015}
1016
1017fn render_multiplexor_enums(
1018    mut w: impl Write,
1019    dbc: &DBC,
1020    msg: &Message,
1021    multiplexor_signal: &Signal,
1022) -> Result<()> {
1023    ensure!(
1024        *multiplexor_signal.multiplexer_indicator() == MultiplexIndicator::Multiplexor,
1025        "signal {} is not the multiplexor",
1026        multiplexor_signal.name(),
1027    );
1028
1029    let mut multiplexed_signals = BTreeMap::new();
1030    for signal in msg.signals() {
1031        if let MultiplexIndicator::MultiplexedSignal(switch_index) = signal.multiplexer_indicator()
1032        {
1033            multiplexed_signals
1034                .entry(switch_index)
1035                .and_modify(|v: &mut Vec<&Signal>| v.push(signal))
1036                .or_insert_with(|| vec![signal]);
1037        }
1038    }
1039
1040    writeln!(
1041        w,
1042        "/// Defined values for multiplexed signal {}",
1043        msg.message_name()
1044    )?;
1045    writeln!(w, r##"#[cfg_attr(feature = "debug", derive(Debug))]"##)?;
1046
1047    writeln!(
1048        w,
1049        "pub enum {} {{",
1050        multiplex_enum_name(msg, multiplexor_signal)?
1051    )?;
1052
1053    {
1054        let mut w = PadAdapter::wrap(&mut w);
1055        for (switch_index, _multiplexed_signals) in multiplexed_signals.iter() {
1056            writeln!(
1057                w,
1058                "{multiplexed_wrapper_name}({multiplexed_name}),",
1059                multiplexed_wrapper_name = multiplexed_enum_variant_wrapper_name(**switch_index),
1060                multiplexed_name =
1061                    multiplexed_enum_variant_name(msg, multiplexor_signal, **switch_index)?
1062            )?;
1063        }
1064    }
1065    writeln!(w, "}}")?;
1066    writeln!(w)?;
1067
1068    for (switch_index, multiplexed_signals) in multiplexed_signals.iter() {
1069        writeln!(w, r##"#[derive(Default)]"##)?;
1070        writeln!(w, r##"#[cfg_attr(feature = "debug", derive(Debug))]"##)?;
1071        let struct_name = multiplexed_enum_variant_name(msg, multiplexor_signal, **switch_index)?;
1072        writeln!(
1073            w,
1074            "pub struct {} {{ raw: [u8; {}] }}",
1075            struct_name,
1076            msg.message_size()
1077        )?;
1078        writeln!(w)?;
1079
1080        writeln!(w, "impl {} {{", struct_name)?;
1081
1082        writeln!(
1083            w,
1084            "pub fn new() -> Self {{ Self {{ raw: [0u8; {}] }} }}",
1085            msg.message_size()
1086        )?;
1087
1088        for signal in multiplexed_signals {
1089            render_signal(&mut w, signal, dbc, msg)?;
1090        }
1091
1092        writeln!(w, "}}")?;
1093        writeln!(w)?;
1094    }
1095
1096    Ok(())
1097}
1098
1099fn render_arbitrary(mut w: impl Write, msg: &Message) -> Result<()> {
1100    writeln!(w, r##"#[cfg(feature = "arb")]"##)?;
1101    writeln!(
1102        w,
1103        "impl<'a> Arbitrary<'a> for {typ} {{",
1104        typ = type_name(msg.message_name())
1105    )?;
1106    {
1107        let mut w = PadAdapter::wrap(&mut w);
1108        writeln!(
1109            w,
1110            "fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self, arbitrary::Error> {{"
1111        )?;
1112        {
1113            let mut w = PadAdapter::wrap(&mut w);
1114            let filtered_signals: Vec<&Signal> = msg
1115                .signals()
1116                .iter()
1117                .filter(|signal| {
1118                    *signal.multiplexer_indicator() == MultiplexIndicator::Plain
1119                        || *signal.multiplexer_indicator() == MultiplexIndicator::Multiplexor
1120                })
1121                .collect();
1122
1123            for signal in filtered_signals.iter() {
1124                writeln!(
1125                    w,
1126                    "let {field_name} = {arbitrary_value};",
1127                    field_name = field_name(signal.name()),
1128                    arbitrary_value = signal_to_arbitrary(signal),
1129                )?;
1130            }
1131
1132            let args: Vec<String> = filtered_signals
1133                .iter()
1134                .map(|signal| field_name(signal.name()))
1135                .collect();
1136
1137            writeln!(
1138                w,
1139                "{typ}::new({args}).map_err(|_| arbitrary::Error::IncorrectFormat)",
1140                typ = type_name(msg.message_name()),
1141                args = args.join(",")
1142            )?;
1143        }
1144        writeln!(w, "}}")?;
1145    }
1146    writeln!(w, "}}")?;
1147
1148    Ok(())
1149}
1150
1151fn signal_to_arbitrary(signal: &Signal) -> String {
1152    if signal.signal_size == 1 {
1153        "u.int_in_range(0..=1)? == 1".to_string()
1154    } else if signal_is_float_in_rust(signal) {
1155        format!(
1156            "u.float_in_range({min}_f32..={max}_f32)?",
1157            min = signal.min(),
1158            max = signal.max()
1159        )
1160    } else {
1161        format!(
1162            "u.int_in_range({min}..={max})?",
1163            min = signal.min(),
1164            max = signal.max()
1165        )
1166    }
1167}
1168
1169fn get_relevant_messages(dbc: &DBC) -> impl Iterator<Item = &Message> {
1170    dbc.messages().iter().filter(|m| !message_ignored(m))
1171}
1172
1173fn message_ignored(message: &Message) -> bool {
1174    // DBC internal message containing signals unassigned to any real message
1175    message.message_name() == "VECTOR__INDEPENDENT_SIG_MSG"
1176}