1#![doc = include_str!("../README.md")]
2#![cfg_attr(docsrs, feature(doc_auto_cfg))]
3#![warn(
4 clippy::undocumented_unsafe_blocks,
5 clippy::missing_const_for_fn,
6 clippy::missing_safety_doc,
7 clippy::suboptimal_flops,
8 unsafe_op_in_unsafe_fn,
9 clippy::dbg_macro,
10 clippy::use_self,
11 missing_docs
12)]
13#![allow(
14 private_bounds,
15 clippy::zero_prefixed_literal,
16 mixed_script_confusables,
17 confusable_idents
18)]
19use std::mem::ManuallyDrop as MD;
20const unsafe fn transmute_unchecked<T, U>(value: T) -> U {
24 unsafe {
26 #[repr(C)]
27 union Transmute<T, U> {
28 t: MD<T>,
29 u: MD<U>,
30 }
31 MD::into_inner(Transmute { t: MD::new(value) }.u)
32 }
33}
34
35macro_rules! trt {
36 (r $(#[doc = $x: expr])+ f $(#[doc = $z: expr])+ w $(#[doc = $y: expr])+) => {
37 use std::io::prelude::*;
38 use std::io::Result;
39 use std::mem::MaybeUninit as MU;
40
41 $(#[doc = $x])+
42 pub trait R: Read {
43 $(#[doc = $z])+
44 fn r<T: Readable>(&mut self) -> Result<T>;
45 fn b(&mut self) -> Result<u8> {
54 self.r::<u8>()
55 }
56 }
57
58 #[doc(hidden)]
59 impl<D: Read> R for D {
60 fn r<T: Readable>(&mut self) -> Result<T> {
61 T::r(self)
62 }
63 }
64 #[diagnostic::on_unimplemented(
65 message = "this type is not suitable for reading into",
66 note = "read to [u8; N] first and then parse it",
67 label = "unreadable type"
68 )]
69 trait Readable
70 where
71 Self: Sized,
72 {
73 fn r(from: &mut impl Read) -> Result<Self>;
74 }
75
76 impl<const N: usize> Readable for [u8; N] {
77 fn r(from: &mut impl Read) -> Result<[u8; N]> {
78 let mut buf = [0; N];
79 from.read_exact(&mut buf).map(|()| buf)
80 }
81 }
82
83 impl<const N: usize> Writable for &[u8; N] {
84 fn _w(self, to: &mut impl Write) -> Result<()> {
85 to.w(&self[..])
86 }
87 }
88
89 $(#[doc = $y])+
90 pub trait W: Write {
91 fn w<T: Writable>(&mut self, data: T) -> Result<()>;
93 }
94
95 #[doc(hidden)]
96 impl<D: Write> W for D {
97 fn w<T: Writable>(&mut self, data: T) -> Result<()> {
98 data._w(self)
99 }
100 }
101 #[diagnostic::on_unimplemented(
102 message = "this type is not suitable for writing",
103 note = "turn it into a &[u8] first and then write that",
104 label = "unwritable type",
105 )]
106 trait Writable {
107 fn _w(self, to: &mut impl Write) -> Result<()>;
108 }
109
110 impl Writable for &[u8] {
111 fn _w(self, to: &mut impl Write) -> Result<()> {
112 to.write_all(self)
113 }
114 }
115 };
116}
117
118macro_rules! n {
119 (writes $bytes:ident $($n:ident)+) => {
120 $(
121 impl<const N: usize> Writable for &[$n; N] {
122 fn _w(self, to: &mut impl Write) -> Result<()> {
123 to.w(&self[..])
124 }
125 }
126
127 impl Writable for &[$n] {
128 fn _w(self, to: &mut impl Write) -> Result<()> {
129 if (cfg!(target_endian = "little") && stringify!($bytes) == "le") || (cfg!(target_endian = "big") && stringify!($bytes) == "be") {
130 to.w(unsafe { std::slice::from_raw_parts(self.as_ptr() as *const u8, self.len() * ($n::BITS / 8) as usize) })
132 } else {
133 self.iter().try_for_each(|x| to.w(x))
134 }
135 }
136 }
137 impl<const N: usize> Readable for [$n; N] {
138 fn r(from: &mut impl Read) -> Result<[$n; N]> {
139 if (cfg!(target_endian = "little") && stringify!($bytes) == "le") || (cfg!(target_endian = "big") && stringify!($bytes) == "be") {
140 let mut buf = [0; N];
141 let mut u8s = unsafe { std::slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u8, N * ($n::BITS / 8) as usize) };
143 from.read_exact(&mut u8s).map(|()| buf)
144 } else {
145 let mut buf = [MU::<$n>::uninit(); N];
146 for elem in &mut buf{
147 elem.write(from.r::<$n>()?);
148 }
149 Ok(unsafe { crate::transmute_unchecked(buf) })
151 }
152 }
153 }
154 )+
155 };
156 (float $bytes:ident $([$n:ident <=> $int:ident])+) => {
157 $(
158 impl Readable for $n {
159 fn r(from: &mut impl Read) -> Result<$n> {
160 from.r::<$int>().map($n::from_bits)
161 }
162 }
163 )+
164
165 $(
166 impl Writable for $n {
167 fn _w(self, to: &mut impl Write) -> Result<()> {
168 to.w(self.to_bits())
169 }
170 }
171 impl Writable for &$n {
172 fn _w(self, to: &mut impl Write) -> Result<()> {
173 to.w(self.to_bits())
174 }
175 }
176 macro_rules! bytes {
177 ($t:ty) => {
178 impl Writable for $t {
179 fn _w(self, to: &mut impl Write) -> Result<()> {
180 to.w(&*self)
181 }
182 }
183 }
184 }
185 bytes![Vec<$n>];
186 bytes![Box<[$n]>];
187 impl<const N: usize> Writable for [$n; N] {
188 fn _w(self, to: &mut impl Write) -> Result<()> {
189 to.w(&self[..])
190 }
191 }
192
193 impl<const N: usize> Writable for &[$n; N] {
194 fn _w(self, to: &mut impl Write) -> Result<()> {
195 to.w(&self[..])
196 }
197 }
198
199 impl Writable for &[$n] {
200 fn _w(self, to: &mut impl Write) -> Result<()> {
201 if (cfg!(target_endian = "little") && stringify!($bytes) == "le") || (cfg!(target_endian = "big") && stringify!($bytes) == "be") {
202 to.w(unsafe { std::slice::from_raw_parts(self.as_ptr() as *const u8, self.len() * ($int::BITS / 8) as usize) })
204 } else {
205 self.iter().try_for_each(|x| to.w(x))
206 }
207 }
208 }
209 impl<const N: usize> Readable for [$n; N] {
210 fn r(from: &mut impl Read) -> Result<[$n; N]> {
211 if (cfg!(target_endian = "little") && stringify!($bytes) == "le") || (cfg!(target_endian = "big") && stringify!($bytes) == "be") {
212 let mut buf = [0.; N];
213 let mut u8s = unsafe { std::slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u8, N * ($int::BITS / 8) as usize) };
215 from.read_exact(&mut u8s).map(|()| buf)
216 } else {
217 let mut buf = [MU::<$n>::uninit(); N];
218 for elem in &mut buf{
219 elem.write(from.r::<$n>()?);
220 }
221 Ok(unsafe { crate::transmute_unchecked(buf) })
223 }
224 }
225 }
226 )+
227 };
228 ($bytes:ident $($n:ident)+) => {
229 $(
230 impl Readable for $n {
231 fn r(from: &mut impl Read) -> Result<$n> {
232 from.r::<[u8; { std::mem::size_of::<$n>() }]>().map($n::from_ne_bytes).map($n::$bytes)
233 }
234 }
235 )+
236
237 $(
238 impl Writable for $n {
239 fn _w(self, to: &mut impl Write) -> Result<()> {
240 to.w(self.$bytes().to_ne_bytes())
241 }
242 }
243 impl Writable for &$n {
244 fn _w(self, to: &mut impl Write) -> Result<()> {
245 to.w(self.$bytes().to_ne_bytes())
246 }
247 }
248 macro_rules! bytes {
249 ($t:ty) => {
250 impl Writable for $t {
251 fn _w(self, to: &mut impl Write) -> Result<()> {
252 to.w(&*self)
253 }
254 }
255 }
256 }
257 bytes![Vec<$n>];
258 bytes![Box<[$n]>];
259 impl<const N: usize> Writable for [$n; N] {
260 fn _w(self, to: &mut impl Write) -> Result<()> {
261 to.w(&self[..])
262 }
263 }
264 )+
265 };
266}
267
268macro_rules! test {
269 () => {
270 #[test]
271 fn x() {
272 let data = &mut &[0x12u8, 0x15][..];
273 let mut out = vec![];
274 out.w(data.r::<[u16; 1]>().unwrap()).unwrap();
275 assert_eq!(out, [0x12, 0x15]);
276
277 let mut out = vec![];
278 out.w([12.0_f32, 13.]).unwrap();
279 assert_eq!((&mut &*out).r::<[f32; 2]>().unwrap(), [12., 13.]);
280 }
281 };
282}
283pub mod le {
284 trt!(
286 r f w );
318 n![writes le u16 u32 u64 u128 i8 i16 i32 i64 i128];
319 n![float le [f32 <=> u32] [f64 <=> u64]];
320 n![to_le u8 u16 u32 u64 u128 i8 i16 i32 i64 i128];
321 test![];
322}
323
324#[doc(alias = "network")]
325pub mod be {
326 trt!(
328 r f w );
355 n![writes be u16 u32 u64 u128 i8 i16 i32 i64 i128];
356 n![float be [f32 <=> u32] [f64 <=> u64]];
357 n![to_be u8 u16 u32 u64 u128 i8 i16 i32 i64 i128];
358 test![];
359}
360
361pub mod ne {
362 #[cfg(target_endian = "big")]
364 #[doc(inline)]
365 pub use super::be::{R, W};
366 #[cfg(target_endian = "little")]
367 #[doc(inline)]
368 pub use super::le::{R, W};
369}