dbc_rs/value_descriptions/value_descriptions_builder.rs
1use crate::compat::{Box, String, Vec, str_to_string};
2use crate::value_descriptions::{MAX_VALUE_DESCRIPTIONS, ValueDescriptions};
3use crate::{Error, Result};
4
5/// Builder for creating `ValueDescriptions` programmatically.
6///
7/// This builder allows you to construct value descriptions when building DBC files
8/// programmatically. It validates that entries are within limits.
9///
10/// # Examples
11///
12/// ```rust,no_run
13/// use dbc_rs::ValueDescriptionsBuilder;
14///
15/// let value_descriptions = ValueDescriptionsBuilder::new()
16/// .add_entry(0, "Park")
17/// .add_entry(1, "Reverse")
18/// .add_entry(2, "Neutral")
19/// .add_entry(3, "Drive")
20/// .build()?;
21///
22/// assert_eq!(value_descriptions.get(0), Some("Park"));
23/// assert_eq!(value_descriptions.get(1), Some("Reverse"));
24/// # Ok::<(), dbc_rs::Error>(())
25/// ```
26///
27/// # Validation
28///
29/// The builder validates:
30/// - Maximum of 64 value descriptions (MAX_VALUE_DESCRIPTIONS)
31///
32/// # Feature Requirements
33///
34/// This builder requires the `alloc` or `kernel` feature to be enabled.
35#[derive(Debug, Clone, Default)]
36pub struct ValueDescriptionsBuilder {
37 entries: Vec<(u64, String)>,
38}
39
40impl ValueDescriptionsBuilder {
41 /// Creates a new `ValueDescriptionsBuilder` with an empty entry list.
42 ///
43 /// # Examples
44 ///
45 /// ```rust,no_run
46 /// use dbc_rs::ValueDescriptionsBuilder;
47 ///
48 /// let builder = ValueDescriptionsBuilder::new();
49 /// let value_descriptions = builder.build()?;
50 /// assert!(value_descriptions.is_empty());
51 /// # Ok::<(), dbc_rs::Error>(())
52 /// ```
53 pub fn new() -> Self {
54 Self::default()
55 }
56
57 /// Adds a value-description pair to the builder.
58 ///
59 /// # Arguments
60 ///
61 /// * `value` - The numeric value (u64)
62 /// * `description` - The human-readable description
63 ///
64 /// # Examples
65 ///
66 /// ```rust,no_run
67 /// use dbc_rs::ValueDescriptionsBuilder;
68 ///
69 /// let builder = ValueDescriptionsBuilder::new()
70 /// .add_entry(0, "Off")
71 /// .add_entry(1, "On");
72 /// # Ok::<(), dbc_rs::Error>(())
73 /// ```
74 #[must_use]
75 pub fn add_entry(mut self, value: u64, description: impl AsRef<str>) -> Self {
76 if self.entries.len() < MAX_VALUE_DESCRIPTIONS {
77 self.entries.push((value, str_to_string(description)));
78 }
79 self
80 }
81
82 /// Builds the `ValueDescriptions` from the builder.
83 ///
84 /// # Errors
85 ///
86 /// Returns an error if the number of entries exceeds the maximum allowed.
87 ///
88 /// # Examples
89 ///
90 /// ```rust,no_run
91 /// use dbc_rs::ValueDescriptionsBuilder;
92 ///
93 /// let value_descriptions = ValueDescriptionsBuilder::new()
94 /// .add_entry(0, "Park")
95 /// .add_entry(1, "Drive")
96 /// .build()?;
97 /// # Ok::<(), dbc_rs::Error>(())
98 /// ```
99 pub fn build(self) -> Result<ValueDescriptions<'static>> {
100 if self.entries.len() > MAX_VALUE_DESCRIPTIONS {
101 return Err(Error::InvalidData(crate::error::str_to_error_string(
102 "Too many value descriptions",
103 )));
104 }
105
106 // Convert Vec<(u64, String)> to Vec<(u64, &'static str)>
107 // We need to leak the strings to get 'static lifetime
108 let mut static_entries: Vec<(u64, &'static str)> = Vec::new();
109 for (value, description) in self.entries {
110 let boxed: Box<str> = description.into_boxed_str();
111 let leaked: &'static str = Box::leak(boxed);
112 static_entries.push((value, leaked));
113 }
114
115 Ok(ValueDescriptions::from_slice(&static_entries))
116 }
117}