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