can_dbc/
lib.rs

1//!
2//! A CAN database (dbc) format parser written with Rust's nom parser combinator library.
3//! CAN databases are used to exchange details about a CAN network.
4//! E.g. what messages are being send over the CAN bus and what data do they contain.
5//!
6//! ```rust
7//! use can_dbc::DBC;
8//! use codegen::Scope;
9//!
10//! use std::fs::File;
11//! use std::io;
12//! use std::io::prelude::*;
13//!
14//! fn main() -> io::Result<()> {
15//!     let mut f = File::open("./examples/sample.dbc")?;
16//!     let mut buffer = Vec::new();
17//!     f.read_to_end(&mut buffer)?;
18//!
19//!     let dbc = can_dbc::DBC::from_slice(&buffer).expect("Failed to parse dbc file");
20//!
21//!     let mut scope = Scope::new();
22//!     for message in dbc.messages() {
23//!         for signal in message.signals() {
24//!
25//!             let mut scope = Scope::new();
26//!             let message_struct = scope.new_struct(message.message_name());
27//!             for signal in message.signals() {
28//!                 message_struct.field(signal.name().to_lowercase().as_str(), "f64");
29//!             }
30//!         }
31//!     }
32//!
33//!     println!("{}", scope.to_string());
34//!     Ok(())
35//! }
36//! ```
37
38#[cfg(feature = "with-serde")]
39extern crate serde;
40#[cfg(feature = "with-serde")]
41#[macro_use]
42extern crate serde_derive;
43
44use std::convert::TryFrom;
45
46use derive_getters::Getters;
47
48pub mod parser;
49
50#[cfg(test)]
51mod tests {
52
53    use super::*;
54
55    const SAMPLE_DBC: &str = r#"
56VERSION "0.1"
57NS_ :
58    NS_DESC_
59    CM_
60    BA_DEF_
61    BA_
62    VAL_
63    CAT_DEF_
64    CAT_
65    FILTER
66    BA_DEF_DEF_
67    EV_DATA_
68    ENVVAR_DATA_
69    SGTYPE_
70    SGTYPE_VAL_
71    BA_DEF_SGTYPE_
72    BA_SGTYPE_
73    SIG_TYPE_REF_
74    VAL_TABLE_
75    SIG_GROUP_
76    SIG_VALTYPE_
77    SIGTYPE_VALTYPE_
78    BO_TX_BU_
79    BA_DEF_REL_
80    BA_REL_
81    BA_DEF_DEF_REL_
82    BU_SG_REL_
83    BU_EV_REL_
84    BU_BO_REL_
85    SG_MUL_VAL_
86BS_:
87BU_: PC
88BO_ 2000 WebData_2000: 4 Vector__XXX
89    SG_ Signal_8 : 24|8@1+ (1,0) [0|255] "" Vector__XXX
90    SG_ Signal_7 : 16|8@1+ (1,0) [0|255] "" Vector__XXX
91    SG_ Signal_6 : 8|8@1+ (1,0) [0|255] "" Vector__XXX
92    SG_ Signal_5 : 0|8@1+ (1,0) [0|255] "" Vector__XXX
93BO_ 1840 WebData_1840: 4 PC
94    SG_ Signal_4 : 24|8@1+ (1,0) [0|255] "" Vector__XXX
95    SG_ Signal_3 : 16|8@1+ (1,0) [0|255] "" Vector__XXX
96    SG_ Signal_2 : 8|8@1+ (1,0) [0|255] "" Vector__XXX
97    SG_ Signal_1 : 0|8@1+ (1,0) [0|0] "" Vector__XXX
98
99BO_ 3040 WebData_3040: 8 Vector__XXX
100    SG_ Signal_6 m2 : 0|4@1+ (1,0) [0|15] "" Vector__XXX
101    SG_ Signal_5 m3 : 16|8@1+ (1,0) [0|255] "kmh" Vector__XXX
102    SG_ Signal_4 m3 : 8|8@1+ (1,0) [0|255] "" Vector__XXX
103    SG_ Signal_3 m3 : 0|4@1+ (1,0) [0|3] "" Vector__XXX
104    SG_ Signal_2 m1 : 3|12@0+ (1,0) [0|4095] "Byte" Vector__XXX
105    SG_ Signal_1 m0 : 0|4@1+ (1,0) [0|7] "Byte" Vector__XXX
106    SG_ Switch M : 4|4@1+ (1,0) [0|3] "" Vector__XXX
107
108EV_ Environment1: 0 [0|220] "" 0 6 DUMMY_NODE_VECTOR0 DUMMY_NODE_VECTOR2;
109EV_ Environment2: 0 [0|177] "" 0 7 DUMMY_NODE_VECTOR1 DUMMY_NODE_VECTOR2;
110ENVVAR_DATA_ SomeEnvVarData: 399;
111
112CM_ BO_ 1840 "Some Message comment";
113CM_ SG_ 1840 Signal_4 "asaklfjlsdfjlsdfgls
114HH?=(%)/&KKDKFSDKFKDFKSDFKSDFNKCnvsdcvsvxkcv";
115CM_ SG_ 5 TestSigLittleUnsigned1 "asaklfjlsdfjlsdfgls
116=0943503450KFSDKFKDFKSDFKSDFNKCnvsdcvsvxkcv";
117
118BA_DEF_DEF_ "BusType" "AS";
119
120BA_ "Attr" BO_ 4358435 283;
121BA_ "Attr" BO_ 56949545 344;
122
123VAL_ 2000 Signal_3 255 "NOP";
124
125SIG_VALTYPE_ 2000 Signal_8 : 1;
126"#;
127
128    #[test]
129    fn dbc_definition_test() {
130        match DBC::try_from(SAMPLE_DBC) {
131            Ok(dbc_content) => println!("DBC Content{:#?}", dbc_content),
132            Err(e) => {
133                match e {
134                    Error::Nom(nom::Err::Incomplete(needed)) => {
135                        eprintln!("Error incomplete input, needed: {:?}", needed)
136                    }
137                    Error::Nom(nom::Err::Error(error)) => {
138                        eprintln!("Nom Error: {:?}", error);
139                    }
140                    Error::Nom(nom::Err::Failure(ctx)) => eprintln!("Failure {:?}", ctx),
141                    Error::Incomplete(dbc, remaining) => eprintln!(
142                        "Not all data in buffer was read {:#?}, remaining unparsed: {}",
143                        dbc, remaining
144                    ),
145                    Error::MultipleMultiplexors => eprintln!("Multiple multiplexors defined"),
146                }
147                panic!("Failed to read DBC");
148            }
149        }
150    }
151
152    #[test]
153    fn lookup_signal_comment() {
154        let dbc_content = DBC::try_from(SAMPLE_DBC).expect("Failed to parse DBC");
155        let comment = dbc_content
156            .signal_comment(MessageId::Standard(1840), "Signal_4")
157            .expect("Signal comment missing");
158        assert_eq!(
159            "asaklfjlsdfjlsdfgls\nHH?=(%)/&KKDKFSDKFKDFKSDFKSDFNKCnvsdcvsvxkcv",
160            comment
161        );
162    }
163
164    #[test]
165    fn lookup_signal_comment_none_when_missing() {
166        let dbc_content = DBC::try_from(SAMPLE_DBC).expect("Failed to parse DBC");
167        let comment = dbc_content.signal_comment(MessageId::Standard(1840), "Signal_2");
168        assert_eq!(None, comment);
169    }
170
171    #[test]
172    fn lookup_message_comment() {
173        let dbc_content = DBC::try_from(SAMPLE_DBC).expect("Failed to parse DBC");
174        let comment = dbc_content
175            .message_comment(MessageId::Standard(1840))
176            .expect("Message comment missing");
177        assert_eq!("Some Message comment", comment);
178    }
179
180    #[test]
181    fn lookup_message_comment_none_when_missing() {
182        let dbc_content = DBC::try_from(SAMPLE_DBC).expect("Failed to parse DBC");
183        let comment = dbc_content.message_comment(MessageId::Standard(2000));
184        assert_eq!(None, comment);
185    }
186
187    #[test]
188    fn lookup_value_descriptions_for_signal() {
189        let dbc_content = DBC::try_from(SAMPLE_DBC).expect("Failed to parse DBC");
190        let val_descriptions = dbc_content
191            .value_descriptions_for_signal(MessageId::Standard(2000), "Signal_3")
192            .expect("Message comment missing");
193
194        let exp = vec![ValDescription {
195            a: 255.0,
196            b: "NOP".to_string(),
197        }];
198        assert_eq!(exp, val_descriptions);
199    }
200
201    #[test]
202    fn lookup_value_descriptions_for_signal_none_when_missing() {
203        let dbc_content = DBC::try_from(SAMPLE_DBC).expect("Failed to parse DBC");
204        let val_descriptions =
205            dbc_content.value_descriptions_for_signal(MessageId::Standard(2000), "Signal_2");
206        assert_eq!(None, val_descriptions);
207    }
208
209    #[test]
210    fn lookup_extended_value_type_for_signal() {
211        let dbc_content = DBC::try_from(SAMPLE_DBC).expect("Failed to parse DBC");
212        let extended_value_type =
213            dbc_content.extended_value_type_for_signal(MessageId::Standard(2000), "Signal_8");
214        assert_eq!(
215            extended_value_type,
216            Some(&SignalExtendedValueType::IEEEfloat32Bit)
217        );
218    }
219
220    #[test]
221    fn lookup_extended_value_type_for_signal_none_when_missing() {
222        let dbc_content = DBC::try_from(SAMPLE_DBC).expect("Failed to parse DBC");
223        let extended_value_type =
224            dbc_content.extended_value_type_for_signal(MessageId::Standard(2000), "Signal_1");
225        assert_eq!(extended_value_type, None);
226    }
227
228    #[test]
229    fn lookup_signal_by_name() {
230        let dbc_content = DBC::try_from(SAMPLE_DBC).expect("Failed to parse DBC");
231        let signal = dbc_content.signal_by_name(MessageId::Standard(2000), "Signal_8");
232        assert!(signal.is_some());
233    }
234
235    #[test]
236    fn lookup_signal_by_name_none_when_missing() {
237        let dbc_content = DBC::try_from(SAMPLE_DBC).expect("Failed to parse DBC");
238        let signal = dbc_content.signal_by_name(MessageId::Standard(2000), "Signal_25");
239        assert_eq!(signal, None);
240    }
241
242    #[test]
243    fn lookup_multiplex_indicator_switch() {
244        let dbc_content = DBC::try_from(SAMPLE_DBC).expect("Failed to parse DBC");
245        let multiplexor_switch = dbc_content.message_multiplexor_switch(MessageId::Standard(3040));
246        assert!(multiplexor_switch.is_ok());
247        assert!(multiplexor_switch.as_ref().unwrap().is_some());
248        assert_eq!(multiplexor_switch.unwrap().unwrap().name(), "Switch");
249    }
250
251    #[test]
252    fn lookup_multiplex_indicator_switch_none_when_missing() {
253        let dbc_content = DBC::try_from(SAMPLE_DBC).expect("Failed to parse DBC");
254        let multiplexor_switch = dbc_content.message_multiplexor_switch(MessageId::Standard(1840));
255        assert!(multiplexor_switch.unwrap().is_none());
256    }
257
258    #[test]
259    fn extended_message_id_raw() {
260        let message_id = MessageId::Extended(2);
261        assert_eq!(message_id.raw(), 2 | 1 << 31);
262        let message_id = MessageId::Extended(2 ^ 29);
263        assert_eq!(message_id.raw(), 2 ^ 29 | 1 << 31);
264    }
265
266    #[test]
267    fn standard_message_id_raw() {
268        let message_id = MessageId::Standard(2);
269        assert_eq!(message_id.raw(), 2);
270    }
271}
272
273/// Possible error cases for `can-dbc`
274#[allow(clippy::large_enum_variant)]
275#[derive(Debug)]
276pub enum Error<'a> {
277    /// Remaining String, the DBC was only read partially.
278    /// Occurs when e.g. an unexpected symbol occurs.
279    Incomplete(DBC, &'a str),
280    /// Parser failed
281    Nom(nom::Err<nom::error::Error<&'a str>>),
282    /// Can't Lookup multiplexors because the message uses extended multiplexing.
283    MultipleMultiplexors,
284}
285
286/// Baudrate of network in kbit/s
287#[derive(Copy, Clone, Debug, PartialEq)]
288#[cfg_attr(feature = "serde", derive(Serialize))]
289pub struct Baudrate(u64);
290
291/// One or multiple signals are the payload of a CAN frame.
292/// To determine the actual value of a signal the following fn applies:
293/// `let fnvalue = |can_signal_value| -> can_signal_value * factor + offset;`
294#[derive(Clone, Debug, PartialEq, Getters)]
295#[cfg_attr(feature = "serde", derive(Serialize))]
296pub struct Signal {
297    name: String,
298    multiplexer_indicator: MultiplexIndicator,
299    pub start_bit: u64,
300    pub signal_size: u64,
301    byte_order: ByteOrder,
302    value_type: ValueType,
303    pub factor: f64,
304    pub offset: f64,
305    pub min: f64,
306    pub max: f64,
307    unit: String,
308    receivers: Vec<String>,
309}
310
311/// CAN id in header of CAN frame.
312/// Must be unique in DBC file.
313#[derive(Copy, Clone, Debug, PartialEq)]
314#[cfg_attr(feature = "serde", derive(Serialize))]
315pub enum MessageId {
316    Standard(u16),
317    /// 29 bit extended identifier without the extended bit.
318    /// For the raw value of the message id including the bit for extended identifiers use the `raw()` method.
319    Extended(u32),
320}
321
322impl MessageId {
323    /// Raw value of the message id including the bit for extended identifiers
324    pub fn raw(&self) -> u32 {
325        match self {
326            MessageId::Standard(id) => *id as u32,
327            MessageId::Extended(id) => *id | 1 << 31,
328        }
329    }
330}
331
332#[derive(Clone, Debug, PartialEq)]
333#[cfg_attr(feature = "serde", derive(Serialize))]
334pub enum Transmitter {
335    /// node transmitting the message
336    NodeName(String),
337    /// message has no sender
338    VectorXXX,
339}
340
341#[derive(Clone, Debug, PartialEq, Getters)]
342#[cfg_attr(feature = "serde", derive(Serialize))]
343pub struct MessageTransmitter {
344    message_id: MessageId,
345    transmitter: Vec<Transmitter>,
346}
347
348/// Version generated by DB editor
349#[derive(Clone, Debug, PartialEq)]
350#[cfg_attr(feature = "serde", derive(Serialize))]
351pub struct Version(pub String);
352
353#[derive(Clone, Debug, PartialEq)]
354#[cfg_attr(feature = "serde", derive(Serialize))]
355pub struct Symbol(pub String);
356
357#[derive(Copy, Clone, Debug, PartialEq)]
358#[cfg_attr(feature = "serde", derive(Serialize))]
359pub enum MultiplexIndicator {
360    /// Multiplexor switch
361    Multiplexor,
362    /// Signal us being multiplexed by the multiplexer switch.
363    MultiplexedSignal(u64),
364    /// Signal us being multiplexed by the multiplexer switch and itself is a multiplexor
365    MultiplexorAndMultiplexedSignal(u64),
366    /// Normal signal
367    Plain,
368}
369
370#[derive(Copy, Clone, Debug, PartialEq)]
371#[cfg_attr(feature = "serde", derive(Serialize))]
372pub enum ByteOrder {
373    LittleEndian,
374    BigEndian,
375}
376
377#[derive(Copy, Clone, Debug, PartialEq)]
378#[cfg_attr(feature = "serde", derive(Serialize))]
379pub enum ValueType {
380    Signed,
381    Unsigned,
382}
383
384#[derive(Copy, Clone, Debug, PartialEq)]
385#[cfg_attr(feature = "serde", derive(Serialize))]
386pub enum EnvType {
387    EnvTypeFloat,
388    EnvTypeu64,
389    EnvTypeData,
390}
391
392#[derive(Clone, Debug, PartialEq, Getters)]
393#[cfg_attr(feature = "serde", derive(Serialize))]
394pub struct SignalType {
395    signal_type_name: String,
396    signal_size: u64,
397    byte_order: ByteOrder,
398    value_type: ValueType,
399    factor: f64,
400    offset: f64,
401    min: f64,
402    max: f64,
403    unit: String,
404    default_value: f64,
405    value_table: String,
406}
407
408#[derive(Copy, Clone, Debug, PartialEq)]
409#[cfg_attr(feature = "serde", derive(Serialize))]
410pub enum AccessType {
411    DummyNodeVector0,
412    DummyNodeVector1,
413    DummyNodeVector2,
414    DummyNodeVector3,
415}
416
417#[derive(Clone, Debug, PartialEq)]
418#[cfg_attr(feature = "serde", derive(Serialize))]
419pub enum AccessNode {
420    AccessNodeVectorXXX,
421    AccessNodeName(String),
422}
423
424#[derive(Clone, Debug, PartialEq)]
425#[cfg_attr(feature = "serde", derive(Serialize))]
426pub enum SignalAttributeValue {
427    Text(String),
428    Int(i64),
429}
430
431#[derive(Clone, Debug, PartialEq)]
432#[cfg_attr(feature = "serde", derive(Serialize))]
433pub enum AttributeValuedForObjectType {
434    RawAttributeValue(AttributeValue),
435    NetworkNodeAttributeValue(String, AttributeValue),
436    MessageDefinitionAttributeValue(MessageId, Option<AttributeValue>),
437    SignalAttributeValue(MessageId, String, AttributeValue),
438    EnvVariableAttributeValue(String, AttributeValue),
439}
440
441#[derive(Clone, Debug, PartialEq)]
442#[cfg_attr(feature = "serde", derive(Serialize))]
443pub enum AttributeValueType {
444    AttributeValueTypeInt(i64, i64),
445    AttributeValueTypeHex(i64, i64),
446    AttributeValueTypeFloat(f64, f64),
447    AttributeValueTypeString,
448    AttributeValueTypeEnum(Vec<String>),
449}
450
451#[derive(Clone, Debug, PartialEq, Getters)]
452#[cfg_attr(feature = "serde", derive(Serialize))]
453pub struct ValDescription {
454    a: f64,
455    b: String,
456}
457
458#[derive(Clone, Debug, PartialEq, Getters)]
459#[cfg_attr(feature = "serde", derive(Serialize))]
460pub struct AttrDefault {
461    name: String,
462    value: AttributeValue,
463}
464
465#[cfg_attr(feature = "serde", derive(Serialize))]
466#[derive(Clone, Debug, PartialEq)]
467pub enum AttributeValue {
468    AttributeValueU64(u64),
469    AttributeValueI64(i64),
470    AttributeValueF64(f64),
471    AttributeValueCharString(String),
472}
473
474/// Global value table
475#[derive(Clone, Debug, PartialEq, Getters)]
476#[cfg_attr(feature = "serde", derive(Serialize))]
477pub struct ValueTable {
478    value_table_name: String,
479    value_descriptions: Vec<ValDescription>,
480}
481
482#[derive(Clone, Debug, PartialEq, Getters)]
483#[cfg_attr(feature = "serde", derive(Serialize))]
484pub struct ExtendedMultiplexMapping {
485    min_value: u64,
486    max_value: u64,
487}
488/// Mapping between multiplexors and multiplexed signals
489#[derive(Clone, Debug, PartialEq, Getters)]
490#[cfg_attr(feature = "serde", derive(Serialize))]
491pub struct ExtendedMultiplex {
492    message_id: MessageId,
493    signal_name: String,
494    multiplexor_signal_name: String,
495    mappings: Vec<ExtendedMultiplexMapping>,
496}
497
498/// Object comments
499#[derive(Clone, Debug, PartialEq)]
500#[cfg_attr(feature = "serde", derive(Serialize))]
501pub enum Comment {
502    Node {
503        node_name: String,
504        comment: String,
505    },
506    Message {
507        message_id: MessageId,
508        comment: String,
509    },
510    Signal {
511        message_id: MessageId,
512        signal_name: String,
513        comment: String,
514    },
515    EnvVar {
516        env_var_name: String,
517        comment: String,
518    },
519    Plain {
520        comment: String,
521    },
522}
523
524/// CAN message (frame) details including signal details
525#[derive(Clone, Debug, PartialEq, Getters)]
526#[cfg_attr(feature = "serde", derive(Serialize))]
527pub struct Message {
528    /// CAN id in header of CAN frame.
529    /// Must be unique in DBC file.
530    message_id: MessageId,
531    message_name: String,
532    message_size: u64,
533    transmitter: Transmitter,
534    signals: Vec<Signal>,
535}
536
537#[derive(Clone, Debug, PartialEq, Getters)]
538#[cfg_attr(feature = "serde", derive(Serialize))]
539pub struct EnvironmentVariable {
540    env_var_name: String,
541    env_var_type: EnvType,
542    min: i64,
543    max: i64,
544    unit: String,
545    initial_value: f64,
546    ev_id: i64,
547    access_type: AccessType,
548    access_nodes: Vec<AccessNode>,
549}
550
551#[derive(Clone, Debug, PartialEq, Getters)]
552#[cfg_attr(feature = "serde", derive(Serialize))]
553pub struct EnvironmentVariableData {
554    env_var_name: String,
555    data_size: u64,
556}
557
558/// CAN network nodes, names must be unique
559#[derive(Clone, Debug, PartialEq)]
560#[cfg_attr(feature = "serde", derive(Serialize))]
561pub struct Node(pub Vec<String>);
562
563#[derive(Clone, Debug, PartialEq, Getters)]
564#[cfg_attr(feature = "serde", derive(Serialize))]
565pub struct AttributeDefault {
566    attribute_name: String,
567    attribute_value: AttributeValue,
568}
569
570#[derive(Clone, Debug, PartialEq, Getters)]
571#[cfg_attr(feature = "serde", derive(Serialize))]
572pub struct AttributeValueForObject {
573    attribute_name: String,
574    attribute_value: AttributeValuedForObjectType,
575}
576
577#[derive(Clone, Debug, PartialEq)]
578#[cfg_attr(feature = "serde", derive(Serialize))]
579pub enum AttributeDefinition {
580    // TODO add properties
581    Message(String),
582    // TODO add properties
583    Node(String),
584    // TODO add properties
585    Signal(String),
586    EnvironmentVariable(String),
587    // TODO figure out name
588    Plain(String),
589}
590
591/// Encoding for signal raw values.
592#[derive(Clone, Debug, PartialEq)]
593#[cfg_attr(feature = "serde", derive(Serialize))]
594pub enum ValueDescription {
595    Signal {
596        message_id: MessageId,
597        signal_name: String,
598        value_descriptions: Vec<ValDescription>,
599    },
600    EnvironmentVariable {
601        env_var_name: String,
602        value_descriptions: Vec<ValDescription>,
603    },
604}
605
606#[derive(Clone, Debug, PartialEq, Getters)]
607#[cfg_attr(feature = "serde", derive(Serialize))]
608pub struct SignalTypeRef {
609    message_id: MessageId,
610    signal_name: String,
611    signal_type_name: String,
612}
613
614/// Signal groups define a group of signals within a message
615#[derive(Clone, Debug, PartialEq, Getters)]
616#[cfg_attr(feature = "serde", derive(Serialize))]
617pub struct SignalGroups {
618    message_id: MessageId,
619    signal_group_name: String,
620    repetitions: u64,
621    signal_names: Vec<String>,
622}
623
624#[derive(Copy, Clone, Debug, PartialEq)]
625#[cfg_attr(feature = "serde", derive(Serialize))]
626pub enum SignalExtendedValueType {
627    SignedOrUnsignedInteger,
628    IEEEfloat32Bit,
629    IEEEdouble64bit,
630}
631
632#[derive(Clone, Debug, PartialEq, Getters)]
633#[cfg_attr(feature = "serde", derive(Serialize))]
634pub struct SignalExtendedValueTypeList {
635    message_id: MessageId,
636    signal_name: String,
637    signal_extended_value_type: SignalExtendedValueType,
638}
639
640#[derive(Clone, Debug, PartialEq, Getters)]
641#[cfg_attr(feature = "serde", derive(Serialize))]
642pub struct DBC {
643    /// Version generated by DB editor
644    version: Version,
645    new_symbols: Vec<Symbol>,
646    /// Baud rate of network
647    bit_timing: Option<Vec<Baudrate>>,
648    /// CAN network nodes
649    nodes: Vec<Node>,
650    /// Global value table
651    value_tables: Vec<ValueTable>,
652    /// CAN message (frame) details including signal details
653    messages: Vec<Message>,
654    message_transmitters: Vec<MessageTransmitter>,
655    environment_variables: Vec<EnvironmentVariable>,
656    environment_variable_data: Vec<EnvironmentVariableData>,
657    signal_types: Vec<SignalType>,
658    /// Object comments
659    comments: Vec<Comment>,
660    attribute_definitions: Vec<AttributeDefinition>,
661    // undefined
662    // sigtype_attr_list: SigtypeAttrList,
663    attribute_defaults: Vec<AttributeDefault>,
664    attribute_values: Vec<AttributeValueForObject>,
665    /// Encoding for signal raw values
666    value_descriptions: Vec<ValueDescription>,
667    // obsolete + undefined
668    // category_definitions: Vec<CategoryDefinition>,
669    // obsolete + undefined
670    //categories: Vec<Category>,
671    // obsolete + undefined
672    //filter: Vec<Filter>,
673    signal_type_refs: Vec<SignalTypeRef>,
674    /// Signal groups define a group of signals within a message
675    signal_groups: Vec<SignalGroups>,
676    signal_extended_value_type_list: Vec<SignalExtendedValueTypeList>,
677    /// Extended multiplex attributes
678    extended_multiplex: Vec<ExtendedMultiplex>,
679}
680
681impl DBC {
682    /// Read a DBC from a buffer
683    #[allow(clippy::result_large_err)]
684    pub fn from_slice(buffer: &[u8]) -> Result<DBC, Error> {
685        let dbc_in = std::str::from_utf8(buffer).unwrap();
686        Self::try_from(dbc_in)
687    }
688
689    #[allow(clippy::should_implement_trait)]
690    #[deprecated(since = "4.0.0", note = "please use `DBC::try_from` instead")]
691    #[allow(clippy::result_large_err)]
692    pub fn from_str(dbc_in: &str) -> Result<DBC, Error> {
693        let (remaining, dbc) = parser::dbc(dbc_in).map_err(Error::Nom)?;
694        if !remaining.is_empty() {
695            return Err(Error::Incomplete(dbc, remaining));
696        }
697        Ok(dbc)
698    }
699
700    pub fn signal_by_name(&self, message_id: MessageId, signal_name: &str) -> Option<&Signal> {
701        let message = self
702            .messages
703            .iter()
704            .find(|message| message.message_id == message_id);
705
706        if let Some(message) = message {
707            return message
708                .signals
709                .iter()
710                .find(|signal| signal.name == *signal_name);
711        }
712        None
713    }
714
715    /// Lookup a message comment
716    pub fn message_comment(&self, message_id: MessageId) -> Option<&str> {
717        self.comments
718            .iter()
719            .filter_map(|x| match x {
720                Comment::Message {
721                    message_id: ref x_message_id,
722                    ref comment,
723                } => {
724                    if *x_message_id == message_id {
725                        Some(comment.as_str())
726                    } else {
727                        None
728                    }
729                }
730                _ => None,
731            })
732            .next()
733    }
734
735    /// Lookup a signal comment
736    pub fn signal_comment(&self, message_id: MessageId, signal_name: &str) -> Option<&str> {
737        self.comments
738            .iter()
739            .filter_map(|x| match x {
740                Comment::Signal {
741                    message_id: ref x_message_id,
742                    signal_name: ref x_signal_name,
743                    comment,
744                } => {
745                    if *x_message_id == message_id && x_signal_name == signal_name {
746                        Some(comment.as_str())
747                    } else {
748                        None
749                    }
750                }
751                _ => None,
752            })
753            .next()
754    }
755
756    /// Lookup value descriptions for signal
757    pub fn value_descriptions_for_signal(
758        &self,
759        message_id: MessageId,
760        signal_name: &str,
761    ) -> Option<&[ValDescription]> {
762        self.value_descriptions
763            .iter()
764            .filter_map(|x| match x {
765                ValueDescription::Signal {
766                    message_id: ref x_message_id,
767                    signal_name: ref x_signal_name,
768                    ref value_descriptions,
769                } => {
770                    if *x_message_id == message_id && x_signal_name == signal_name {
771                        Some(value_descriptions.as_slice())
772                    } else {
773                        None
774                    }
775                }
776                _ => None,
777            })
778            .next()
779    }
780
781    /// Lookup the extended value for a given signal
782    pub fn extended_value_type_for_signal(
783        &self,
784        message_id: MessageId,
785        signal_name: &str,
786    ) -> Option<&SignalExtendedValueType> {
787        self.signal_extended_value_type_list
788            .iter()
789            .filter_map(|x| {
790                let SignalExtendedValueTypeList {
791                    message_id: ref x_message_id,
792                    signal_name: ref x_signal_name,
793                    ref signal_extended_value_type,
794                } = x;
795                if *x_message_id == message_id && x_signal_name == signal_name {
796                    Some(signal_extended_value_type)
797                } else {
798                    None
799                }
800            })
801            .next()
802    }
803
804    /// Lookup the message multiplexor switch signal for a given message
805    /// This does not work for extended multiplexed messages, if multiple multiplexors are defined for a message a Error is returned.
806    #[allow(clippy::result_large_err)]
807    pub fn message_multiplexor_switch(
808        &self,
809        message_id: MessageId,
810    ) -> Result<Option<&Signal>, Error> {
811        let message = self
812            .messages
813            .iter()
814            .find(|message| message.message_id == message_id);
815
816        if let Some(message) = message {
817            if self
818                .extended_multiplex
819                .iter()
820                .any(|ext_mp| ext_mp.message_id == message_id)
821            {
822                Err(Error::MultipleMultiplexors)
823            } else {
824                Ok(message
825                    .signals
826                    .iter()
827                    .find(|signal| signal.multiplexer_indicator == MultiplexIndicator::Multiplexor))
828            }
829        } else {
830            Ok(None)
831        }
832    }
833}
834
835impl<'a> TryFrom<&'a str> for DBC {
836    type Error = Error<'a>;
837
838    fn try_from(dbc_in: &'a str) -> Result<Self, Self::Error> {
839        let (remaining, dbc) = parser::dbc(dbc_in).map_err(Error::Nom)?;
840        if !remaining.is_empty() {
841            return Err(Error::Incomplete(dbc, remaining));
842        }
843        Ok(dbc)
844    }
845}