modbius_core/util.rs
1use crate::ModbusSerializationError;
2
3/// Reads an u16 from the given modbus data. The data is considered to be big endian with msB first
4///
5/// # Errors
6/// If the data slice contains less than 2 bytes a [ModbusSerializationError::UnexpectedEOF] will be returned
7/// with its expected field set to 2 and its got field set to data.len().
8pub fn read_u16(data: &[u8]) -> Result<(u16, &[u8]), crate::ModbusSerializationError> {
9 if let [Some(dhi), Some(dlo)] = [data.get(0), data.get(1)] {
10 Ok((u16::from_be_bytes([*dhi, *dlo]), &data[2..]))
11 } else {
12 Err(ModbusSerializationError::UnexpectedEOF {
13 expected: 2,
14 got: data.len(),
15 })
16 }
17}
18
19/// Reads an u16 from the given modbus data without performing bounds checks. The data is considered to be big endian with msB first.
20pub unsafe fn read_u16_unchecked(data: &[u8]) -> (u16, &[u8]) {
21 let word = u16::from_be_bytes([*data.get_unchecked(0), *data.get_unchecked(1)]);
22
23 //This is safe if data.len() > 2 as get_unchecked only invokes undefined behavior
24 //if get would return none (idx > len)
25 (word, data.get_unchecked(2..))
26}
27
28#[cfg(test)]
29mod read_u16_test {
30 use super::read_u16;
31
32 #[test]
33 fn read8() {
34 let (w8, tail) = read_u16(&[0, 8]).unwrap();
35 assert_eq!(w8, 8);
36 assert_eq!(tail, []);
37 }
38
39 #[test]
40 fn read0() {
41 let (w8, tail) = read_u16(&[0, 0, 100]).unwrap();
42 assert_eq!(w8, 0);
43 assert_eq!(tail, &[100]);
44 }
45
46 #[test]
47 fn read256() {
48 let (w8, tail) = read_u16(&[1, 0, 100, 200, 2, 3, 4, 5]).unwrap();
49 assert_eq!(w8, 256);
50 assert_eq!(tail, &[100, 200, 2, 3, 4, 5]);
51 }
52
53 #[test]
54 #[should_panic(expected = "called `Result::unwrap()` on an `Err` value")]
55 fn read_error1() {
56 let (_w8, _tail) = read_u16(&[1]).unwrap();
57 }
58
59 #[test]
60 #[should_panic(expected = "called `Result::unwrap()` on an `Err` value")]
61 fn read_error0() {
62 let (_w8, _tail) = read_u16(&[]).unwrap();
63 }
64}
65/*
66/// Interprets the data as an address and a quantity. They are returned in this order.
67/// The data left in the slice is returned too.
68///
69/// # Errors
70/// If the data slice contains less than 4 bytes a [ModbusSerializationError::UnexpectedEOF] will be returned
71/// with its expected field set to 4 and its got field set to data.len().
72pub fn read_addr_quantity(data: &[u8]) -> Result<(u16, u16, &[u8]), ModbusSerializationError> {
73 if data.len() < 4 {
74 return Err(ModbusSerializationError::UnexpectedEOF {expected: 4, got: data.len()})
75 }
76
77 Ok(unsafe { read_addr_quantity_unchecked(data) })
78}
79
80pub unsafe fn read_addr_quantity_unchecked(data: &[u8]) -> (u16, u16, &[u8]) {
81 let (addr, data) = read_u16_unchecked(data);
82 let (quantity, data) = read_u16_unchecked(data);
83
84 (addr, quantity, data)
85}
86
87pub fn write_addr_quantity(
88 addr: u16,
89 quantity: u16,
90 out: &mut [u8],
91) -> Result<(), ModbusSerializationError> {
92 if out.len() < 4 {
93 return Err(ModbusSerializationError::InsufficientBuffer {
94 expected: 4,
95 got: out.len(),
96 });
97 }
98
99 unsafe {
100 write_addr_quantity_unchecked(addr, quantity, out);
101 }
102
103 Ok(())
104}
105
106pub unsafe fn write_addr_quantity_unchecked(addr: u16, quantity: u16, out: &mut [u8]) {
107 let addr_bytes = addr.to_be_bytes();
108 *out.get_unchecked_mut(0) = addr_bytes[0];
109 *out.get_unchecked_mut(1) = addr_bytes[1];
110
111 let quantity_bytes = quantity.to_be_bytes();
112 *out.get_unchecked_mut(2) = quantity_bytes[0];
113 *out.get_unchecked_mut(3) = quantity_bytes[1];
114} */