modbus_rtu/slave/data_model/
mod.rs

1mod structure;      pub use structure::DataStructure;
2
3
4/// A data model for accessing values stored at unique 16-bit addresses.
5/// 
6/// ---
7/// # Examples
8/// ```
9/// use modbus_rtu::slave::{DataModel, DataStructure};
10/// 
11/// // Define data structure first.
12/// const DATA_STRUCTURE: DataStructure<4> = DataStructure::new([
13///     0x0001,
14///     0x0002,
15///     0x1234,
16///     0x5678,
17/// ]);
18/// 
19/// // And create a new data model instance with initial value array.
20/// let data_model = DataModel::new(&DATA_STRUCTURE, [0; 4]);
21/// ```
22/// 
23#[derive(Debug)]
24pub struct DataModel<const L: usize, T: Copy> {
25    /// The data structure defined as a constant at compile time.
26    /// The data model conforms to this structure.
27    /// 
28    structure: &'static DataStructure<L>,
29
30    /// The list of values being stored.
31    /// It is stored in the same form as the data structure.
32    values: [T; L],
33}
34
35
36impl<const L: usize, T: Copy> DataModel<L, T> {
37    /// Creates and initializes a new data model using the given data structure.
38    ///
39    /// ---
40    /// # Arguments
41    /// - `structure`: A reference to the constant data structure.
42    /// - `initial_values`: The initial values to populate the data model.
43    ///
44    /// ---
45    /// # Returns
46    /// A new `DataModel` instance initialized with the provided structure and values.
47    /// 
48    /// ---
49    /// # Examples
50    /// ```
51    /// use modbus_rtu::slave::{DataModel, DataStructure};
52    /// 
53    /// const STRUCTURE: DataStructure<5> = DataStructure::new([
54    ///     0x0000,
55    ///     0x0001,
56    ///     0x0002,
57    ///     0x1234,
58    ///     0x5678,
59    /// ]);
60    /// 
61    /// let data_model = DataModel::new(&STRUCTURE, [0; 5]);
62    /// ```
63    /// 
64    pub fn new(structure: &'static DataStructure<L>, initial_values: [T; L]) -> DataModel<L, T> {
65        Self { structure, values: initial_values }
66    }
67
68    /// Retrieves a value from the data model by using an address defined in the associated data structure.
69    ///
70    /// This method uses the address defined in the data structure to access the corresponding value
71    /// stored within the data model.
72    /// 
73    /// ---
74    /// # Arguments
75    /// - `address`: The address of the value to retrieve. Only addresses defined in the data structure are allowed.
76    /// 
77    /// ---
78    /// # Returns
79    /// The value stored at the specified address.
80    /// 
81    /// ---
82    /// # Examples
83    /// ```
84    /// use modbus_rtu::slave::{DataModel, DataStructure};
85    /// 
86    /// const STRUCTURE: DataStructure<5> = DataStructure::new([
87    ///     0x0000,
88    ///     0x0001,
89    ///     0x0002,
90    ///     0x1234,
91    ///     0x5678,
92    /// ]);
93    /// 
94    /// let data_model = DataModel::new(&STRUCTURE, [0; 5]);
95    /// 
96    /// assert_eq!(data_model.get_value(0x0001), 0);
97    /// ```
98    /// 
99    /// The code below will panic at compile time.
100    /// ```should_panic
101    /// # use modbus_rtu::slave::{DataModel, DataStructure};
102    /// # const STRUCTURE: DataStructure<5> = DataStructure::new([
103    /// #     0x0000,
104    /// #     0x0001,
105    /// #     0x0002,
106    /// #     0x1234,
107    /// #     0x5678,
108    /// # ]);
109    /// # let data_model = DataModel::new(&STRUCTURE, [0; 5]);
110    /// // Will panic!!
111    /// let value = data_model.get_value(0x0003);
112    /// ```
113    /// 
114    /// ---
115    /// # Panics
116    /// ...
117    /// 
118    pub const fn get_value(&self, address: u16) -> T {
119        let index = self.structure.get(address);
120        self.values[index]
121    }
122
123    /// Retrieves a value from the data model using a given address, if it exists in the structure.
124    ///
125    /// Unlike `get_value`, this method returns `None` instead of panicking if the address is not part of the structure.
126    /// This makes it suitable for use with dynamic or external input.
127    ///
128    /// ---
129    /// # Arguments
130    /// - `address`: The address of the value to look up. The address may or may not be defined in the structure.
131    ///
132    /// ---
133    /// # Returns
134    /// An `Option<T>` containing the value if the address is found, or `None` if it is not.
135    ///
136    /// ---
137    /// # Examples
138    /// ```
139    /// use modbus_rtu::slave::{DataModel, DataStructure};
140    ///
141    /// const STRUCTURE: DataStructure<5> = DataStructure::new([
142    ///     0x0000,
143    ///     0x0001,
144    ///     0x0002,
145    ///     0x1234,
146    ///     0x5678,
147    /// ]);
148    ///
149    /// let data_model = DataModel::new(&STRUCTURE, [10, 20, 30, 40, 50]);
150    ///
151    /// assert_eq!(data_model.find_value(0x0002), Some(30));
152    /// assert_eq!(data_model.find_value(0x9999), None);
153    /// ```
154    /// 
155    pub fn find_value(&self, address: u16) -> Option<T> {
156        let index = self.structure.find(address)?;
157        Some(self.values[index])
158    }
159
160    /// Checks whether the data model is empty.
161    ///
162    /// This returns `true` if the data model contains no entries, which occurs when its length `L` is zero.
163    ///
164    /// ---
165    /// # Returns
166    /// `true` if the data model is empty, `false` otherwise.
167    ///
168    /// ---
169    /// # Examples
170    /// ```
171    /// use modbus_rtu::slave::DataModel;
172    ///
173    /// let empty_model = DataModel::<0, u16>::empty();
174    /// assert!(empty_model.is_empty());
175    /// ```
176    ///
177    pub fn is_empty(&self) -> bool {
178        L == 0
179    }
180}
181
182
183impl<T: Copy> DataModel<0, T> {
184    /// Creates and returns an empty data model with no stored values.
185    ///
186    /// This is useful when a data model is required but no data is needed or used.
187    ///
188    /// ---
189    /// # Returns
190    /// An empty `DataModel` instance with no associated data.
191    ///
192    /// ---
193    /// # Examples
194    /// ```
195    /// use modbus_rtu::slave::{ModbusSlave, DataModel};
196    ///
197    /// let holding_registers = DataModel::empty();
198    /// let input_registers = DataModel::empty();
199    /// 
200    /// // Create modbus slave instance with zero registers
201    /// let modbus_slave = ModbusSlave::new(0x01, holding_registers, input_registers);
202    /// ```
203    ///
204    pub fn empty() -> DataModel<0, T> {
205        DataModel { structure: &DataStructure::EMPTY, values: [] }
206    }
207}