| 1 | //! Helpers for the generated code |
| 2 | |
| 3 | use super::x11_utils::TryParse; |
| 4 | use core::marker::PhantomData; |
| 5 | |
| 6 | /// Iterator implementation used by [GetPropertyReply]. |
| 7 | /// |
| 8 | /// This is the actual type returned by [GetPropertyReply::value8], [GetPropertyReply::value16], |
| 9 | /// and [GetPropertyReply::value32]. This type needs to be public due to Rust's visibility rules. |
| 10 | /// |
| 11 | /// [GetPropertyReply]: crate::protocol::xproto::GetPropertyReply |
| 12 | /// [GetPropertyReply::value8]: crate::protocol::xproto::GetPropertyReply::value8 |
| 13 | /// [GetPropertyReply::value16]: crate::protocol::xproto::GetPropertyReply::value16 |
| 14 | /// [GetPropertyReply::value32]: crate::protocol::xproto::GetPropertyReply::value32 |
| 15 | #[derive (Debug, Clone)] |
| 16 | pub struct PropertyIterator<'a, T>(&'a [u8], PhantomData<T>); |
| 17 | |
| 18 | impl<'a, T> PropertyIterator<'a, T> { |
| 19 | pub(crate) fn new(value: &'a [u8]) -> Self { |
| 20 | PropertyIterator(value, PhantomData) |
| 21 | } |
| 22 | } |
| 23 | |
| 24 | impl<T> Iterator for PropertyIterator<'_, T> |
| 25 | where |
| 26 | T: TryParse, |
| 27 | { |
| 28 | type Item = T; |
| 29 | |
| 30 | fn next(&mut self) -> Option<Self::Item> { |
| 31 | match T::try_parse(self.0) { |
| 32 | Ok((value: T, remaining: &[u8])) => { |
| 33 | self.0 = remaining; |
| 34 | Some(value) |
| 35 | } |
| 36 | Err(_) => { |
| 37 | self.0 = &[]; |
| 38 | None |
| 39 | } |
| 40 | } |
| 41 | } |
| 42 | |
| 43 | fn size_hint(&self) -> (usize, Option<usize>) { |
| 44 | let size: usize = self.0.len() / core::mem::size_of::<T>(); |
| 45 | (size, Some(size)) |
| 46 | } |
| 47 | } |
| 48 | |
| 49 | impl<T: TryParse> core::iter::FusedIterator for PropertyIterator<'_, T> {} |
| 50 | |
| 51 | #[cfg (test)] |
| 52 | mod tests { |
| 53 | use super::PropertyIterator; |
| 54 | use alloc::vec::Vec; |
| 55 | |
| 56 | #[test ] |
| 57 | fn test_parse_u8() { |
| 58 | let input = [0u8, 1, 2, 3, 4, 5]; |
| 59 | let output = PropertyIterator::new(&input).collect::<Vec<u8>>(); |
| 60 | assert_eq!(&input[..], output); |
| 61 | } |
| 62 | |
| 63 | #[test ] |
| 64 | fn test_parse_u32() { |
| 65 | let expected = [0u32, 1, 2, 3, 4, 5]; |
| 66 | let input = { |
| 67 | let mut input = Vec::new(); |
| 68 | for value in &expected { |
| 69 | input.extend_from_slice(&value.to_ne_bytes()); |
| 70 | } |
| 71 | input |
| 72 | }; |
| 73 | |
| 74 | let output = PropertyIterator::new(&input).collect::<Vec<u32>>(); |
| 75 | assert_eq!(&expected[..], output); |
| 76 | } |
| 77 | |
| 78 | #[test ] |
| 79 | fn test_size_hint() { |
| 80 | let hint = PropertyIterator::<u32>::new(&[0; 0]).size_hint(); |
| 81 | assert_eq!(hint, (0, Some(0))); |
| 82 | |
| 83 | let hint = PropertyIterator::<u32>::new(&[0; 8]).size_hint(); |
| 84 | assert_eq!(hint, (2, Some(2))); |
| 85 | |
| 86 | // In this case, the data is not an exact multiple of the element size |
| 87 | let hint = PropertyIterator::<u32>::new(&[0; 30]).size_hint(); |
| 88 | assert_eq!(hint, (7, Some(7))); |
| 89 | } |
| 90 | } |
| 91 | |