diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /third_party/rust/plain | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/plain')
-rw-r--r-- | third_party/rust/plain/.cargo-checksum.json | 1 | ||||
-rw-r--r-- | third_party/rust/plain/Cargo.toml | 24 | ||||
-rw-r--r-- | third_party/rust/plain/LICENSE-APACHE | 201 | ||||
-rw-r--r-- | third_party/rust/plain/LICENSE-MIT | 25 | ||||
-rw-r--r-- | third_party/rust/plain/README.md | 146 | ||||
-rw-r--r-- | third_party/rust/plain/src/error.rs | 6 | ||||
-rw-r--r-- | third_party/rust/plain/src/lib.rs | 158 | ||||
-rw-r--r-- | third_party/rust/plain/src/methods.rs | 198 | ||||
-rw-r--r-- | third_party/rust/plain/src/plain.rs | 96 | ||||
-rw-r--r-- | third_party/rust/plain/src/tests.rs | 123 |
10 files changed, 978 insertions, 0 deletions
diff --git a/third_party/rust/plain/.cargo-checksum.json b/third_party/rust/plain/.cargo-checksum.json new file mode 100644 index 0000000000..154d244037 --- /dev/null +++ b/third_party/rust/plain/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"7ca9f28917559a3066a55570c2af18d3d76656537d6826aeaea03b9b53703f03","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"bc12b75fd81829814d843a03fa52aad0e53355b1f13665e309ff7fa33c66e5b5","README.md":"016afabc736fc574d980b31ef5fec1b695c458b5ee5b53be7e6490772cdbf59d","src/error.rs":"febf6f4536848406692a7e81769934c629ce66d147b119bb33cba214598cf314","src/lib.rs":"2e66f345463c909a04cdc438b02a0bded92891eda64e4796ab02ec8bd66220ea","src/methods.rs":"cd78e4505a1e3aeb8ed08abcc2000d0b46b9c572becbc6fc90358332377a8081","src/plain.rs":"15d2f5ce4c1239b36871e1f5e1da0fc0fb8e3d73b52185cb77d3139f6c3be223","src/tests.rs":"cef8f21e98efd7dab3508843a375fb6dbb2b04e879779336ca70ac9f5eeb2c89"},"package":"b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"}
\ No newline at end of file diff --git a/third_party/rust/plain/Cargo.toml b/third_party/rust/plain/Cargo.toml new file mode 100644 index 0000000000..e08b586a6c --- /dev/null +++ b/third_party/rust/plain/Cargo.toml @@ -0,0 +1,24 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "plain" +version = "0.2.3" +authors = ["jzr"] +description = "A small Rust library that allows users to reinterpret data of certain types safely." +homepage = "https://github.com/randomites/plain" +documentation = "https://docs.rs/plain" +readme = "README.md" +keywords = ["plain", "pod", "ffi", "memory"] +categories = ["no-std", "data-structures", "parsing"] +license = "MIT/Apache-2.0" +repository = "https://github.com/randomites/plain" diff --git a/third_party/rust/plain/LICENSE-APACHE b/third_party/rust/plain/LICENSE-APACHE new file mode 100644 index 0000000000..16fe87b06e --- /dev/null +++ b/third_party/rust/plain/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/third_party/rust/plain/LICENSE-MIT b/third_party/rust/plain/LICENSE-MIT new file mode 100644 index 0000000000..fcb6e2f85a --- /dev/null +++ b/third_party/rust/plain/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2017 Plain contributors + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/plain/README.md b/third_party/rust/plain/README.md new file mode 100644 index 0000000000..fec0ccd062 --- /dev/null +++ b/third_party/rust/plain/README.md @@ -0,0 +1,146 @@ +# libplain + +[![Build Status](https://travis-ci.org/randomites/plain.svg?branch=master)](https://travis-ci.org/randomites/plain) +[![Current Crates.io Version](https://img.shields.io/crates/v/plain.svg)](https://crates.io/crates/plain) +[![Current Documentation](https://docs.rs/plain/badge.svg)](https://docs.rs/plain) + +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`](https://docs.rs/plain/0.2.0/plain/trait.Plain.html), which the user +of the crate uses to mark types for which operations of this library are safe. +See [`Plain`](https://docs.rs/plain/0.2.0/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_... + diff --git a/third_party/rust/plain/src/error.rs b/third_party/rust/plain/src/error.rs new file mode 100644 index 0000000000..0012eba9bc --- /dev/null +++ b/third_party/rust/plain/src/error.rs @@ -0,0 +1,6 @@ + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum Error { + TooShort, + BadAlignment, +} 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; diff --git a/third_party/rust/plain/src/methods.rs b/third_party/rust/plain/src/methods.rs new file mode 100644 index 0000000000..58be4a2500 --- /dev/null +++ b/third_party/rust/plain/src/methods.rs @@ -0,0 +1,198 @@ + +use core::{mem, slice}; + +use {Error, Plain}; + +/// Check if a byte slice is aligned suitably for type T. +#[inline] +pub fn is_aligned<T>(bytes: &[u8]) -> bool { + ((bytes.as_ptr() as usize) % mem::align_of::<T>()) == 0 +} + +#[inline(always)] +fn check_alignment<T>(bytes: &[u8]) -> Result<(), Error> { + if is_aligned::<T>(bytes) { + Ok(()) + } else { + Err(Error::BadAlignment) + } +} + +#[inline(always)] +fn check_length<T>(bytes: &[u8], len: usize) -> Result<(), Error> { + if mem::size_of::<T>() > 0 && (bytes.len() / mem::size_of::<T>()) < len { + Err(Error::TooShort) + } else { + Ok(()) + } +} + +/// Interpret data as bytes. Not safe for data with padding. +#[inline(always)] +pub unsafe fn as_bytes<S>(s: &S) -> &[u8] +where + S: ?Sized, +{ + let bptr = s as *const S as *const u8; + let bsize = mem::size_of_val(s); + slice::from_raw_parts(bptr, bsize) +} + +/// Interpret data as mutable bytes. +/// Reading is not safe for data with padding. Writing is ok. +#[inline(always)] +pub unsafe fn as_mut_bytes<S>(s: &mut S) -> &mut [u8] +where + S: Plain + ?Sized, +{ + let bptr = s as *mut S as *mut u8; + let bsize = mem::size_of_val(s); + slice::from_raw_parts_mut(bptr, bsize) +} + +/// Safely converts a byte slice to a reference. +/// +/// However, if the byte slice is not long enough +/// to contain target type, or if it doesn't +/// satisfy the type's alignment requirements, +/// the function returns an error. +/// +/// The function will not fail when the +/// byte slice is longer than necessary, since it is +/// a common practice to interpret the beginning of +/// a slice as a fixed-size header. +/// +/// In many cases it is preferrable to allocate +/// a value/slice of the target type and use +/// [`copy_from_bytes()`](fn.copy_from_bytes.html) to copy +/// data instead. That way, any issues with alignment +/// are implicitly avoided. +/// +#[inline] +pub fn from_bytes<T>(bytes: &[u8]) -> Result<&T, Error> +where + T: Plain, +{ + try!(check_alignment::<T>(bytes)); + try!(check_length::<T>(bytes, 1)); + Ok(unsafe { &*(bytes.as_ptr() as *const T) }) +} + +/// Similar to [`from_bytes()`](fn.from_bytes.html), +/// except that the output is a slice of T, instead +/// of a reference to a single T. All concerns about +/// alignment also apply here, but size is handled +/// differently. +/// +/// The result slice's length is set to be +/// `bytes.len() / size_of::<T>()`, and there +/// are no requirements for input size. I.e. +/// the result may be empty slice, and the input +/// slice doesn't necessarily have to end on `T`'s +/// boundary. The latter has pragmatic reasons: If the +/// length of the array is not known in advance, +/// e.g. if it's terminated by a special element, +/// it's perfectly legal to turn the whole rest +/// of data into `&[T]` and set the proper length +/// after inspecting the array. +/// +/// In many cases it is preferrable to allocate +/// a value/slice of the target type and use +/// [`copy_from_bytes()`](fn.copy_from_bytes.html) to copy +/// data instead. That way, any issues with alignment +/// are implicitly avoided. +/// +#[inline] +pub fn slice_from_bytes<T>(bytes: &[u8]) -> Result<&[T], Error> +where + T: Plain, +{ + let len = bytes.len() / mem::size_of::<T>(); + slice_from_bytes_len(bytes, len) +} + + +/// Same as [`slice_from_bytes()`](fn.slice_from_bytes.html), +/// except that it takes explicit length of the result slice. +/// +/// If the input slice cannot satisfy the length, returns error. +/// The input slice is allowed to be longer than necessary. +/// +#[inline] +pub fn slice_from_bytes_len<T>(bytes: &[u8], len: usize) -> Result<&[T], Error> +where + T: Plain, +{ + try!(check_alignment::<T>(bytes)); + try!(check_length::<T>(bytes, len)); + Ok(unsafe { + slice::from_raw_parts(bytes.as_ptr() as *const T, len) + }) +} + +/// See [`from_bytes()`](fn.from_bytes.html). +/// +/// Does the same, except with mutable references. +/// +#[inline] +pub fn from_mut_bytes<T>(bytes: &mut [u8]) -> Result<&mut T, Error> +where + T: Plain, +{ + try!(check_alignment::<T>(bytes)); + try!(check_length::<T>(bytes, 1)); + Ok(unsafe { &mut *(bytes.as_mut_ptr() as *mut T) }) +} + +/// See [`slice_from_bytes()`](fn.slice_from_bytes.html). +/// +/// Does the same, except with mutable references. +/// +#[inline] +pub fn slice_from_mut_bytes<T>(bytes: &mut [u8]) -> Result<&mut [T], Error> +where + T: Plain, +{ + let len = bytes.len() / mem::size_of::<T>(); + slice_from_mut_bytes_len(bytes, len) +} + +/// See [`slice_from_bytes_len()`](fn.slice_from_bytes_len.html). +/// +/// Does the same, except with mutable references. +/// +#[inline] +pub fn slice_from_mut_bytes_len<T>(bytes: &mut [u8], len: usize) -> Result<&mut [T], Error> +where + T: Plain, +{ + try!(check_alignment::<T>(bytes)); + try!(check_length::<T>(bytes, len)); + Ok(unsafe { + slice::from_raw_parts_mut(bytes.as_ptr() as *mut T, len) + }) +} + +/// Copies data from a byte slice into existing memory. +/// Suitable when [`from_bytes()`](fn.from_bytes.html) would normally +/// be used, but the data is not aligned properly in memory. +/// +/// For an example how to use it, see crate-level documentation. +/// +#[inline] +pub fn copy_from_bytes<T>(into: &mut T, bytes: &[u8]) -> Result<(), Error> +where + T: Plain + ?Sized, +{ + let sz = mem::size_of_val(into); + + if bytes.len() < sz { + return Err(Error::TooShort); + } + + unsafe { + as_mut_bytes(into).copy_from_slice(&bytes[..sz]); + } + + Ok(()) +} diff --git a/third_party/rust/plain/src/plain.rs b/third_party/rust/plain/src/plain.rs new file mode 100644 index 0000000000..35522006de --- /dev/null +++ b/third_party/rust/plain/src/plain.rs @@ -0,0 +1,96 @@ +use Error; + +/// A trait for plain data types that can be safely read from a byte slice. +/// +/// A type can be [`Plain`](trait.Plain.html) if it is `#repr(C)` and only contains +/// data with no possible invalid values. Types that _can't_ be `Plain` +/// include, but are not limited to, `bool`, `char`, `enum`s, tuples, +/// pointers and references. +/// +/// At this moment, `Drop` types are also not legal, because +/// compiler adds a special "drop flag" into the type. This is slated +/// to change in the future. +/// +/// On the other hand, arrays of a `Plain` type, and +/// structures where all members are plain (and not `Drop`), are okay. +/// +/// Structures that are not `#repr(C)`, while not necessarily illegal +/// in principle, are largely useless because they don't have a stable +/// layout. For example, the compiler is allowed to reorder fields +/// arbitrarily. +/// +/// All methods of this trait are implemented automatically as wrappers +/// for crate-level funtions. +/// +pub unsafe trait Plain { + #[inline(always)] + fn from_bytes(bytes: &[u8]) -> Result<&Self, Error> + where + Self: Sized, + { + ::from_bytes(bytes) + } + + #[inline(always)] + fn slice_from_bytes(bytes: &[u8]) -> Result<&[Self], Error> + where + Self: Sized, + { + ::slice_from_bytes(bytes) + } + + #[inline(always)] + fn slice_from_bytes_len(bytes: &[u8], len: usize) -> Result<&[Self], Error> + where + Self: Sized, + { + ::slice_from_bytes_len(bytes, len) + } + + #[inline(always)] + fn from_mut_bytes(bytes: &mut [u8]) -> Result<&mut Self, Error> + where + Self: Sized, + { + ::from_mut_bytes(bytes) + } + + #[inline(always)] + fn slice_from_mut_bytes(bytes: &mut [u8]) -> Result<&mut [Self], Error> + where + Self: Sized, + { + ::slice_from_mut_bytes(bytes) + } + + #[inline(always)] + fn slice_from_mut_bytes_len(bytes: &mut [u8], len: usize) -> Result<&mut [Self], Error> + where + Self: Sized, + { + ::slice_from_mut_bytes_len(bytes, len) + } + + #[inline(always)] + fn copy_from_bytes(&mut self, bytes: &[u8]) -> Result<(), Error> { + ::copy_from_bytes(self, bytes) + } +} + +unsafe impl Plain for u8 {} +unsafe impl Plain for u16 {} +unsafe impl Plain for u32 {} +unsafe impl Plain for u64 {} +unsafe impl Plain for usize {} + +unsafe impl Plain for i8 {} +unsafe impl Plain for i16 {} +unsafe impl Plain for i32 {} +unsafe impl Plain for i64 {} +unsafe impl Plain for isize {} + +unsafe impl<S> Plain for [S] +where + S: Plain, +{ +} diff --git a/third_party/rust/plain/src/tests.rs b/third_party/rust/plain/src/tests.rs new file mode 100644 index 0000000000..7ab1c3753e --- /dev/null +++ b/third_party/rust/plain/src/tests.rs @@ -0,0 +1,123 @@ + + +#![allow(dead_code)] + +use ::*; +use core::mem; + +#[repr(C)] +#[derive(Debug, Default, Copy, Eq, Clone, PartialEq)] +struct Dummy1 { + field1: u64, + field2: u32, + field3: u16, + field4: u8, + field5: u8, +} + +unsafe impl Plain for Dummy1 {} + +#[repr(C)] +#[derive(Debug, Default, Copy, Eq, Clone, PartialEq)] +struct Dummy2 { + field1: u8, + field2: u8, + field3: u16, + field4: u32, + field5: u64, +} + +unsafe impl Plain for Dummy2 {} + +fn as_bytes<T: ?Sized>(r: &T) -> &[u8] { + unsafe { methods::as_bytes(r) } +} + +fn as_mut_bytes<T: Plain + ?Sized>(r: &mut T) -> &mut [u8] { + unsafe { methods::as_mut_bytes(r) } +} + +#[test] +fn one_too_short() { + let b = vec![0u8; mem::size_of::<Dummy1>() - 1]; + + let r = Dummy1::from_bytes(&b); + assert!(r == Err(Error::TooShort)); +} + +#[test] +fn unaligned() { + let b = vec![0u8; mem::size_of::<Dummy1>() + 1]; + let b = &b[1..]; + + let r = Dummy1::from_bytes(&b); + assert!(r == Err(Error::BadAlignment)); +} + +#[test] +fn copy_test() { + let t1 = Dummy1 { + field1: 0xaaaaaaaaaaaaaaaau64, + field2: 0xbbbbbbbbu32, + field3: 0xccccu16, + field4: 0xddu8, + field5: 0xeeu8, + }; + + let mut t2 = Dummy2::default(); + + assert!(t2.copy_from_bytes(as_bytes(&t1)) == Ok(())); + + assert!(t2.field1 == 0xaau8); + assert!(t2.field2 == 0xaau8); + assert!(t2.field3 == 0xaaaau16); + assert!(t2.field4 == 0xaaaaaaaau32); + assert!(t2.field5 == 0xbbbbbbbbccccddeeu64 || t2.field5 == 0xeeddccccbbbbbbbbu64); + + let sz = mem::size_of::<Dummy2>(); + assert!(t2.copy_from_bytes(&as_bytes(&t1)[..sz - 1]) == Err(Error::TooShort)); +} + +#[test] +fn basic_function() { + let t1 = Dummy1 { + field1: 0xaaaaaaaaaaaaaaaau64, + field2: 0xbbbbbbbbu32, + field3: 0xccccu16, + field4: 0xddu8, + field5: 0xeeu8, + }; + + let r1: &Dummy2 = from_bytes(as_bytes(&t1)).unwrap(); + + assert!(r1.field1 == 0xaau8); + assert!(r1.field2 == 0xaau8); + assert!(r1.field3 == 0xaaaau16); + assert!(r1.field4 == 0xaaaaaaaau32); + assert!(r1.field5 == 0xbbbbbbbbccccddeeu64 || r1.field5 == 0xeeddccccbbbbbbbbu64); + + let r2 = as_bytes(r1); + assert!(r2.len() == mem::size_of::<Dummy1>()); + assert!(r2[5] == 0xaa); + + let size = r2.len(); + let r3 = as_bytes(r2); + assert!(r3.len() == size); + + let r4 = Dummy1::from_bytes(r3).unwrap(); + + let r5 = from_bytes::<Dummy2>(as_bytes(r4)).unwrap(); + + { + let r6 = slice_from_bytes::<Dummy1>(as_bytes(r5)).unwrap(); + + assert!(r6.len() == 1); + assert!(t1 == r6[0]); + } + + let r7 = slice_from_bytes::<u64>(as_bytes(r5)).unwrap(); + assert!(r7.len() == 2); + + assert!(r7[0] == 0xaaaaaaaaaaaaaaaau64); + assert!(r7[1] == 0xbbbbbbbbccccddeeu64 || r7[1] == 0xeeddccccbbbbbbbbu64); +} |