1use crate::{
2 io::{Seek, Write},
3 BinResult, BinWrite, Endian,
4};
5#[cfg(not(feature = "std"))]
6use alloc::{boxed::Box, vec::Vec};
7use core::{
8 any::Any,
9 marker::PhantomData,
10 num::{
11 NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroU128, NonZeroU16,
12 NonZeroU32, NonZeroU64, NonZeroU8,
13 },
14};
15
16macro_rules! binwrite_num_impl {
17 ($($type_name:ty),*$(,)?) => {
18 $(
19 impl BinWrite for $type_name {
20 type Args<'a> = ();
21
22 fn write_options<W: Write + Seek>(
23 &self,
24 writer: &mut W,
25 endian: Endian,
26 (): Self::Args<'_>,
27 ) -> BinResult<()> {
28 writer.write_all(&match endian {
29 Endian::Big => self.to_be_bytes(),
30 Endian::Little => self.to_le_bytes(),
31 }).map_err(Into::into)
32 }
33 }
34 )*
35 };
36}
37
38binwrite_num_impl!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, f32, f64);
39
40macro_rules! binwrite_nonzero_num_impl {
41 ($($non_zero_type:ty => $type_name:ty),*$(,)?) => {
42 $(
43 impl BinWrite for $non_zero_type {
44 type Args<'a> = ();
45
46 fn write_options<W: Write + Seek>(
47 &self,
48 writer: &mut W,
49 endian: Endian,
50 (): Self::Args<'_>,
51 ) -> BinResult<()> {
52 let num = <$type_name>::from(*self);
53
54 writer.write_all(&match endian {
55 Endian::Big => num.to_be_bytes(),
56 Endian::Little => num.to_le_bytes(),
57 }).map_err(Into::into)
58 }
59 }
60 )*
61 };
62}
63
64binwrite_nonzero_num_impl!(
65 NonZeroU8 => u8,
66 NonZeroU16 => u16,
67 NonZeroU32 => u32,
68 NonZeroU64 => u64,
69 NonZeroU128 => u128,
70 NonZeroI8 => i8,
71 NonZeroI16 => i16,
72 NonZeroI32 => i32,
73 NonZeroI64 => i64,
74 NonZeroI128 => i128,
75);
76
77impl<T, const N: usize> BinWrite for [T; N]
78where
79 T: BinWrite + 'static,
80 for<'a> T::Args<'a>: Clone,
81{
82 type Args<'a> = T::Args<'a>;
83
84 fn write_options<W: Write + Seek>(
85 &self,
86 writer: &mut W,
87 endian: Endian,
88 args: Self::Args<'_>,
89 ) -> BinResult<()> {
90 if let Some(this) = <dyn Any>::downcast_ref::<[u8; N]>(self) {
91 writer.write_all(&this[..])?;
92 } else {
93 for item in self {
94 T::write_options(item, writer, endian, args.clone())?;
95 }
96 }
97
98 Ok(())
99 }
100}
101
102impl<T> BinWrite for [T]
103where
104 T: BinWrite,
105 for<'a> T::Args<'a>: Clone,
106{
107 type Args<'a> = T::Args<'a>;
108
109 fn write_options<W: Write + Seek>(
110 &self,
111 writer: &mut W,
112 endian: Endian,
113 args: Self::Args<'_>,
114 ) -> BinResult<()> {
115 for item in self {
116 T::write_options(item, writer, endian, args.clone())?;
117 }
118
119 Ok(())
120 }
121}
122
123impl<T> BinWrite for Vec<T>
124where
125 T: BinWrite + 'static,
126 for<'a> T::Args<'a>: Clone,
127{
128 type Args<'a> = T::Args<'a>;
129
130 fn write_options<W: Write + Seek>(
131 &self,
132 writer: &mut W,
133 endian: Endian,
134 args: Self::Args<'_>,
135 ) -> BinResult<()> {
136 if let Some(this) = <dyn Any>::downcast_ref::<Vec<u8>>(self) {
137 writer.write_all(this)?;
138 } else if let Some(this) = <dyn Any>::downcast_ref::<Vec<i8>>(self) {
139 writer.write_all(bytemuck::cast_slice(this.as_slice()))?;
140 } else {
141 for item in self {
142 T::write_options(item, writer, endian, args.clone())?;
143 }
144 }
145
146 Ok(())
147 }
148}
149
150impl<T: BinWrite + ?Sized> BinWrite for &T {
151 type Args<'a> = T::Args<'a>;
152
153 fn write_options<W: Write + Seek>(
154 &self,
155 writer: &mut W,
156 endian: Endian,
157 args: Self::Args<'_>,
158 ) -> BinResult<()> {
159 (**self).write_options(writer, endian, args)
160 }
161}
162
163impl<T: BinWrite + ?Sized + 'static> BinWrite for Box<T> {
164 type Args<'a> = T::Args<'a>;
165
166 fn write_options<W: Write + Seek>(
167 &self,
168 writer: &mut W,
169 endian: Endian,
170 args: Self::Args<'_>,
171 ) -> BinResult<()> {
172 if let Some(this) = <dyn Any>::downcast_ref::<Box<[u8]>>(self) {
173 writer.write_all(this)?;
174 } else {
175 (**self).write_options(writer, endian, args)?;
176 }
177
178 Ok(())
179 }
180}
181
182impl<T: BinWrite> BinWrite for Option<T> {
183 type Args<'a> = T::Args<'a>;
184
185 fn write_options<W: Write + Seek>(
186 &self,
187 writer: &mut W,
188 endian: Endian,
189 args: Self::Args<'_>,
190 ) -> BinResult<()> {
191 match self {
192 Some(inner) => inner.write_options(writer, endian, args),
193 None => Ok(()),
194 }
195 }
196}
197
198impl<T> BinWrite for PhantomData<T> {
199 type Args<'a> = ();
200
201 fn write_options<W: Write + Seek>(
202 &self,
203 _: &mut W,
204 _: Endian,
205 (): Self::Args<'_>,
206 ) -> BinResult<()> {
207 Ok(())
208 }
209}
210
211impl BinWrite for () {
212 type Args<'a> = ();
213
214 fn write_options<W: Write + Seek>(
215 &self,
216 _: &mut W,
217 _: Endian,
218 (): Self::Args<'_>,
219 ) -> BinResult<()> {
220 Ok(())
221 }
222}
223
224macro_rules! binwrite_tuple_impl {
225 ($type1:ident $(, $types:ident)*) => {
226 #[allow(non_camel_case_types)]
227 impl<Args: Clone,
228 $type1: for<'a> BinWrite<Args<'a> = Args>, $($types: for<'a> BinWrite<Args<'a> = Args>),*
229 > BinWrite for ($type1, $($types),*) {
230 type Args<'a> = Args;
231
232 fn write_options<W: Write + Seek>(
233 &self,
234 writer: &mut W,
235 endian: Endian,
236 args: Self::Args<'_>,
237 ) -> BinResult<()> {
238 let ($type1, $(
239 $types
240 ),*) = self;
241
242 $type1.write_options(writer, endian, args.clone())?;
243 $(
244 $types.write_options(writer, endian, args.clone())?;
245 )*
246
247 Ok(())
248 }
249 }
250
251 binwrite_tuple_impl!($($types),*);
252 };
253
254 () => {};
255}
256
257binwrite_tuple_impl!(
258 b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16, b17, b18, b19, b20, b21,
259 b22, b23, b24, b25, b26, b27, b28, b29, b30, b31, b32
260);