# structview `structview` is a Rust library for casting references to binary data into references to higher-level data structures, such as structs, unions, and arrays. The implemented approach is similar to a common pattern used when parsing binary data formats in C, where `char *`s representing the raw data are directly cast to, for example, struct pointers. This technique has the benefits of being simple and highly efficient. Unfortunately, it is also unsafe, as issues with alignment and integer endianess are usually ignored. `structview` avoids these issues by providing a safe interface to its users. The intended use-case for this crate is parsing of binary data formats, particularly if one is only interested in the value of certain fields, not all of them. In these cases `structview` can be used to efficiently find the fields of interest without having to potentially perform byteorder conversion for all the irrelevant ones. If all fields need to be parsed anyway, it is probably more straightforward to use the [`byteorder` crate](https://crates.io/crates/byteorder) directly. ## Example The following example demonstrates viewing a slice of binary data as a simple struct: ```rust use structview::{u32_le, View}; #[derive(Clone, Copy, View)] #[repr(C)] struct Animal { name: [u8; 4], number_of_heads: u8, number_of_legs: u32_le, } fn main() -> Result<(), structview::Error> { let data = [0x43, 0x61, 0x74, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00]; let animal = Animal::view(&data)?; assert_eq!(animal.name, *b"Cat\x00"); assert_eq!(animal.number_of_heads, 1); assert_eq!(animal.number_of_legs.to_int(), 4); Ok(()) } ``` As the example shows, `structview` makes reinterpreting raw data both safe and convenient by providing [an (automatically derivable) trait `View`](#view-trait), as well as [types for safely viewing integer fields](#integer-views). ## Requirements Requires Rust version **1.38.0** or newer. ## The `View` Trait By implementing the `View` trait, a type promises it is safe to be cast from raw binary data. The trait adds several view methods to implementing types, which enable producing references to instances of these types from byte slices: ```rust pub unsafe trait View: Copy { fn view(data: &[u8]) -> Result<&Self, structview::Error> { ... } fn view_slice(data: &[u8]) -> Result<&[Self], Error> { ... } fn view_boxed_slice(data: Box<[u8]>) -> Result, Error> { ... } } ``` All view methods check the length of the given `data` and return `Error::NotEnoughData` if there are too few bytes. Additionally, the two slice view methods require that `mem::size_of::() > 0` and will panic otherwise. Implementing `View` is unsafe as one must ensure that: - every possible raw byte value constitutes valid data for the implementing type - the implementing type is 1-byte aligned - the compiler doesn't change the order of the implementing type's fields (in case of a compound type) `structview` already implements `View` for the 1-byte integer types (`i8` and `u8`), arrays of `View` types, and the provided integer views (`u32_le` and friends). Based on these primitives, users can create views for their own structs and unions. Manually implementing the `View` trait is not recommended. Instead, it should be automatically derived as demonstrated in the example above. The derive ensures safety be enforcing that implementing structs and unions are `repr(C)` and contain only `View` fields. This is sufficient to satisfy the safety requirements mentioned above. ## Integer Views While the single-byte integers `i8` and `u8` can be safely cast from raw data, wider integers can not: Their alignment is incompatible with the 1-byte alignment of byte slices and their (application-defined) endianess might be incompatible with the system's native byteorder. `structview` solves this by casting these wider integer types to special integer views instead: wrappers around `u8` arrays of appropriate sizes that provide methods to parse the raw data into the actual integers. The `u32_le` type used in the example is one of these integer views. It is actually an alias for `U32`, a type generic over a `ByteOrder` supplied by the [`byteorder` crate](https://crates.io/crates/byteorder). The following table lists all provided integer views: | bit-width | generic | little-endian | big-endian | | :-------: | :-------: | :-----------: | :--------: | | 16 | `I16` | `i16_le` | `i16_be` | | | `U16` | `u16_le` | `u16_be` | | 32 | `I32` | `i32_le` | `i32_be` | | | `U32` | `u32_le` | `u32_be` | | 64 | `I64` | `i64_le` | `i64_be` | | | `U64` | `u64_le` | `u64_be` | Each integer view provides a `to_int` method that parses and returns the respective integer value. Each integer view also implements the [`From` conversion trait](https://doc.rust-lang.org/std/convert/trait.From.html) for its integer type. ## Use in `no_std` contexts `structview` has a feature, `std`, that is enabled by default. To use the crate in `no_std` contexts, disable the default features in the `Cargo.toml`: ```toml [dependencies.structview] version = "1" default-features = false ``` If `std` is disabled: - `structview::Error` does not impl `std::error::Error` - `View::view_boxed_slice` is not available ## License This project is licensed under the MIT license ([LICENSE](LICENSE) or http://opensource.org/licenses/MIT). Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in structview by you, shall be licensed as above, without any additional terms or conditions.