Skip to main content

rs_matter/utils/storage/
parsebuf.rs

1/*
2 *
3 *    Copyright (c) 2022-2026 Project CHIP Authors
4 *
5 *    Licensed under the Apache License, Version 2.0 (the "License");
6 *    you may not use this file except in compliance with the License.
7 *    You may obtain a copy of the License at
8 *
9 *        http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *    Unless required by applicable law or agreed to in writing, software
12 *    distributed under the License is distributed on an "AS IS" BASIS,
13 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *    See the License for the specific language governing permissions and
15 *    limitations under the License.
16 */
17
18use core::borrow::{Borrow, BorrowMut};
19
20use crate::error::*;
21use core::convert::TryInto;
22
23/// A buffer for reading data from a byte slice.
24pub struct ReadBuf<T> {
25    buf: T,
26    read_off: usize,
27    left: usize,
28}
29
30impl<T> ReadBuf<T>
31where
32    T: Borrow<[u8]>,
33{
34    pub fn new(buf: T) -> Self {
35        let left = buf.borrow().len();
36
37        Self {
38            buf,
39            read_off: 0,
40            left,
41        }
42    }
43
44    pub fn reset(&mut self) {
45        self.read_off = 0;
46        self.left = self.buf.borrow().len();
47    }
48
49    pub fn load<Q>(&mut self, pb: &ReadBuf<Q>) -> Result<(), Error>
50    where
51        T: BorrowMut<[u8]>,
52        Q: Borrow<[u8]>,
53    {
54        if self.buf.borrow().len() < pb.read_off + pb.left {
55            Err(ErrorCode::BufferTooSmall)?;
56        }
57
58        self.buf.borrow_mut()[0..pb.read_off + pb.left]
59            .copy_from_slice(&pb.buf.borrow()[..pb.read_off + pb.left]);
60        self.read_off = pb.read_off;
61        self.left = pb.left;
62
63        Ok(())
64    }
65
66    pub fn set_len(&mut self, left: usize) {
67        self.left = left;
68    }
69
70    pub fn read_off(&self) -> usize {
71        self.read_off
72    }
73
74    pub fn slice_range(&self) -> (usize, usize) {
75        (self.read_off, self.read_off + self.left)
76    }
77
78    // Return the data that is valid as a slice
79    pub fn as_slice(&self) -> &[u8] {
80        &self.buf.borrow()[self.read_off..(self.read_off + self.left)]
81    }
82
83    // Return the data that is valid as a slice
84    pub fn as_mut_slice(&mut self) -> &mut [u8]
85    where
86        T: BorrowMut<[u8]>,
87    {
88        &mut self.buf.borrow_mut()[self.read_off..(self.read_off + self.left)]
89    }
90
91    pub fn parsed_as_slice(&self) -> &[u8] {
92        &self.buf.borrow()[0..self.read_off]
93    }
94
95    pub fn tail(&mut self, size: usize) -> Result<&[u8], Error> {
96        if size <= self.left {
97            let end_offset = self.read_off + self.left;
98            let tail = &self.buf.borrow()[(end_offset - size)..end_offset];
99            self.left -= size;
100            return Ok(tail);
101        }
102        Err(ErrorCode::TruncatedPacket.into())
103    }
104
105    fn advance(&mut self, len: usize) {
106        self.read_off += len;
107        self.left -= len;
108    }
109
110    pub fn parse_head_with<F, R>(&mut self, size: usize, f: F) -> Result<R, Error>
111    where
112        F: FnOnce(&mut Self) -> R,
113    {
114        if self.left >= size {
115            let data = f(self);
116            self.advance(size);
117            return Ok(data);
118        }
119        Err(ErrorCode::TruncatedPacket.into())
120    }
121
122    pub fn parse_as_array<F, R, const N: usize>(&mut self, f: F) -> Result<R, Error>
123    where
124        F: FnOnce([u8; N]) -> R,
125    {
126        if self.left >= N {
127            let end_offset = self.read_off + N;
128            let data = f(self.buf.borrow()[self.read_off..end_offset]
129                .try_into()
130                .unwrap());
131            self.advance(N);
132            return Ok(data);
133        }
134        Err(ErrorCode::TruncatedPacket.into())
135    }
136
137    pub fn le_u8(&mut self) -> Result<u8, Error> {
138        self.parse_head_with(1, |x| x.buf.borrow()[x.read_off])
139    }
140
141    pub fn le_u16(&mut self) -> Result<u16, Error> {
142        self.parse_as_array(u16::from_le_bytes)
143    }
144
145    pub fn le_u32(&mut self) -> Result<u32, Error> {
146        self.parse_as_array(u32::from_le_bytes)
147    }
148
149    pub fn le_u64(&mut self) -> Result<u64, Error> {
150        self.parse_as_array(u64::from_le_bytes)
151    }
152}
153
154pub type ParseBuf<'a> = ReadBuf<&'a mut [u8]>;
155
156#[cfg(test)]
157mod tests {
158    use crate::utils::storage::ParseBuf;
159
160    #[test]
161    fn test_parse_with_success() {
162        let mut test_slice = [0x01, 65, 0, 0xbe, 0xba, 0xfe, 0xca, 0xa, 0xb, 0xc, 0xd];
163        let mut buf = ParseBuf::new(&mut test_slice);
164
165        assert_eq!(buf.le_u8().unwrap(), 0x01);
166        assert_eq!(buf.le_u16().unwrap(), 65);
167        assert_eq!(buf.le_u32().unwrap(), 0xcafebabe);
168        assert_eq!(buf.as_slice(), [0xa, 0xb, 0xc, 0xd]);
169    }
170
171    #[test]
172    fn test_parse_with_overrun() {
173        let mut test_slice = [0x01, 65];
174        let mut buf = ParseBuf::new(&mut test_slice);
175
176        assert_eq!(buf.le_u8().unwrap(), 0x01);
177
178        if buf.le_u16().is_ok() {
179            panic!("This should have returned error")
180        }
181
182        if buf.le_u32().is_ok() {
183            panic!("This should have returned error")
184        }
185
186        // Now consume the leftover byte
187        assert_eq!(buf.le_u8().unwrap(), 65);
188
189        if buf.le_u8().is_ok() {
190            panic!("This should have returned error")
191        }
192        assert_eq!(buf.as_slice(), [] as [u8; 0]);
193    }
194
195    #[test]
196    fn test_tail_with_success() {
197        let mut test_slice = [0x01, 65, 0, 0xbe, 0xba, 0xfe, 0xca, 0xa, 0xb, 0xc, 0xd];
198        let mut buf = ParseBuf::new(&mut test_slice);
199
200        assert_eq!(buf.le_u8().unwrap(), 0x01);
201        assert_eq!(buf.le_u16().unwrap(), 65);
202        assert_eq!(buf.le_u32().unwrap(), 0xcafebabe);
203
204        assert_eq!(buf.tail(2).unwrap(), [0xc, 0xd]);
205        assert_eq!(buf.as_slice(), [0xa, 0xb]);
206
207        assert_eq!(buf.tail(2).unwrap(), [0xa, 0xb]);
208        assert_eq!(buf.as_slice(), [] as [u8; 0]);
209    }
210
211    #[test]
212    fn test_tail_with_overrun() {
213        let mut test_slice = [0x01, 65, 0, 0xbe, 0xba, 0xfe, 0xca, 0xa, 0xb, 0xc, 0xd];
214        let mut buf = ParseBuf::new(&mut test_slice);
215
216        assert_eq!(buf.le_u8().unwrap(), 0x01);
217        assert_eq!(buf.le_u16().unwrap(), 65);
218        assert_eq!(buf.le_u32().unwrap(), 0xcafebabe);
219        if buf.tail(5).is_ok() {
220            panic!("This should have returned error")
221        }
222        assert_eq!(buf.tail(2).unwrap(), [0xc, 0xd]);
223    }
224
225    #[test]
226    fn test_parsed_as_slice() {
227        let mut test_slice = [0x01, 65, 0, 0xbe, 0xba, 0xfe, 0xca, 0xa, 0xb, 0xc, 0xd];
228        let mut buf = ParseBuf::new(&mut test_slice);
229
230        assert_eq!(buf.parsed_as_slice(), [] as [u8; 0]);
231        assert_eq!(buf.le_u8().unwrap(), 0x1);
232        assert_eq!(buf.le_u16().unwrap(), 65);
233        assert_eq!(buf.le_u32().unwrap(), 0xcafebabe);
234        assert_eq!(buf.parsed_as_slice(), [0x01, 65, 0, 0xbe, 0xba, 0xfe, 0xca]);
235    }
236}