binwrite/lib.rs
1//! A Rust crate for helping write structs as binary data using ✨macro magic✨
2//!
3//! # Example:
4//!```rust
5//! use binwrite::BinWrite;
6//!
7//! #[derive(BinWrite)]
8//! #[binwrite(little)]
9//! struct Rect {
10//! x: i32,
11//! y: i32,
12//! #[binwrite(big)]
13//! size: (u16, u16),
14//! }
15//!
16//! fn main() {
17//! let rects = vec![
18//! Rect { x: 1, y: -2, size: (3, 4) },
19//! Rect { x: 20, y: 4, size: (5, 7) }
20//! ];
21//! let mut bytes = vec![];
22//! rects.write(&mut bytes).unwrap();
23//! assert_eq!(
24//! bytes,
25//! vec![
26//! // [ x (little endian) ] [ y (little endian) ] [ size.0 ] [ size.1 ]
27//! 0x01, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x03, 0x00, 0x04,
28//! 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x07,
29//! ]
30//! );
31//! }
32//!```
33
34use std::io::{Result, Write};
35
36/// Derive macro for BinWrite. [Usage here](BinWrite).
37pub use binwrite_derive::BinWrite;
38
39/// Module for [WriteTrack\<T\>](write_track::WriteTrack)
40pub mod write_track;
41/// Built-in special writers (example: C strings)
42pub mod writers;
43mod binwrite_impls;
44
45pub use binwrite_impls::*;
46
47/// A trait providing the ability to write the struct to a writer
48///
49/// ### Derive-based example:
50/// ```rust
51/// use binwrite::BinWrite;
52///
53/// #[derive(BinWrite)]
54/// struct Point {
55/// x: i32,
56/// y: i32,
57/// }
58///
59/// fn main() {
60/// let point = Point { x: 1, y: -2 };
61/// let mut bytes = vec![];
62///
63/// point.write(&mut bytes).unwrap();
64///
65/// assert_eq!(bytes, vec![1, 0, 0, 0, 0xFE, 0xFF, 0xFF, 0xFF]);
66/// }
67/// ```
68///
69/// ### Setting Endianness
70/// ```rust
71/// use binwrite::BinWrite;
72///
73/// #[derive(BinWrite)]
74/// #[binwrite(big)]
75/// struct Foo {
76/// bar: u32,
77/// bar2: i32,
78///
79/// #[binwrite(little)]
80/// bar3: u32,
81/// }
82///
83/// fn main() {
84/// let point = Foo {
85/// bar: 1,
86/// bar2: -2,
87/// bar3: 3
88/// };
89/// let mut bytes = vec![];
90///
91/// point.write(&mut bytes).unwrap();
92///
93/// assert_eq!(bytes, vec![0, 0, 0, 1, 0xFF, 0xFF, 0xFF, 0xFE, 3, 0, 0, 0]);
94/// }
95/// ```
96///
97/// ### Using a preprocessor
98/// ```rust
99/// use binwrite::BinWrite;
100///
101/// #[derive(BinWrite)]
102/// struct Foo {
103/// #[binwrite(preprocessor(u32_to_hex_string))]
104/// bar: u32,
105/// bar2: String,
106/// }
107///
108/// fn u32_to_hex_string(var: &u32) -> String {
109/// format!("{:X}", var)
110/// }
111///
112/// fn main() {
113/// let point = Foo {
114/// bar: 0xF00D,
115/// bar2: String::from(" looks like food")
116/// };
117/// let mut bytes = vec![];
118///
119/// point.write(&mut bytes).unwrap();
120///
121/// assert_eq!(bytes, b"F00D looks like food");
122/// }
123/// ```
124///
125/// ### Using a custom writer
126///
127/// For more complicated or more reusable serialization methods, you may want to use a custom
128/// writer instead of just preprocessing.
129/// ```rust
130/// use std::io::{Write, Result};
131/// use binwrite::{BinWrite, WriterOption};
132///
133/// #[derive(BinWrite)]
134/// struct Foo {
135/// vec_without_len: Vec<u8>,
136/// #[binwrite(with(write_vec_with_len), big)]
137/// vec_with_len: Vec<u8>,
138/// }
139///
140/// pub fn write_vec_with_len<W, T>(vec: &Vec<T>, writer: &mut W, options: &WriterOption) -> Result<()>
141/// where W: Write,
142/// T: BinWrite,
143/// {
144/// BinWrite::write_options(&(vec.len() as u32), writer, options)?;
145/// BinWrite::write_options(vec, writer, options)
146/// }
147///
148/// fn main() {
149/// let point = Foo {
150/// vec_without_len: vec![0, 1, 2, 3],
151/// vec_with_len: vec![0, 1, 2, 3],
152/// };
153/// let mut bytes = vec![];
154///
155/// point.write(&mut bytes).unwrap();
156///
157/// assert_eq!(bytes, vec![0, 1, 2, 3, 0, 0, 0, 4, 0, 1, 2, 3]);
158/// }
159/// ```
160///
161/// ### Built in Writers:
162/// Currently supported built in writers:
163/// * cstr - "C string" (null terminated string)
164/// * utf16 - UTF-16/2 byte wide/Windows string, endianness is used to determine byte order
165/// * utf16_null - same as utf16 but with a null terminator
166/// * ignore - skip writing this field
167/// ```rust
168/// use binwrite::BinWrite;
169///
170/// #[derive(BinWrite)]
171/// struct Foo {
172/// #[binwrite(cstr)]
173/// bar: u32,
174/// #[binwrite(cstr)]
175/// bar2: String,
176/// #[binwrite(ignore)]
177/// bar3: u8,
178/// }
179///
180/// fn main() {
181/// let point = Foo {
182/// bar: 1234,
183/// bar2: String::from("this is null terminated"),
184/// bar3: 0xFF
185/// };
186/// let mut bytes = vec![];
187///
188/// point.write(&mut bytes).unwrap();
189///
190/// assert_eq!(bytes, b"1234\0this is null terminated\0");
191/// }
192/// ```
193///
194/// ### Padding/Alignment
195/// binwrite also has the ability to align to the nearest X bytes
196/// ```rust
197/// use binwrite::BinWrite;
198///
199/// #[derive(BinWrite)]
200/// struct Foo {
201/// // For tuples/arrays/vecs/slices of types implementing BinWrite work out of the box
202/// // and items will just be written in order.
203/// bar: [char; 3],
204/// // pad specifies the padding before
205/// // pad_after specifiers the padding after
206/// #[binwrite(align(8), align_after(0x10))]
207/// bar2: String,
208/// }
209///
210/// fn main() {
211/// let point = Foo {
212/// bar: ['a', 'b', 'c'],
213/// bar2: String::from("test string")
214/// };
215/// let mut bytes = vec![];
216///
217/// point.write(&mut bytes).unwrap();
218///
219/// assert_eq!(bytes, b"abc\0\0\0\0\0test string\0\0\0\0\0\0\0\0\0\0\0\0\0");
220/// }
221/// ```
222/// use `pad` and `pad_after` for fixed amounts of padding.
223///
224/// ### Advanced Preprocessors
225/// Using generics/closures, you can make "configurable" and more reusable preprocessors.
226///
227/// Example (a configurable "add X before writing"):
228/// ```rust
229/// use binwrite::BinWrite;
230///
231/// fn add<T: std::ops::Add<Output = T> + Copy>(lhs: T) -> impl Fn(&T) -> T {
232/// move |rhs| lhs + *rhs
233/// }
234///
235/// #[derive(BinWrite)]
236/// struct Foo {
237/// #[binwrite(preprocessor(add(10)))]
238/// bar_u32: u32,
239/// #[binwrite(preprocessor(add(-1)))]
240/// bar_i64: i64,
241/// }
242///
243/// fn main() {
244/// let mut bytes = vec![];
245///
246/// Foo {
247/// bar_u32: 2,
248/// bar_i64: 0,
249/// }.write(&mut bytes).unwrap();
250///
251/// assert_eq!(bytes, vec![0xCu8, 0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]);
252/// }
253/// ```
254///
255/// ### Postprocessors
256///
257/// Postprocessors are functions which take a `Vec<u8>` (what would normally be written) and
258/// produce any type that implements BinWrite, which is then written in place of the bytes.
259/// ```rust
260/// use binwrite::BinWrite;
261///
262/// fn not_crc32(bytes: &Vec<u8>) -> u32 {
263/// 4
264/// }
265///
266/// fn prepend_crc32(bytes: Vec<u8>) -> (u32, Vec<u8>) {
267/// (
268/// not_crc32(&bytes),
269/// bytes
270/// )
271/// }
272///
273/// #[derive(BinWrite)]
274/// #[binwrite(big)]
275/// struct Foo {
276/// #[binwrite(postprocessor(prepend_crc32))]
277/// bar: u32,
278/// }
279///
280/// fn main() {
281/// let mut bytes = vec![];
282///
283/// Foo {
284/// bar: 2,
285/// }.write(&mut bytes).unwrap();
286///
287/// assert_eq!(bytes, vec![0x0u8, 0, 0, 4, 0, 0, 0, 0x2]);
288/// }
289/// ```
290pub trait BinWrite {
291 fn write<W: Write>(&self, writer: &mut W) -> std::io::Result<()> {
292 self.write_options(writer, &WriterOption::default())
293 }
294
295 fn write_options<W: Write>(&self, writer: &mut W, options: &WriterOption) -> Result<()>;
296}
297
298/// An enum to represent what endianness to write with
299#[derive(Clone, Copy, Debug)]
300pub enum Endian {
301 Big,
302 Little,
303 Native,
304}
305
306impl Into<String> for &Endian {
307 fn into(self) -> String {
308 String::from(
309 match self {
310 Endian::Big => "Big",
311 Endian::Little => "Little",
312 Endian::Native => "Native",
313 }
314 )
315 }
316}
317
318/// Options on how to write. Use [writer_option_new!](writer_option_new) to create a new
319/// instance. Manual initialization is not possible to prevent forward compatibility issues.
320#[derive(Default, Clone)]
321pub struct WriterOption {
322 pub endian: Endian,
323 /// A private field to prevent users from creating/destructuring in a non-forwards compatible
324 /// manner
325 _prevent_creation: ()
326}
327
328/// Macro for creating a new writer option, with the idea being a non-verbose means of providing a
329/// forwards-compatible set of options which uses default values for all provided options.
330#[macro_export] macro_rules! writer_option_new {
331 ($($field:ident : $val:expr),*$(,)?) => {
332 {
333 let mut _writer_option = ::binwrite::WriterOption::default();
334 $(
335 _writer_option.$field = $val;
336 )*
337 _writer_option
338 }
339 }
340}
341
342impl Default for Endian {
343 fn default() -> Endian {
344 Endian::Native
345 }
346}