modbus_core/frame/
data.rs

1use super::*;
2use crate::error::*;
3
4/// Modbus data (u16 values)
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub struct Data<'d> {
7    pub(crate) data: RawData<'d>,
8    pub(crate) quantity: usize,
9}
10
11impl<'d> Data<'d> {
12    /// Pack words (u16 values) into a byte buffer.
13    pub fn from_words(words: &[u16], target: &'d mut [u8]) -> Result<Self, Error> {
14        if (words.len() * 2 > target.len()) || words.is_empty() {
15            return Err(Error::BufferSize);
16        }
17        for (i, w) in words.iter().enumerate() {
18            BigEndian::write_u16(&mut target[i * 2..], *w);
19        }
20        Ok(Data {
21            data: target,
22            quantity: words.len(),
23        })
24    }
25    //TODO: add tests
26    pub(crate) fn copy_to(&self, buf: &mut [u8]) {
27        let cnt = self.quantity * 2;
28        debug_assert!(buf.len() >= cnt);
29        (0..cnt).for_each(|idx| {
30            buf[idx] = self.data[idx];
31        });
32    }
33    /// Quantity of words (u16 values)
34    #[must_use]
35    pub const fn len(&self) -> usize {
36        self.quantity
37    }
38    ///  Returns `true` if the container has no items.
39    #[must_use]
40    pub const fn is_empty(&self) -> bool {
41        self.quantity == 0
42    }
43    /// Get a specific word.
44    #[must_use]
45    pub fn get(&self, idx: usize) -> Option<Word> {
46        if idx + 1 > self.quantity {
47            return None;
48        }
49        let idx = idx * 2;
50        Some(BigEndian::read_u16(&self.data[idx..idx + 2]))
51    }
52}
53
54/// Data iterator
55// TODO: crate a generic iterator
56#[derive(Debug, Clone, PartialEq, Eq)]
57pub struct DataIter<'d> {
58    cnt: usize,
59    data: Data<'d>,
60}
61
62impl<'d> Iterator for DataIter<'d> {
63    type Item = Word;
64
65    fn next(&mut self) -> Option<Self::Item> {
66        let result = self.data.get(self.cnt);
67        self.cnt += 1;
68        result
69    }
70}
71
72impl<'d> IntoIterator for Data<'d> {
73    type Item = Word;
74    type IntoIter = DataIter<'d>;
75
76    fn into_iter(self) -> Self::IntoIter {
77        DataIter { cnt: 0, data: self }
78    }
79}
80
81#[cfg(test)]
82mod tests {
83
84    use super::*;
85
86    #[test]
87    fn from_word_slice() {
88        let words: &[u16] = &[0xABCD, 0xEF00, 0x1234];
89        let buff: &mut [u8] = &mut [0; 5];
90        assert!(Data::from_words(words, buff).is_err());
91        let buff: &mut [u8] = &mut [0; 6];
92        let data = Data::from_words(words, buff).unwrap();
93        assert_eq!(data.len(), 3);
94        let mut iter = data.into_iter();
95        assert_eq!(iter.next(), Some(0xABCD));
96        assert_eq!(iter.next(), Some(0xEF00));
97        assert_eq!(iter.next(), Some(0x1234));
98        assert_eq!(iter.next(), None);
99    }
100
101    #[test]
102    fn data_len() {
103        let data = Data {
104            data: &[0, 1, 2],
105            quantity: 5,
106        };
107        assert_eq!(data.len(), 5);
108    }
109
110    #[test]
111    fn data_empty() {
112        let data = Data {
113            data: &[0, 1, 2],
114            quantity: 0,
115        };
116        assert!(data.is_empty());
117    }
118
119    #[test]
120    fn data_get() {
121        let data = Data {
122            data: &[0xAB, 0xBC, 0x12],
123            quantity: 1,
124        };
125        assert_eq!(data.get(0), Some(0xABBC));
126        assert_eq!(data.get(1), None);
127
128        let data = Data {
129            data: &[0xFF, 0xAB, 0xCD, 0xEF, 0x33],
130            quantity: 2,
131        };
132        assert_eq!(data.get(0), Some(0xFFAB));
133        assert_eq!(data.get(1), Some(0xCDEF));
134        assert_eq!(data.get(2), None);
135    }
136
137    #[test]
138    fn data_iter() {
139        let data = Data {
140            data: &[0x01, 0x02, 0x03, 0x04, 0xAA, 0xBB],
141            quantity: 3,
142        };
143        let mut data_iter = DataIter { cnt: 0, data };
144        assert_eq!(data_iter.next(), Some(0x0102));
145        assert_eq!(data_iter.next(), Some(0x0304));
146        assert_eq!(data_iter.next(), Some(0xAABB));
147        assert_eq!(data_iter.next(), None);
148    }
149
150    #[test]
151    fn data_into_iter() {
152        let data = Data {
153            data: &[0x01, 0x02, 0x03, 0x04, 0xAA, 0xBB],
154            quantity: 3,
155        };
156        let mut data_iter = data.into_iter();
157        assert!(data_iter.next().is_some());
158        assert!(data_iter.next().is_some());
159        assert!(data_iter.next().is_some());
160        assert!(data_iter.next().is_none());
161    }
162}