dbc_rs/value_descriptions/
value_descriptions.rs

1use crate::MAX_VALUE_DESCRIPTIONS;
2use std::{string::String, vec::Vec};
3
4/// Value descriptions for a signal.
5///
6/// Maps numeric signal values to human-readable text descriptions.
7/// For example, a gear position signal might map:
8/// - 0 -> "Park"
9/// - 1 -> "Reverse"
10/// - 2 -> "Neutral"
11/// - 3 -> "Drive"
12///
13/// # Examples
14///
15/// ```rust,no_run
16/// use dbc_rs::Dbc;
17///
18/// let dbc_content = r#"VERSION "1.0"
19///
20/// BU_: ECM
21///
22/// BO_ 100 EngineData : 8 ECM
23///  SG_ GearPosition : 0|8@1+ (1,0) [0|5] "" *
24///
25/// VAL_ 100 GearPosition 0 "Park" 1 "Reverse" 2 "Neutral" 3 "Drive" ;
26/// "#;
27///
28/// let dbc = Dbc::parse(dbc_content)?;
29/// let message = dbc.messages().iter().find(|m| m.id() == 100).unwrap();
30/// let signal = message.signals().find("GearPosition").unwrap();
31///
32/// if let Some(value_descriptions) = dbc.value_descriptions_for_signal(message.id(), signal.name()) {
33///     if let Some(description) = value_descriptions.get(0) {
34///         println!("Value 0 means: {}", description);
35///     }
36/// }
37/// # Ok::<(), dbc_rs::Error>(())
38/// ```
39#[derive(Debug, Clone, PartialEq, Eq, Hash)]
40pub struct ValueDescriptions {
41    entries: Vec<(u64, String)>,
42}
43
44impl ValueDescriptions {
45    /// Create ValueDescriptions from a slice of (value, description) pairs
46    pub(crate) fn from_slice(entries: &[(u64, String)]) -> Self {
47        let count = entries.len().min(MAX_VALUE_DESCRIPTIONS);
48        let vec_entries: Vec<(u64, String)> =
49            entries.iter().take(count).map(|(value, desc)| (*value, desc.clone())).collect();
50        Self {
51            entries: vec_entries,
52        }
53    }
54
55    /// Get the description for a numeric value
56    ///
57    /// # Examples
58    ///
59    /// ```rust,no_run
60    /// # use dbc_rs::Dbc;
61    /// # let dbc = Dbc::parse(r#"VERSION "1.0"\n\nBU_: ECM\n\nBO_ 100 Engine : 8 ECM\n SG_ Gear : 0|8@1+ (1,0) [0|5] "" *\n\nVAL_ 100 Gear 0 "Park" 1 "Reverse" ;"#)?;
62    /// # let message = dbc.messages().iter().next().unwrap();
63    /// # let signal = message.signals().iter().next().unwrap();
64    /// if let Some(value_descriptions) = dbc.value_descriptions_for_signal(message.id(), signal.name()) {
65    ///     if let Some(desc) = value_descriptions.get(0) {
66    ///         println!("Value 0: {}", desc);
67    ///     }
68    /// }
69    /// # Ok::<(), dbc_rs::Error>(())
70    /// ```
71    #[must_use]
72    pub fn get(&self, value: u64) -> Option<&str> {
73        for (v, desc) in &self.entries {
74            if *v == value {
75                return Some(desc.as_ref());
76            }
77        }
78        None
79    }
80
81    /// Get the number of value descriptions
82    #[must_use]
83    pub fn len(&self) -> usize {
84        self.entries.len()
85    }
86
87    /// Check if there are any value descriptions
88    #[must_use]
89    pub fn is_empty(&self) -> bool {
90        self.entries.is_empty()
91    }
92
93    /// Iterate over all value descriptions
94    ///
95    /// # Examples
96    ///
97    /// ```rust,no_run
98    /// # use dbc_rs::Dbc;
99    /// # let dbc = Dbc::parse(r#"VERSION "1.0"\n\nBU_: ECM\n\nBO_ 100 Engine : 8 ECM\n SG_ Gear : 0|8@1+ (1,0) [0|5] "" *\n\nVAL_ 100 Gear 0 "Park" 1 "Reverse" ;"#)?;
100    /// # let message = dbc.messages().iter().next().unwrap();
101    /// # let signal = message.signals().iter().next().unwrap();
102    /// if let Some(value_descriptions) = dbc.value_descriptions_for_signal(message.id(), signal.name()) {
103    ///     for (value, description) in value_descriptions.iter() {
104    ///         println!("{} -> {}", value, description);
105    ///     }
106    /// }
107    /// # Ok::<(), dbc_rs::Error>(())
108    /// ```
109    pub fn iter(&self) -> ValueDescriptionsIter<'_> {
110        ValueDescriptionsIter {
111            entries: &self.entries,
112            pos: 0,
113        }
114    }
115}
116
117/// Iterator over value descriptions
118pub struct ValueDescriptionsIter<'a> {
119    entries: &'a [(u64, String)],
120    pos: usize,
121}
122
123impl<'a> Iterator for ValueDescriptionsIter<'a> {
124    type Item = (u64, String);
125
126    fn next(&mut self) -> Option<Self::Item> {
127        if self.pos < self.entries.len() {
128            let entry = &self.entries[self.pos];
129            let result = (entry.0, entry.1.clone());
130            self.pos += 1;
131            Some(result)
132        } else {
133            None
134        }
135    }
136}