1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
//! 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::<ELF64Header>(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<ArrayEntry> {
//!		let length = buf.len() / mem::size_of::<ArrayEntry>();
//! 	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;