1use std::iter::FusedIterator;
2use std::mem::size_of;
3use std::ops::Deref;
4use std::ptr::slice_from_raw_parts;
5
6use crate::{FixedSized, SubRecord};
7
8#[derive(Copy, Clone, Debug, PartialEq)]
13pub enum SliceWrapper<'a, T: FixedSized> {
14 Raw(&'a [u8]),
15 Cooked(&'a [T]),
16}
17
18impl<'a, T, A> From<A> for SliceWrapper<'a, T>
19where
20 T: FixedSized,
21 A: AsRef<&'a [T]>,
22{
23 #[inline]
24 fn from(array: A) -> Self {
25 SliceWrapper::from_cooked(array.as_ref())
26 }
27}
28
29impl<'a> Deref for SliceWrapper<'a, u8> {
30 type Target = &'a [u8];
31
32 #[inline]
33 fn deref(&self) -> &Self::Target {
34 match self {
35 SliceWrapper::Raw(d) => d,
36 SliceWrapper::Cooked(d) => d,
37 }
38 }
39}
40
41impl<'a> AsRef<[u8]> for SliceWrapper<'a, u8> {
42 #[inline]
43 fn as_ref(&self) -> &'a [u8] {
44 **self
45 }
46}
47
48impl<'a, T> SliceWrapper<'a, T>
49where
50 T: FixedSized,
51{
52 pub fn from_raw(bytes: &'a [u8]) -> Self {
55 assert_eq!(bytes.len() % size_of::<T>(), 0);
56 Self::Raw(bytes)
57 }
58
59 pub fn from_cooked(array: &'a [T]) -> Self {
60 SliceWrapper::Cooked(array)
61 }
62}
63
64impl<'a, T> SliceWrapper<'a, T>
65where
66 T: FixedSized + SubRecord<'a>,
67{
68 pub fn get(&self, i: usize) -> Option<T> {
70 match *self {
71 SliceWrapper::Raw(raw) => {
72 if i * size_of::<T>() + size_of::<T>() > raw.len() {
73 None
74 } else {
75 let raw: &'a [u8] = unsafe {
76 &*slice_from_raw_parts(
77 raw.as_ptr().add(i * size_of::<T>()),
78 size_of::<T>(),
79 )
80 };
81 Some(T::_deserialize_chained(raw).map(|(_, v)| v).unwrap())
82 }
83 }
84 SliceWrapper::Cooked(ary) => ary.get(i).copied(),
85 }
86 }
87
88 pub fn iter(&self) -> Iter<'a, T> {
89 self.into_iter()
90 }
91}
92
93impl<'a, T> SliceWrapper<'a, T>
94where
95 T: FixedSized,
96{
97 pub fn is_raw(&self) -> bool {
98 matches!(self, SliceWrapper::Raw(_))
99 }
100}
101
102impl<'a, T> SliceWrapper<'a, T>
103where
104 T: FixedSized,
105{
106 #[inline]
108 pub fn len(&self) -> usize {
109 match *self {
110 SliceWrapper::Raw(raw) => raw.len() / size_of::<T>(),
111 SliceWrapper::Cooked(ary) => ary.len(),
112 }
113 }
114
115 #[inline]
116 pub fn is_empty(&self) -> bool {
117 match *self {
118 SliceWrapper::Raw(raw) => raw.is_empty(),
119 SliceWrapper::Cooked(ary) => ary.is_empty(),
120 }
121 }
122
123 #[inline]
126 pub fn size(&self) -> usize {
127 match *self {
128 SliceWrapper::Raw(raw) => raw.len(),
129 SliceWrapper::Cooked(ary) => ary.len() * size_of::<T>(),
130 }
131 }
132}
133
134impl<'a, T> IntoIterator for SliceWrapper<'a, T>
135where
136 T: FixedSized + SubRecord<'a>,
137{
138 type Item = T;
139 type IntoIter = Iter<'a, T>;
140
141 #[inline]
142 fn into_iter(self) -> Self::IntoIter {
143 Iter(self, 0)
144 }
145}
146
147pub struct Iter<'a, T: FixedSized>(SliceWrapper<'a, T>, usize);
148
149impl<'a, T> Iterator for Iter<'a, T>
150where
151 T: FixedSized + SubRecord<'a>,
152{
153 type Item = T;
154
155 fn next(&mut self) -> Option<T> {
156 let r = self.0.get(self.1);
157 self.1 += 1;
158 r
159 }
160}
161
162impl<'a, T> FusedIterator for Iter<'a, T> where T: FixedSized + SubRecord<'a> {}
163impl<'a, T> ExactSizeIterator for Iter<'a, T>
164where
165 T: FixedSized + SubRecord<'a>,
166{
167 fn len(&self) -> usize {
168 debug_assert!(self.1 <= self.0.len());
169 self.0.len() - self.1
170 }
171}
172
173#[cfg(test)]
174mod test {
175 use std::convert::TryInto;
176
177 use crate::{
178 define_serialize_chained, packed_read, DeResult, FixedSized, SliceWrapper,
179 SubRecord,
180 };
181
182 #[repr(packed)]
183 #[derive(Debug, Eq, PartialEq, Copy, Clone)]
184 struct Fixed {
185 a: u8,
186 b: u64,
187 }
188
189 impl FixedSized for Fixed {}
190
191 fn cooked_array() -> &'static [Fixed] {
192 &[
193 Fixed { a: 23, b: 98072396 },
194 Fixed {
195 a: 134,
196 b: 2389502334,
197 },
198 Fixed { a: 73, b: 98273 },
199 Fixed { a: 1, b: 59125 },
200 ]
201 }
202
203 impl<'raw> SubRecord<'raw> for Fixed {
204 const MIN_SERIALIZED_SIZE: usize = Self::SERIALIZED_SIZE;
205 const EXACT_SERIALIZED_SIZE: Option<usize> = Some(Self::SERIALIZED_SIZE);
206
207 fn serialized_size(&self) -> usize {
208 Self::SERIALIZED_SIZE
209 }
210
211 define_serialize_chained!(*Fixed => |zelf, dest| {
212 Ok(zelf.a._serialize_chained(dest)? + packed_read!(zelf.b)._serialize_chained(dest)?)
213 });
214
215 fn _deserialize_chained(raw: &'raw [u8]) -> DeResult<(usize, Self)> {
216 Ok((
217 9,
218 Self {
219 a: raw[0],
220 b: u64::from_le_bytes((raw[1..9]).try_into().unwrap()),
221 },
222 ))
223 }
224 }
225
226 #[test]
227 fn from_raw() {
228 let s = <SliceWrapper<u16>>::from_raw(&[0x00, 0x00, 0x00, 0x00]);
230 assert!(!s.is_empty());
231 }
232
233 #[test]
234 #[should_panic]
235 fn from_raw_err() {
236 let s = <SliceWrapper<u16>>::from_raw(&[0x00, 0x00, 0x00]);
238 assert!(!s.is_empty());
239 }
240
241 #[test]
242 fn get_cooked_fixed_struct() {
243 let array = cooked_array();
244 let s = SliceWrapper::Cooked(array);
245 for i in 0..array.len() {
246 assert_eq!(s.get(i).unwrap(), array[i]);
247 }
248 }
249
250 #[test]
251 fn get_cooked_primitive() {
252 let array: &'static [u16] = &[0x0000, 0x1243, 0x8f90, 0x097a];
253 let s = SliceWrapper::Cooked(array);
254 for i in 0..array.len() {
255 assert_eq!(s.get(i).unwrap(), array[i]);
256 }
257 }
258
259 #[test]
260 fn get_raw_fixed_struct() {
261 let s = <SliceWrapper<Fixed>>::Raw(&[0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
263 let s0 = s.get(0).unwrap();
264 assert_eq!(packed_read!(s0.a), 1);
265 assert_eq!(packed_read!(s0.b), 2);
266 }
267
268 #[test]
269 fn get_raw_primitive() {
270 let s = <SliceWrapper<u16>>::Raw(&[0x01, 0x00, 0x02, 0x00]);
272 assert_eq!(s.get(0).unwrap(), 1);
273 assert_eq!(s.get(1).unwrap(), 2);
274 }
275
276 #[test]
277 fn iter_cooked() {
278 let array = cooked_array();
279 let s = SliceWrapper::Cooked(array);
280 for (i, v) in s.iter().enumerate() {
281 assert_eq!(v, array[i]);
282 }
283 }
284
285 #[test]
286 fn iter_raw() {
287 let s = <SliceWrapper<Fixed>>::Raw(&[
288 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x04, 0x00, 0x00, 0x00,
289 0x00, 0x00, 0x00, 0x00,
290 ]);
291 for (i, v) in s.iter().enumerate() {
292 assert_eq!(packed_read!(v.a), (i * 2 + 1) as u8);
293 assert_eq!(packed_read!(v.b), (i * 2 + 2) as u64);
294 }
295 }
296
297 #[test]
298 fn size_cooked_struct() {
299 let s = SliceWrapper::Cooked(cooked_array());
300 assert_eq!(s.len(), 4);
301 assert_eq!(s.size(), 9 * 4);
302 }
303
304 #[test]
305 fn size_raw_struct() {
306 let s = <SliceWrapper<Fixed>>::Raw(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
307 assert_eq!(s.len(), 1);
308 assert_eq!(s.size(), 9);
309 }
310
311 #[test]
312 fn size_cooked_primitive() {
313 let s = <SliceWrapper<u16>>::Cooked(&[0x0000, 0x0000, 0x0000]);
314 assert_eq!(s.len(), 3);
315 assert_eq!(s.size(), 6);
316 }
317
318 #[test]
319 fn size_raw_primitive() {
320 let s = <SliceWrapper<u16>>::Raw(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
321 assert_eq!(s.len(), 3);
322 assert_eq!(s.size(), 6);
323 }
324
325 #[test]
326 fn deref_u8_raw() {
327 let s = <SliceWrapper<u8>>::Raw(&[0x00, 0x01, 0x04, 0x06]);
328 let s2: &[u8] = *s;
329 assert_eq!(s2[0], 0);
330 assert_eq!(s2[1], 1);
331 assert_eq!(s2[2], 4);
332 assert_eq!(s2[3], 6);
333 }
334
335 #[test]
336 fn deref_u8_cooked() {
337 let s = <SliceWrapper<u8>>::Cooked(&[0x00, 0x01, 0x04, 0x06]);
338 let s2: &[u8] = *s;
339 assert_eq!(s2[0], 0);
340 assert_eq!(s2[1], 1);
341 assert_eq!(s2[2], 4);
342 assert_eq!(s2[3], 6);
343 }
344}