plain/lib.rs
1//! A small Rust library that allows users to interpret arrays of bytes
2//! as certain kinds of structures safely.
3//!
4//! This crate provides an unsafe trait [`Plain`](trait.Plain.html), which the user
5//! of the crate uses to mark types for which operations of this library are safe.
6//! See [`Plain`](trait.Plain.html) for the contractual obligation.
7//!
8//! Other than that, everything else in this crate is perfectly safe to use as long
9//! as the `Plain` trait is not implemented on inadmissible types (similar to how
10//! `Send` and `Sync` in the standard library work).
11//!
12//! # Purpose
13//!
14//! In low level systems development, it is sometimes necessary to
15//! interpret locations in memory as data structures. Functions of
16//! this crate serve to avoid pitfalls associated with that, without
17//! having to resort to big, full-featured (de)serialization libraries.
18//!
19//! On the other hand, this crate contains no provisions when it comes
20//! to handling differences in encoding and byte ordering between
21//! platforms. As such, it is entirely unsuitable for processing
22//! external data such as file contents or network packets.
23//!
24//! # Examples
25//!
26//! To start using the crate, simply do `extern crate plain;`.
27//!
28//! If you want your plain types to have methods from this crate, also include `use plain.Plain;`.
29//!
30//! Then it's just a matter of marking the right types and using them.
31//!
32//! ```
33//!
34//! extern crate plain;
35//! use plain::Plain;
36//! use std::mem;
37//!
38//!
39//! #[repr(C)]
40//! #[derive(Default)]
41//! struct ELF64Header {
42//! pub e_ident: [u8; 16],
43//! pub e_type: u16,
44//! pub e_machine: u16,
45//! pub e_version: u32,
46//! pub e_entry: u64,
47//! pub e_phoff: u64,
48//! pub e_shoff: u64,
49//! pub e_flags: u32,
50//! pub e_ehsize: u16,
51//! pub e_phentsize: u16,
52//! pub e_phnum: u16,
53//! pub e_shentsize: u16,
54//! pub e_shnum: u16,
55//! pub e_shstrndx: u16,
56//! }
57//!
58//! // SAFE: ELF64Header satisfies all the requirements of `Plain`.
59//! unsafe impl Plain for ELF64Header {}
60//!
61//! impl ELF64Header {
62//! fn from_bytes(buf: &[u8]) -> &ELF64Header {
63//! plain::from_bytes(buf).expect("The buffer is either too short or not aligned!")
64//! }
65//!
66//! fn from_mut_bytes(buf: &mut [u8]) -> &mut ELF64Header {
67//! plain::from_mut_bytes(buf).expect("The buffer is either too short or not aligned!")
68//! }
69//!
70//! fn copy_from_bytes(buf: &[u8]) -> ELF64Header {
71//! let mut h = ELF64Header::default();
72//! h.copy_from_bytes(buf).expect("The buffer is too short!");
73//! h
74//! }
75//! }
76//!
77//! # fn process_elf(elf: &ELF64Header) {}
78//!
79//! // Conditional copying for ultimate hackery.
80//! fn opportunistic_elf_processing(buf: &[u8]) {
81//! if plain::is_aligned::<ELF64Header>(buf) {
82//! // No copy necessary.
83//! let elf_ref = ELF64Header::from_bytes(buf);
84//! process_elf(elf_ref);
85//! } else {
86//! // Not aligned properly, copy to stack first.
87//! let elf = ELF64Header::copy_from_bytes(buf);
88//! process_elf(&elf);
89//! }
90//! }
91//!
92//! #[repr(C)]
93//! #[derive(Default, Copy, Clone)]
94//! struct ArrayEntry {
95//! pub name: [u8; 32],
96//! pub tag: u32,
97//! pub score: u32,
98//! }
99//!
100//! // SAFE: ArrayEntry satisfies all the requirements of `Plain`.
101//! unsafe impl Plain for ArrayEntry {}
102//!
103//! fn array_from_bytes(buf: &[u8]) -> &[ArrayEntry] {
104//! // NOTE: length is not a concern here,
105//! // since slice_from_bytes() can return empty slice.
106//!
107//! match plain::slice_from_bytes(buf) {
108//! Err(_) => panic!("The buffer is not aligned!"),
109//! Ok(arr) => arr,
110//! }
111//! }
112//!
113//! fn array_from_unaligned_bytes(buf: &[u8]) -> Vec<ArrayEntry> {
114//! let length = buf.len() / mem::size_of::<ArrayEntry>();
115//! let mut result = vec![ArrayEntry::default(); length];
116//! (&mut result).copy_from_bytes(buf).expect("Cannot fail here.");
117//! result
118//! }
119//!
120//! # fn main() {}
121//!
122//! ```
123//!
124//! # Comparison to [`pod`](https://crates.io/crates/pod)
125//!
126//! [`pod`](https://crates.io/crates/pod) is another crate created to help working with plain data.
127//! The major difference between `pod` and `plain` is scope.
128//!
129//! `plain` currently provides only a few functions (+method wrappers) and its implementation
130//! involves very few lines of unsafe code. It can be used in `no_std` code. Also, it doesn't
131//! deal with [endianness](https://en.wikipedia.org/wiki/Endianness) in any way,
132//! so it is only suitable for certain kinds of low-level work.
133//!
134//! `pod`, on the other hand, provides a wide arsenal
135//! of various methods, most of which may be unnecessary for a given use case.
136//! It has dependencies on `std` as well as other crates, but among other things
137//! it provides tools to handle endianness properly.
138//!
139//! In short, `plain` is much, much _plainer_...
140#![no_std]
141
142mod error;
143pub use error::Error;
144
145mod plain;
146pub use plain::Plain;
147
148mod methods;
149pub use methods::{as_bytes, as_mut_bytes, copy_from_bytes, from_bytes, from_mut_bytes, is_aligned,
150 slice_from_bytes, slice_from_bytes_len, slice_from_mut_bytes,
151 slice_from_mut_bytes_len};
152
153#[cfg(test)]
154#[macro_use]
155extern crate std;
156
157#[cfg(test)]
158mod tests;