1pub use std::io::{Read, Write};
7
8pub trait Packable {
10 type Error: std::fmt::Debug;
12
13 fn packed_len(&self) -> usize;
15
16 fn pack<W: Write>(&self, writer: &mut W) -> Result<(), Self::Error>;
18
19 fn pack_new(&self) -> Vec<u8> {
21 let mut bytes = Vec::with_capacity(self.packed_len());
22 self.pack(&mut bytes).unwrap();
24
25 bytes
26 }
27
28 fn unpack_inner<R: Read + ?Sized, const CHECK: bool>(reader: &mut R) -> Result<Self, Self::Error>
30 where
31 Self: Sized;
32
33 fn unpack<R: Read + ?Sized>(reader: &mut R) -> Result<Self, Self::Error>
36 where
37 Self: Sized,
38 {
39 Self::unpack_inner::<R, true>(reader)
40 }
41
42 fn unpack_unchecked<R: Read + ?Sized>(reader: &mut R) -> Result<Self, Self::Error>
45 where
46 Self: Sized,
47 {
48 Self::unpack_inner::<R, false>(reader)
49 }
50}
51
52impl<const N: usize> Packable for [u8; N] {
53 type Error = std::io::Error;
54
55 fn packed_len(&self) -> usize {
56 N
57 }
58
59 fn pack<W: Write>(&self, writer: &mut W) -> Result<(), Self::Error> {
60 writer.write_all(self)?;
61
62 Ok(())
63 }
64
65 fn unpack_inner<R: Read + ?Sized, const CHECK: bool>(reader: &mut R) -> Result<Self, Self::Error>
66 where
67 Self: Sized,
68 {
69 let mut bytes = [0u8; N];
70 reader.read_exact(&mut bytes)?;
71
72 Ok(bytes)
73 }
74}
75
76impl Packable for bool {
77 type Error = std::io::Error;
78
79 fn packed_len(&self) -> usize {
80 (*self as u8).packed_len()
81 }
82
83 fn pack<W: Write>(&self, writer: &mut W) -> Result<(), Self::Error> {
84 (*self as u8).pack(writer)
85 }
86
87 fn unpack_inner<R: Read + ?Sized, const CHECK: bool>(reader: &mut R) -> Result<Self, Self::Error>
88 where
89 Self: Sized,
90 {
91 Ok(u8::unpack_inner::<R, CHECK>(reader)? != 0)
92 }
93}
94
95impl<P> Packable for Vec<P>
96where
97 P: Packable,
98 P::Error: From<std::io::Error>,
99{
100 type Error = P::Error;
101
102 fn packed_len(&self) -> usize {
103 0u64.packed_len() + self.iter().map(Packable::packed_len).sum::<usize>()
104 }
105
106 fn pack<W: Write>(&self, writer: &mut W) -> Result<(), Self::Error> {
107 (self.len() as u64).pack(writer)?;
108 self.iter().try_for_each(|x| x.pack(writer))
109 }
110
111 fn unpack_inner<R: Read + ?Sized, const CHECK: bool>(reader: &mut R) -> Result<Self, Self::Error>
112 where
113 Self: Sized,
114 {
115 (0..u64::unpack_inner::<R, CHECK>(reader)?)
116 .map(|_| P::unpack_inner::<R, CHECK>(reader))
117 .collect()
118 }
119}
120
121#[derive(Debug)]
123pub enum OptionError<E> {
124 Bool(<bool as Packable>::Error),
126 Inner(E),
128}
129
130impl<E> From<E> for OptionError<E> {
131 fn from(inner: E) -> Self {
132 OptionError::Inner(inner)
133 }
134}
135
136impl<P: Packable> Packable for Option<P> {
137 type Error = OptionError<P::Error>;
138
139 fn packed_len(&self) -> usize {
140 true.packed_len() + self.as_ref().map_or(0, Packable::packed_len)
141 }
142
143 fn pack<W: Write>(&self, writer: &mut W) -> Result<(), Self::Error> {
144 if let Some(p) = self {
145 true.pack(writer).map_err(OptionError::Bool)?;
146 p.pack(writer).map_err(OptionError::Inner)?;
147 } else {
148 false.pack(writer).map_err(OptionError::Bool)?;
149 }
150
151 Ok(())
152 }
153
154 fn unpack_inner<R: Read + ?Sized, const CHECK: bool>(reader: &mut R) -> Result<Self, Self::Error>
155 where
156 Self: Sized,
157 {
158 Ok(if bool::unpack_inner::<R, CHECK>(reader).map_err(OptionError::Bool)? {
159 Some(P::unpack_inner::<R, CHECK>(reader).map_err(OptionError::Inner)?)
160 } else {
161 None
162 })
163 }
164}
165
166macro_rules! impl_packable_for_num {
167 ($ty:ident) => {
168 impl Packable for $ty {
169 type Error = std::io::Error;
170
171 fn packed_len(&self) -> usize {
172 std::mem::size_of_val(&self.to_le_bytes())
173 }
174
175 fn pack<W: Write>(&self, writer: &mut W) -> Result<(), Self::Error> {
176 writer.write_all(&self.to_le_bytes())?;
177
178 Ok(())
179 }
180
181 fn unpack_inner<R: Read + ?Sized, const CHECK: bool>(reader: &mut R) -> Result<Self, Self::Error>
182 where
183 Self: Sized,
184 {
185 let mut bytes = [0; $ty::MIN.to_le_bytes().len()];
186 reader.read_exact(&mut bytes)?;
187
188 Ok($ty::from_le_bytes(bytes))
189 }
190 }
191 };
192}
193
194impl_packable_for_num!(i8);
195impl_packable_for_num!(u8);
196impl_packable_for_num!(i16);
197impl_packable_for_num!(u16);
198impl_packable_for_num!(i32);
199impl_packable_for_num!(u32);
200impl_packable_for_num!(i64);
201impl_packable_for_num!(u64);
202#[cfg(has_i128)]
203impl_packable_for_num!(i128);
204#[cfg(has_u128)]
205impl_packable_for_num!(u128);