1use core::mem::MaybeUninit;
2
3use crate::error::{NetpackError, Result};
4
5pub trait CheckedReader: Sized {
6 fn read_slice_checked(&mut self, size: usize) -> Result<&[u8]>;
7 #[inline(always)]
8 fn read_checked<T: ReadDataChecked>(&mut self) -> Result<T> {
9 T::read_checked(self)
10 }
11}
12
13pub trait CheckedWriter: Sized {
14 fn write_slice(&mut self, data: &[u8]) -> Result<()>;
15 #[inline(always)]
16 fn write<T: WriteDataChecked>(&mut self, value: T) -> Result<()> {
17 T::write_to_checked(value, self)
18 }
19}
20
21impl<'a> CheckedReader for &'a [u8] {
22 #[inline(always)]
23 fn read_slice_checked(&mut self, size: usize) -> Result<&'a [u8]> {
24 if self.len() < size {
25 return Err(NetpackError::BufferTooSmall {
26 provided_size: self.len(),
27 requried_size: size,
28 });
29 }
30 let (data, remaining) = self.split_at(size);
31 *self = remaining;
32 Ok(data)
33 }
34}
35
36impl<'a> CheckedWriter for &'a mut [u8] {
37 #[inline(always)]
38 fn write_slice(&mut self, data: &[u8]) -> Result<()> {
39 if self.len() < data.len() {
40 return Err(NetpackError::BufferTooSmall {
41 provided_size: self.len(),
42 requried_size: data.len(),
43 });
44 }
45 let this = core::mem::take(self);
46 let (write_buffer, remaining) = this.split_at_mut(data.len());
47 *self = remaining;
48 write_buffer.copy_from_slice(data);
49 Ok(())
50 }
51}
52
53pub trait ReadDataChecked: Sized {
54 fn read_checked(reader: &mut impl CheckedReader) -> Result<Self>;
55}
56
57pub trait WriteDataChecked {
58 fn write_to_checked(self, writer: &mut impl CheckedWriter) -> Result<()>;
59}
60
61impl<const N: usize> ReadDataChecked for [u8; N] {
62 #[cfg_attr(feature = "fast-rw", inline(always))]
63 fn read_checked(reader: &mut impl CheckedReader) -> Result<Self> {
64 let slice = reader.read_slice_checked(N)?;
65 unsafe { Ok(*slice.as_ptr().cast()) }
66 }
67}
68
69impl<const N: usize> WriteDataChecked for [u8; N] {
70 fn write_to_checked(self, writer: &mut impl CheckedWriter) -> Result<()> {
71 writer.write_slice(&self)
72 }
73}
74
75impl<const N: usize> ReadDataChecked for [u16; N] {
76 fn read_checked(reader: &mut impl CheckedReader) -> Result<Self> {
77 let mut read_buffer = reader.read_slice_checked(core::mem::size_of::<u16>() * N)?;
78
79 let mut write_buffer: [MaybeUninit<u16>; N] =
80 unsafe { MaybeUninit::uninit().assume_init() };
81 let read_ptr = &mut read_buffer;
82
83 for elem in write_buffer.iter_mut() {
84 elem.write(u16::read_checked(read_ptr)?);
85 }
86
87 Ok(unsafe { *write_buffer.as_ptr().cast() })
88 }
89}
90impl<const N: usize> WriteDataChecked for [u16; N] {
91 fn write_to_checked(self, writer: &mut impl CheckedWriter) -> Result<()> {
92 for v in self.iter() {
93 writer.write(*v)?;
94 }
95 Ok(())
96 }
97}
98
99impl ReadDataChecked for u8 {
100 fn read_checked(reader: &mut impl CheckedReader) -> Result<Self> {
101 reader.read_slice_checked(1).map(|m| m[0])
102 }
103}
104
105impl WriteDataChecked for u8 {
106 fn write_to_checked(self, writer: &mut impl CheckedWriter) -> Result<()> {
107 writer.write_slice(&[self])
108 }
109}
110
111macro_rules! impl_read_write_data {
112 ($($t:ty),+) => {
113 $(
114 impl ReadDataChecked for $t {
115 #[inline(always)]
116 fn read_checked(reader: &mut impl CheckedReader) -> Result<$t> {
117 let data = reader.read_checked();
118 data.map(<$t>::from_be_bytes)
119 }
120 }
121
122 impl WriteDataChecked for $t {
123 #[inline(always)]
124 fn write_to_checked(self, writer: &mut impl CheckedWriter) -> Result<()> {
125 let data = self.to_be_bytes();
126 writer.write(data)
127 }
128 }
129 )*
130 };
131}
132
133impl_read_write_data! {
134 u16,
135 u32,
136 u64
137}