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}