binrw/binwrite/
impls.rs

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);