| Crates.io | structview |
| lib.rs | structview |
| version | 1.1.0 |
| created_at | 2018-12-19 12:11:25.667125+00 |
| updated_at | 2020-06-05 17:11:20.717153+00 |
| description | Viewing binary data as high-level data structures, safely. |
| homepage | |
| repository | https://gitlab.com/ra_kete/structview-rs |
| max_upload_size | |
| id | 102727 |
| size | 25,565 |
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
directly.
The following example demonstrates viewing a slice of binary data as a simple struct:
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,
as well as types for safely viewing integer fields.
Requires Rust version 1.38.0 or newer.
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:
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<Box<[Self]>, 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::<Self>() > 0 and will panic
otherwise.
Implementing View is unsafe as one must ensure that:
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.
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<LittleEndian>, a type generic over a ByteOrder
supplied by the byteorder crate. The
following table lists all provided integer views:
| bit-width | generic | little-endian | big-endian |
|---|---|---|---|
| 16 | I16<BO> |
i16_le |
i16_be |
U16<BO> |
u16_le |
u16_be |
|
| 32 | I32<BO> |
i32_le |
i32_be |
U32<BO> |
u32_le |
u32_be |
|
| 64 | I64<BO> |
i64_le |
i64_be |
U64<BO> |
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 for its
integer type.
no_std contextsstructview 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:
[dependencies.structview]
version = "1"
default-features = false
If std is disabled:
structview::Error does not impl std::error::ErrorView::view_boxed_slice is not availableThis project is licensed under the MIT 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.