binread/
lib.rs

1//! A Rust crate for helping parse binary data using ✨macro magic✨.
2//!
3//! # Example
4//!
5//! ```
6//! # use binread::{prelude::*, io::Cursor, NullString};
7//!
8//! #[derive(BinRead)]
9//! #[br(magic = b"DOG", assert(name.len() != 0))]
10//! struct Dog {
11//!     bone_pile_count: u8,
12//!
13//!     #[br(big, count = bone_pile_count)]
14//!     bone_piles: Vec<u16>,
15//!
16//!     #[br(align_before = 0xA)]
17//!     name: NullString
18//! }
19//!
20//! let mut reader = Cursor::new(b"DOG\x02\x00\x01\x00\x12\0\0Rudy\0");
21//! let dog: Dog = reader.read_ne().unwrap();
22//! assert_eq!(dog.bone_piles, &[0x1, 0x12]);
23//! assert_eq!(dog.name.into_string(), "Rudy")
24//! ```
25//!
26//! # The Basics
27//!
28//! At the core of `binread` is the [`BinRead`](BinRead) trait. It defines how to read
29//! a type from bytes and is already implemented for most primitives and simple collections.
30//!
31//! ```rust
32//! use binread::{BinRead, io::Cursor};
33//!
34//! let mut reader = Cursor::new(b"\0\0\0\x01");
35//! let val = u32::read(&mut reader).unwrap();
36//! ```
37//!
38//! However, [`read`](BinRead::read) is intentionally simple and, as a result, doesn't even
39//! allow you to configure the byte order. For that you need [`read_options`](BinRead::read_options)
40//! which, while more powerful, isn't exactly ergonomics.
41//!
42//! So, as a balance between ergonomics and configurability you have the [`BinReaderExt`](BinReaderExt)
43//! trait. It is an extension for readers to allow for you to directly read any BinRead types from
44//! any reader.
45//!
46//! Example:
47//! ```rust
48//! use binread::{BinReaderExt, io::Cursor};
49//!
50//! let mut reader = Cursor::new(b"\x00\x0A");
51//! let val: u16 = reader.read_be().unwrap();
52//! assert_eq!(val, 10);
53//! ```
54//!
55//! It even works for tuples and arrays of BinRead types for up to size 32.
56//!
57//! # Derive Macro
58//!
59//! The most significant feature of binread is its ability to use the Derive macro to
60//! implement [`BinRead`](BinRead) for your own types. This allows you to replace repetitive
61//! imperative code with declarative struct definitions for your binary data parsing.
62//!
63//! ## Basic Derive Example
64//! ```rust
65//! # use binread::BinRead;
66//! #[derive(BinRead)]
67//! struct MyType {
68//!     first: u32,
69//!     second: u32
70//! }
71//!
72//! // Also works with tuple types!
73//! #[derive(BinRead)]
74//! struct MyType2(u32, u32);
75//! ```
76//! ## Attributes
77//! The BinRead derive macro uses attributes in order to allow for more complicated parsers. For
78//! example you can use `big` or `little` at either the struct-level or the field-level in order
79//! to override the byte order of values.
80//! ```rust
81//! # use binread::{prelude::*, io::Cursor};
82//! #[derive(BinRead)]
83//! #[br(little)]
84//! struct MyType (
85//!     #[br(big)] u32, // will be big endian
86//!     u32, // will be little endian
87//! );
88//! ```
89//! The order of precedence is: (from highest to lowest)
90//! 1. Field-level
91//! 2. Variant-level (for enums)
92//! 3. Top-level
93//! 4. Configured (i.e. what endianess was passed in)
94//! 5. Native endianess
95//!
96//! For a list of attributes see the [`attribute`](attribute) module
97//!
98//! ## Generics
99//! The BinRead derive macro also allows for generic parsing. That way you can build up
100//! higher-level parsers that can have their type swapped out to allow greater reuse of code.
101//!
102//! ```rust
103//! # use binread::{prelude::*, io::Cursor};
104//! #[derive(BinRead)]
105//! struct U32CountVec<T: BinRead<Args=()>> {
106//!     count: u32,
107//!     #[br(count = count)]
108//!     data: Vec<T>,
109//! }
110//! ```
111//!
112//! In order to parse generically, we have to (in some way) bound `Args`. The easiest way to do
113//! this is to bound `<T as BinRead>::Args` to `()` (no arguments), however it is also possible to
114//! either accept a specific set of arguments or be generic over the given arguments.
115//!
116//! ## Features
117//!
118//! * `const_generics` - Change array [`BinRead`] implementation to use const generics
119//! * `std` - Disable this feature to enable `no_std` support, on by default
120#![cfg_attr(not(feature = "std"), no_std)]
121#![warn(rust_2018_idioms)]
122
123#[cfg(feature = "std")]
124use std as alloc;
125
126#[cfg(not(feature = "std"))]
127extern crate alloc;
128
129#[cfg(not(feature = "std"))]
130use alloc::{boxed::Box, string::String, vec::Vec};
131
132#[doc(hidden)]
133#[path = "private.rs"]
134pub mod __private;
135
136pub mod attribute;
137pub mod endian;
138pub mod error;
139pub mod file_ptr;
140pub mod helpers;
141pub mod io;
142#[doc(hidden)]
143pub mod options;
144#[doc(hidden)]
145pub mod pos_value;
146pub mod punctuated;
147#[doc(hidden)]
148pub mod strings;
149
150#[cfg(feature = "std")]
151#[cfg(feature = "debug_template")]
152pub mod binary_template;
153
154use core::any::{Any, TypeId};
155
156#[doc(inline)]
157pub use {
158    endian::Endian,
159    error::Error,
160    file_ptr::{FilePtr, FilePtr128, FilePtr16, FilePtr32, FilePtr64, FilePtr8},
161    helpers::{count, until, until_eof, until_exclusive},
162    options::ReadOptions,
163    pos_value::PosValue,
164    strings::{NullString, NullWideString},
165};
166
167use io::{Read, Seek, SeekFrom, StreamPosition};
168
169/// Derive macro for BinRead. [Usage here](BinRead).
170pub use binread_derive::BinRead;
171
172/// Equivalent to `derive(BinRead)` but allows for temporary variables.
173pub use binread_derive::derive_binread;
174
175mod binread_impls;
176pub use binread_impls::*;
177
178/// A Result for any binread function that can return an error
179pub type BinResult<T> = core::result::Result<T, Error>;
180
181/// A `BinRead` trait allows reading a structure from anything that implements [`io::Read`](io::Read) and [`io::Seek`](io::Seek)
182/// BinRead is implemented on the type to be read out of the given reader
183pub trait BinRead: Sized {
184    /// The type of arguments needed to be supplied in order to read this type, usually a tuple.
185    ///
186    /// **NOTE:** For types that don't require any arguments, use the unit (`()`) type. This will allow [`read`](BinRead::read) to be used.
187    type Args: Any + Copy;
188
189    /// Read the type from the reader while assuming no arguments have been passed
190    ///
191    /// # Panics
192    /// Panics if there is no [`args_default`](BinRead::args_default) implementation
193    fn read<R: Read + Seek>(reader: &mut R) -> BinResult<Self> {
194        let args = match Self::args_default() {
195            Some(args) => args,
196            None => panic!("Must pass args, no args_default implemented"),
197        };
198
199        Self::read_options(reader, &ReadOptions::default(), args)
200    }
201
202    /// Read the type from the reader using the specified arguments
203    fn read_args<R: Read + Seek>(reader: &mut R, args: Self::Args) -> BinResult<Self> {
204        Self::read_options(reader, &ReadOptions::default(), args)
205    }
206
207    /// Read the type from the reader
208    fn read_options<R: Read + Seek>(
209        reader: &mut R,
210        options: &ReadOptions,
211        args: Self::Args,
212    ) -> BinResult<Self>;
213
214    fn after_parse<R: Read + Seek>(
215        &mut self,
216        _: &mut R,
217        _: &ReadOptions,
218        _: Self::Args,
219    ) -> BinResult<()> {
220        Ok(())
221    }
222
223    /// The default arguments to be used when using the [`read`](BinRead::read) shortcut method.
224    /// Override this for any type that optionally requries arguments
225    fn args_default() -> Option<Self::Args> {
226        // Trick to effectively get specialization on stable, should constant-folded away
227        // Returns `Some(())` if Self::Args == (), otherwise returns `None`
228        if TypeId::of::<Self::Args>() == TypeId::of::<()>() {
229            Some(unsafe { core::mem::MaybeUninit::uninit().assume_init() })
230        } else {
231            None
232        }
233    }
234}
235
236/// An extension trait for [`io::Read`](io::Read) to provide methods for reading a value directly
237///
238/// ## Example
239/// ```rust
240/// use binread::prelude::*; // BinReadExt is in the prelude
241/// use binread::endian::LE;
242/// use binread::io::Cursor;
243///
244/// let mut reader = Cursor::new(b"\x07\0\0\0\xCC\0\0\x05");
245/// let x: u32 = reader.read_le().unwrap();
246/// let y: u16 = reader.read_type(LE).unwrap();
247/// let z = reader.read_be::<u16>().unwrap();
248///
249/// assert_eq!((x, y, z), (7u32, 0xCCu16, 5u16));
250/// ```
251pub trait BinReaderExt: Read + Seek + Sized {
252    /// Read the given type from the reader using the given endianness.
253    fn read_type<T: BinRead>(&mut self, endian: Endian) -> BinResult<T> {
254        let args = match T::args_default() {
255            Some(args) => args,
256            None => panic!("Must pass args, no args_default implemented"),
257        };
258
259        let options = ReadOptions {
260            endian,
261            ..Default::default()
262        };
263
264        let mut res = T::read_options(self, &options, args)?;
265        res.after_parse(self, &options, args)?;
266
267        Ok(res)
268    }
269
270    /// Read the given type from the reader with big endian byteorder
271    fn read_be<T: BinRead>(&mut self) -> BinResult<T> {
272        self.read_type(Endian::Big)
273    }
274
275    /// Read the given type from the reader with little endian byteorder
276    fn read_le<T: BinRead>(&mut self) -> BinResult<T> {
277        self.read_type(Endian::Little)
278    }
279
280    /// Read the given type from the reader with the native byteorder
281    fn read_ne<T: BinRead>(&mut self) -> BinResult<T> {
282        self.read_type(Endian::Native)
283    }
284
285    /// Read `T` from the reader with the given byte order and arguments.
286    fn read_type_args<T: BinRead>(&mut self, endian: Endian, args: T::Args) -> BinResult<T> {
287        let options = ReadOptions {
288            endian,
289            ..Default::default()
290        };
291
292        let mut res = T::read_options(self, &options, args.clone())?;
293        res.after_parse(self, &options, args)?;
294
295        Ok(res)
296    }
297
298    /// Read `T` from the reader, assuming big-endian byte order, using the
299    /// given arguments.
300    fn read_be_args<T: BinRead>(&mut self, args: T::Args) -> BinResult<T> {
301        self.read_type_args(Endian::Big, args)
302    }
303
304    /// Read `T` from the reader, assuming little-endian byte order, using the
305    /// given arguments.
306    fn read_le_args<T: BinRead>(&mut self, args: T::Args) -> BinResult<T> {
307        self.read_type_args(Endian::Little, args)
308    }
309
310    /// Read `T` from the reader, assuming native-endian byte order, using the
311    /// given arguments.
312    fn read_ne_args<T: BinRead>(&mut self, args: T::Args) -> BinResult<T> {
313        self.read_type_args(Endian::Native, args)
314    }
315}
316
317impl<R: Read + Seek + Sized> BinReaderExt for R {}
318
319/// The collection of traits and types you'll likely need when working with binread and are
320/// unlikely to cause name conflicts.
321pub mod prelude {
322    pub use crate::BinRead;
323    pub use crate::BinReaderExt;
324    pub use crate::BinResult;
325}