1use crate::{ClientError, InvalidResponseKind};
2
3#[derive(Debug, Clone, PartialEq, Eq)]
8pub struct CoilPoints {
9 start_address: u16,
10 values: Vec<bool>,
11}
12
13impl CoilPoints {
14 #[must_use]
16 pub fn new(start_address: u16, count: usize) -> Self {
17 Self {
18 start_address,
19 values: vec![false; count],
20 }
21 }
22
23 #[must_use]
25 pub fn from_values(start_address: u16, values: Vec<bool>) -> Self {
26 Self {
27 start_address,
28 values,
29 }
30 }
31
32 pub fn start_address(&self) -> u16 {
34 self.start_address
35 }
36
37 pub fn len(&self) -> usize {
39 self.values.len()
40 }
41
42 pub fn is_empty(&self) -> bool {
44 self.values.is_empty()
45 }
46
47 pub fn values(&self) -> &[bool] {
49 &self.values
50 }
51
52 pub fn get(&self, address: u16) -> Option<bool> {
54 let offset = usize::from(address.checked_sub(self.start_address)?);
55 self.values.get(offset).copied()
56 }
57
58 pub fn set(&mut self, address: u16, value: bool) -> Result<(), ClientError> {
60 let offset = usize::from(
61 address
62 .checked_sub(self.start_address)
63 .ok_or(ClientError::InvalidResponse(InvalidResponseKind::Other("coil address out of range")))?,
64 );
65 let slot = self
66 .values
67 .get_mut(offset)
68 .ok_or(ClientError::InvalidResponse(InvalidResponseKind::Other("coil address out of range")))?;
69 *slot = value;
70 Ok(())
71 }
72
73 pub fn apply_read(&mut self, start_address: u16, values: &[bool]) -> Result<(), ClientError> {
75 for (i, value) in values.iter().copied().enumerate() {
76 let offset = u16::try_from(i)
77 .map_err(|_| ClientError::InvalidResponse(InvalidResponseKind::Other("coil address overflow")))?;
78 let addr = start_address
79 .checked_add(offset)
80 .ok_or(ClientError::InvalidResponse(InvalidResponseKind::Other("coil address overflow")))?;
81 self.set(addr, value)?;
82 }
83 Ok(())
84 }
85}
86
87#[derive(Debug, Clone, PartialEq, Eq)]
92pub struct RegisterPoints {
93 start_address: u16,
94 values: Vec<u16>,
95}
96
97impl RegisterPoints {
98 #[must_use]
100 pub fn new(start_address: u16, count: usize) -> Self {
101 Self {
102 start_address,
103 values: vec![0; count],
104 }
105 }
106
107 #[must_use]
109 pub fn from_values(start_address: u16, values: Vec<u16>) -> Self {
110 Self {
111 start_address,
112 values,
113 }
114 }
115
116 pub fn start_address(&self) -> u16 {
118 self.start_address
119 }
120
121 pub fn len(&self) -> usize {
123 self.values.len()
124 }
125
126 pub fn is_empty(&self) -> bool {
128 self.values.is_empty()
129 }
130
131 pub fn values(&self) -> &[u16] {
133 &self.values
134 }
135
136 pub fn get(&self, address: u16) -> Option<u16> {
138 let offset = usize::from(address.checked_sub(self.start_address)?);
139 self.values.get(offset).copied()
140 }
141
142 pub fn set(&mut self, address: u16, value: u16) -> Result<(), ClientError> {
144 let offset = usize::from(
145 address
146 .checked_sub(self.start_address)
147 .ok_or(ClientError::InvalidResponse(InvalidResponseKind::Other("register address out of range")))?,
148 );
149 let slot = self
150 .values
151 .get_mut(offset)
152 .ok_or(ClientError::InvalidResponse(InvalidResponseKind::Other("register address out of range")))?;
153 *slot = value;
154 Ok(())
155 }
156
157 pub fn apply_read(&mut self, start_address: u16, values: &[u16]) -> Result<(), ClientError> {
159 for (i, value) in values.iter().copied().enumerate() {
160 let offset = u16::try_from(i)
161 .map_err(|_| ClientError::InvalidResponse(InvalidResponseKind::Other("register address overflow")))?;
162 let addr = start_address
163 .checked_add(offset)
164 .ok_or(ClientError::InvalidResponse(InvalidResponseKind::Other("register address overflow")))?;
165 self.set(addr, value)?;
166 }
167 Ok(())
168 }
169}
170
171#[cfg(test)]
172mod tests {
173 use super::{CoilPoints, RegisterPoints};
174
175 #[test]
176 fn coil_points_apply_read() {
177 let mut points = CoilPoints::new(10, 4);
178 points.apply_read(11, &[true, false]).unwrap();
179 assert_eq!(points.get(10), Some(false));
180 assert_eq!(points.get(11), Some(true));
181 assert_eq!(points.get(12), Some(false));
182 }
183
184 #[test]
185 fn register_points_apply_read() {
186 let mut points = RegisterPoints::new(100, 3);
187 points.apply_read(100, &[10, 20, 30]).unwrap();
188 assert_eq!(points.get(101), Some(20));
189 points.set(102, 42).unwrap();
190 assert_eq!(points.get(102), Some(42));
191 }
192}