• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

src/H03-May-2022-586287

.cargo-checksum.jsonH A D03-May-202289 11

.gitignoreH A D24-Nov-201730 43

.travis.ymlH A D24-Nov-201754 75

Cargo.tomlH A D01-Jan-1970972 2523

Cargo.toml.orig-cargoH A D24-Nov-2017450 1512

LICENSE-APACHEH A D24-Nov-201710.6 KiB202169

LICENSE-MITH A D24-Nov-20171 KiB2622

README.mdH A D24-Nov-20174.6 KiB147112

README.md

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