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}