can_dbc/
lib.rs

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