summaryrefslogtreecommitdiffstats
path: root/third_party/rust/plain/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/plain/src/lib.rs')
-rw-r--r--third_party/rust/plain/src/lib.rs158
1 files changed, 158 insertions, 0 deletions
diff --git a/third_party/rust/plain/src/lib.rs b/third_party/rust/plain/src/lib.rs
new file mode 100644
index 0000000000..f4eb4badf1
--- /dev/null
+++ b/third_party/rust/plain/src/lib.rs
@@ -0,0 +1,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;