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}