1use regex;
2use std::time::Duration;
3
4pub fn set_bool(
5 bytearray: &mut [u8],
6 byte_index: usize,
7 bool_index: usize,
8 value: bool,
9) -> Result<(), String> {
10 if bool_index > 7 {
11 return Err(format!("bool_index {} out of range", bool_index));
12 }
13
14 let mask = 1 << bool_index;
15 if value {
16 bytearray[byte_index] |= mask;
17 } else {
18 bytearray[byte_index] &= !mask;
19 }
20 Ok(())
21}
22
23pub fn set_byte(bytearray: &mut [u8], byte_index: usize, value: u8) {
24 bytearray[byte_index] = value;
25}
26
27pub fn set_word(bytearray: &mut [u8], byte_index: usize, value: u16) {
28 bytearray[byte_index..byte_index + 2].copy_from_slice(&value.to_be_bytes());
29}
30
31pub fn set_int(bytearray: &mut [u8], byte_index: usize, value: i16) {
32 bytearray[byte_index..byte_index + 2].copy_from_slice(&value.to_be_bytes());
33}
34
35pub fn set_uint(bytearray: &mut [u8], byte_index: usize, value: u16) {
36 bytearray[byte_index..byte_index + 2].copy_from_slice(&value.to_be_bytes());
37}
38
39pub fn set_real(bytearray: &mut [u8], byte_index: usize, value: f32) {
40 bytearray[byte_index..byte_index + 4].copy_from_slice(&value.to_be_bytes());
41}
42
43pub fn set_dword(bytearray: &mut [u8], byte_index: usize, value: u32) {
44 bytearray[byte_index..byte_index + 4].copy_from_slice(&value.to_be_bytes());
45}
46
47pub fn set_dint(bytearray: &mut [u8], byte_index: usize, value: i32) {
48 bytearray[byte_index..byte_index + 4].copy_from_slice(&value.to_be_bytes());
49}
50
51pub fn set_udint(bytearray: &mut [u8], byte_index: usize, value: u32) {
52 bytearray[byte_index..byte_index + 4].copy_from_slice(&value.to_be_bytes());
53}
54
55pub fn set_time(bytearray: &mut [u8], byte_index: usize, time_string: &str) -> Result<(), String> {
56 let duration = parse_time_string(time_string)?;
57 let millis = duration.as_millis() as i32;
58 bytearray[byte_index..byte_index + 4].copy_from_slice(&millis.to_be_bytes());
59 Ok(())
60}
61
62pub fn parse_time_string(time_string: &str) -> Result<Duration, String> {
63 let re = regex::Regex::new(r"(-?)(\d+):(\d+):(\d+):(\d+).(\d+)").unwrap();
64 if let Some(caps) = re.captures(time_string) {
65 let sign = if &caps[1] == "-" { -1 } else { 1 };
66 let days: u64 = caps[2].parse().unwrap();
67 let hours: u64 = caps[3].parse().unwrap();
68 let minutes: u64 = caps[4].parse().unwrap();
69 let seconds: u64 = caps[5].parse().unwrap();
70 let millis: u64 = caps[6].parse().unwrap();
71 let total_millis = (((((days * 24 + hours) * 60 + minutes) * 60 + seconds) * 1000 + millis)
72 as i64
73 * sign) as u64;
74 Ok(Duration::from_millis(total_millis))
75 } else {
76 Err(format!("Invalid time string: {}", time_string))
77 }
78}
79
80pub fn set_usint(bytearray: &mut [u8], byte_index: usize, value: u8) {
81 bytearray[byte_index] = value;
82}
83
84pub fn set_sint(bytearray: &mut [u8], byte_index: usize, value: i8) {
85 bytearray[byte_index] = value as u8;
86}
87
88pub fn set_lreal(bytearray: &mut [u8], byte_index: usize, value: f64) {
89 bytearray[byte_index..byte_index + 8].copy_from_slice(&value.to_be_bytes());
90}
91
92pub fn set_char(bytearray: &mut [u8], byte_index: usize, value: char) -> Result<(), String> {
93 if value.is_ascii() {
94 bytearray[byte_index] = value as u8;
95 Ok(())
96 } else {
97 Err(format!("Non-ASCII character: {}", value))
98 }
99}
100
101pub fn set_date(
102 bytearray: &mut [u8],
103 byte_index: usize,
104 value: chrono::NaiveDate,
105) -> Result<(), String> {
106 let base_date = chrono::NaiveDate::from_ymd_opt(1990, 1, 1).expect("failed to get base date");
107 if value < base_date
108 || value > chrono::NaiveDate::from_ymd_opt(2168, 12, 31).expect("failed to get base date")
109 {
110 return Err(format!("Date out of range: {}", value));
111 }
112 let days = (value - base_date).num_days() as i16;
113 bytearray[byte_index..byte_index + 2].copy_from_slice(&days.to_be_bytes());
114 Ok(())
115}
116
117#[cfg(test)]
118mod setters_tests {
119 use super::*;
120 use chrono::NaiveDate;
121
122 #[test]
123 fn test_set_bool() {
124 let mut data = vec![0; 1];
125 set_bool(&mut data, 0, 0, true).unwrap();
126 assert_eq!(data, vec![1]);
127 set_bool(&mut data, 0, 0, false).unwrap();
128 assert_eq!(data, vec![0]);
129 }
130
131 #[test]
132 fn test_set_byte() {
133 let mut data = vec![0; 1];
134 set_byte(&mut data, 0, 255);
135 assert_eq!(data, vec![255]);
136 }
137
138 #[test]
139 fn test_set_word() {
140 let mut data = vec![0; 2];
141 set_word(&mut data, 0, 65535);
142 assert_eq!(data, vec![255, 255]);
143 }
144
145 #[test]
146 fn test_set_int() {
147 let mut data = vec![0; 2];
148 set_int(&mut data, 0, -32768);
149 assert_eq!(data, vec![128, 0]);
150 }
151
152 #[test]
153 fn test_set_date() {
154 let mut data = vec![0; 2];
155 let date = NaiveDate::from_ymd_opt(2024, 3, 27).unwrap();
156 set_date(&mut data, 0, date).unwrap();
157 assert_eq!(data, vec![48, 216]);
158 }
159 #[test]
160 fn test_set_uint() {
161 let mut bytearray = [0u8; 10];
162 set_uint(&mut bytearray, 2, 0x1234);
163 assert_eq!(bytearray[2], 0x12);
164 assert_eq!(bytearray[3], 0x34);
165 }
166
167 #[test]
168 fn test_set_real() {
169 let mut bytearray = [0u8; 10];
170 set_real(&mut bytearray, 2, 12.34);
171 assert_eq!(bytearray[2..6], 12.34f32.to_be_bytes());
172 }
173
174 #[test]
175 fn test_set_dword() {
176 let mut bytearray = [0u8; 10];
177 set_dword(&mut bytearray, 2, 0x12345678);
178 assert_eq!(bytearray[2], 0x12);
179 assert_eq!(bytearray[3], 0x34);
180 assert_eq!(bytearray[4], 0x56);
181 assert_eq!(bytearray[5], 0x78);
182 }
183
184 #[test]
185 fn test_set_dint() {
186 let mut bytearray = [0u8; 10];
187 set_dint(&mut bytearray, 2, -12345678);
188 assert_eq!(bytearray[2..6], (-12345678i32).to_be_bytes());
189 }
190
191 #[test]
192 fn test_set_udint() {
193 let mut bytearray = [0u8; 10];
194 set_udint(&mut bytearray, 2, 0x12345678);
195 assert_eq!(bytearray[2], 0x12);
196 assert_eq!(bytearray[3], 0x34);
197 assert_eq!(bytearray[4], 0x56);
198 assert_eq!(bytearray[5], 0x78);
199 }
200
201 #[test]
202 fn test_set_time() {
203 let mut bytearray = [0u8; 10];
204 set_time(&mut bytearray, 2, "0:0:0:1:0.0").unwrap();
205 assert_eq!(bytearray[2..6], 1000i32.to_be_bytes());
206 }
207
208 #[test]
209 fn test_set_usint() {
210 let mut bytearray = [0u8; 10];
211 set_usint(&mut bytearray, 2, 0x12);
212 assert_eq!(bytearray[2], 0x12);
213 }
214
215 #[test]
216 fn test_set_sint() {
217 let mut bytearray = [0u8; 10];
218 set_sint(&mut bytearray, 2, -5);
219 assert_eq!(bytearray[2], (-5i8) as u8);
220 }
221
222 #[test]
223 fn test_set_lreal() {
224 let mut bytearray = [0u8; 10];
225 set_lreal(&mut bytearray, 2, 12.34);
226 assert_eq!(bytearray[2..10], 12.34f64.to_be_bytes());
227 }
228
229 #[test]
230 fn test_set_char() {
231 let mut bytearray = [0u8; 10];
232 set_char(&mut bytearray, 2, 'A').unwrap();
233 assert_eq!(bytearray[2], b'A');
234 }
235
236 #[test]
237 fn test_set_char_non_ascii() {
238 let mut bytearray = [0u8; 10];
239 let result = set_char(&mut bytearray, 2, 'รง');
240 assert!(result.is_err());
241 }
242
243 #[test]
244 fn test_parse_time_string_valid() {
245 let duration = parse_time_string("0:0:0:1:0.0").unwrap();
246 assert_eq!(duration.as_millis(), 1000);
247 }
248
249 #[test]
250 fn test_parse_time_string_invalid() {
251 let result = parse_time_string("invalid time");
252 assert!(result.is_err());
253 }
254}