//! A small Rust library that allows users to interpret arrays of bytes //! as certain kinds of structures safely. //! //! This crate provides an unsafe trait [`Plain`](trait.Plain.html), which the user //! of the crate uses to mark types for which operations of this library are safe. //! See [`Plain`](trait.Plain.html) for the contractual obligation. //! //! Other than that, everything else in this crate is perfectly safe to use as long //! as the `Plain` trait is not implemented on inadmissible types (similar to how //! `Send` and `Sync` in the standard library work). //! //! # Purpose //! //! In low level systems development, it is sometimes necessary to //! interpret locations in memory as data structures. Functions of //! this crate serve to avoid pitfalls associated with that, without //! having to resort to big, full-featured (de)serialization libraries. //! //! On the other hand, this crate contains no provisions when it comes //! to handling differences in encoding and byte ordering between //! platforms. As such, it is entirely unsuitable for processing //! external data such as file contents or network packets. //! //! # Examples //! //! To start using the crate, simply do `extern crate plain;`. //! //! If you want your plain types to have methods from this crate, also include `use plain.Plain;`. //! //! Then it's just a matter of marking the right types and using them. //! //! ``` //! //! extern crate plain; //! use plain::Plain; //! use std::mem; //! //! //! #[repr(C)] //! #[derive(Default)] //! struct ELF64Header { //! pub e_ident: [u8; 16], //! pub e_type: u16, //! pub e_machine: u16, //! pub e_version: u32, //! pub e_entry: u64, //! pub e_phoff: u64, //! pub e_shoff: u64, //! pub e_flags: u32, //! pub e_ehsize: u16, //! pub e_phentsize: u16, //! pub e_phnum: u16, //! pub e_shentsize: u16, //! pub e_shnum: u16, //! pub e_shstrndx: u16, //! } //! //! // SAFE: ELF64Header satisfies all the requirements of `Plain`. //! unsafe impl Plain for ELF64Header {} //! //! impl ELF64Header { //! fn from_bytes(buf: &[u8]) -> &ELF64Header { //! plain::from_bytes(buf).expect("The buffer is either too short or not aligned!") //! } //! //! fn from_mut_bytes(buf: &mut [u8]) -> &mut ELF64Header { //! plain::from_mut_bytes(buf).expect("The buffer is either too short or not aligned!") //! } //! //! fn copy_from_bytes(buf: &[u8]) -> ELF64Header { //! let mut h = ELF64Header::default(); //! h.copy_from_bytes(buf).expect("The buffer is too short!"); //! h //! } //! } //! //! # fn process_elf(elf: &ELF64Header) {} //! //! // Conditional copying for ultimate hackery. //! fn opportunistic_elf_processing(buf: &[u8]) { //! if plain::is_aligned::(buf) { //! // No copy necessary. //! let elf_ref = ELF64Header::from_bytes(buf); //! process_elf(elf_ref); //! } else { //! // Not aligned properly, copy to stack first. //! let elf = ELF64Header::copy_from_bytes(buf); //! process_elf(&elf); //! } //! } //! //! #[repr(C)] //! #[derive(Default, Copy, Clone)] //! struct ArrayEntry { //! pub name: [u8; 32], //! pub tag: u32, //! pub score: u32, //! } //! //! // SAFE: ArrayEntry satisfies all the requirements of `Plain`. //! unsafe impl Plain for ArrayEntry {} //! //! fn array_from_bytes(buf: &[u8]) -> &[ArrayEntry] { //! // NOTE: length is not a concern here, //! // since slice_from_bytes() can return empty slice. //! //! match plain::slice_from_bytes(buf) { //! Err(_) => panic!("The buffer is not aligned!"), //! Ok(arr) => arr, //! } //! } //! //! fn array_from_unaligned_bytes(buf: &[u8]) -> Vec { //! let length = buf.len() / mem::size_of::(); //! let mut result = vec![ArrayEntry::default(); length]; //! (&mut result).copy_from_bytes(buf).expect("Cannot fail here."); //! result //! } //! //! # fn main() {} //! //! ``` //! //! # Comparison to [`pod`](https://crates.io/crates/pod) //! //! [`pod`](https://crates.io/crates/pod) is another crate created to help working with plain data. //! The major difference between `pod` and `plain` is scope. //! //! `plain` currently provides only a few functions (+method wrappers) and its implementation //! involves very few lines of unsafe code. It can be used in `no_std` code. Also, it doesn't //! deal with [endianness](https://en.wikipedia.org/wiki/Endianness) in any way, //! so it is only suitable for certain kinds of low-level work. //! //! `pod`, on the other hand, provides a wide arsenal //! of various methods, most of which may be unnecessary for a given use case. //! It has dependencies on `std` as well as other crates, but among other things //! it provides tools to handle endianness properly. //! //! In short, `plain` is much, much _plainer_... #![no_std] mod error; pub use error::Error; mod plain; pub use plain::Plain; mod methods; pub use methods::{as_bytes, as_mut_bytes, copy_from_bytes, from_bytes, from_mut_bytes, is_aligned, slice_from_bytes, slice_from_bytes_len, slice_from_mut_bytes, slice_from_mut_bytes_len}; #[cfg(test)] #[macro_use] extern crate std; #[cfg(test)] mod tests;