dbc_rs/value_descriptions/
value_descriptions.rs

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