diff options
Diffstat (limited to 'vendor/lebe')
-rw-r--r-- | vendor/lebe/.cargo-checksum.json | 1 | ||||
-rw-r--r-- | vendor/lebe/Cargo.toml | 61 | ||||
-rw-r--r-- | vendor/lebe/LICENSE-BSD-3-Clause | 26 | ||||
-rw-r--r-- | vendor/lebe/README.md | 90 | ||||
-rw-r--r-- | vendor/lebe/benches/benches.rs | 137 | ||||
-rw-r--r-- | vendor/lebe/src/lib.rs | 578 | ||||
-rw-r--r-- | vendor/lebe/tests/tests.rs | 213 |
7 files changed, 1106 insertions, 0 deletions
diff --git a/vendor/lebe/.cargo-checksum.json b/vendor/lebe/.cargo-checksum.json new file mode 100644 index 0000000..14ab426 --- /dev/null +++ b/vendor/lebe/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"365b393a87b2706f0eb52139c1ce3909e47ca4e1226cf7bdcae4e4c1d0f386b5","LICENSE-BSD-3-Clause":"f1b2855ae21da69e0a02499e13f57f3be92db7abbbffe9a89f33e04e9e21ec81","README.md":"d9f3a595b28433de13f0c88ae049a73af3d88068f08dd8364d45504224651448","benches/benches.rs":"a73feca65ddde13e082121cc2268318fc72a87029f2d7106f939a4356af3e232","src/lib.rs":"72567c8ad6ae8e59d59ce2e9ffcfa8f013bb24f104b128d92a52f034f592b777","tests/tests.rs":"76b860f51bef80c4223f06998fbed540d9bcd0ddc4fa1ed0f0c0964e3d58bdcc"},"package":"03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8"}
\ No newline at end of file diff --git a/vendor/lebe/Cargo.toml b/vendor/lebe/Cargo.toml new file mode 100644 index 0000000..38a619e --- /dev/null +++ b/vendor/lebe/Cargo.toml @@ -0,0 +1,61 @@ +# 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 are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "lebe" +version = "0.5.2" +authors = ["johannesvollmer <johannes596@t-online.de>"] +description = "Tiny, dead simple, high performance endianness conversions with a generic API" +documentation = "https://docs.rs/crate/lebe/" +readme = "README.md" +keywords = [ + "endianness", + "binary", + "io", + "byteorder", + "endian", +] +categories = [ + "encoding", + "filesystem", + "algorithms", +] +license = "BSD-3-Clause" +repository = "https://github.com/johannesvollmer/lebe" + +[profile.bench] +lto = true +debug = true + +[lib] +path = "src/lib.rs" +test = true +doctest = true +bench = true +doc = true +plugin = false +proc-macro = false + +[[bench]] +name = "benches" +harness = false + +[dev-dependencies.bencher] +version = "0.1.5" + +[dev-dependencies.byteorder] +version = "1.4.3" + +[features] + +[badges.maintenance] +status = "actively-developed" diff --git a/vendor/lebe/LICENSE-BSD-3-Clause b/vendor/lebe/LICENSE-BSD-3-Clause new file mode 100644 index 0000000..8c53234 --- /dev/null +++ b/vendor/lebe/LICENSE-BSD-3-Clause @@ -0,0 +1,26 @@ +Copyright (c) 2022 Contributors to the lebe Project. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/lebe/README.md b/vendor/lebe/README.md new file mode 100644 index 0000000..d32a28a --- /dev/null +++ b/vendor/lebe/README.md @@ -0,0 +1,90 @@ +[![Rust Docs](https://docs.rs/lebe/badge.svg)](https://docs.rs/lebe) +[![Crate Crate](https://img.shields.io/crates/v/lebe.svg)](https://crates.io/crates/lebe) +![Lines of Code](https://tokei.rs/b1/github/johannesvollmer/lebe?category=code) + + +# LEBE +Tiny, dead simple, high performance endianness conversions with a generic API. +This crate purposefully does not have a different method, like `write_u16(my_value)`, for each primitive type. Instead, this uses generic type inference: `write(my_u16)`. + +# Purpose +This crate has exactly two purposes: + 1. Simple conversion between slices of primitives and byte arrays without unsafe code + 2. Simple and fast conversion from one endianness to the other one + +The [byteorder crate](https://github.com/BurntSushi/byteorder) uses ![Lines of Code](https://tokei.rs/b1/github/BurntSushi/byteorder?category=code) for this. + +This simplifies reading and writing binary data to files or network streams. + + +# Usage + +Write values. +```rust + use lebe::io::WriteEndian; + use std::io::Write; + + fn main(){ + let mut output_bytes: Vec<u8> = Vec::new(); + + let numbers: &[i32] = &[ 32, 102, 420, 594 ]; + output_bytes.write_as_little_endian(numbers.len()).unwrap(); + output_bytes.write_as_little_endian(numbers).unwrap(); + } +``` + +Read numbers. +```rust + use lebe::io::ReadEndian; + use std::io::Read; + + fn main(){ + let mut input_bytes: &[u8] = &[ 3, 244 ]; + let number: u16 = input_bytes.read_from_little_endian().unwrap(); + } +``` + +Read slices. +```rust + use lebe::io::ReadEndian; + use std::io::Read; + + fn main(){ + let mut input_bytes: &[u8] = &[ 0, 2, 0, 3, 244, 1, 0, 3, 244, 1 ]; + + let len: u16 = input_bytes.read_from_little_endian().unwrap(); + let mut numbers = vec![ 0.0; len as usize ]; + + input_bytes.read_from_little_endian_into(numbers.as_mut_slice()).unwrap(); + } +``` + +Convert slices in-place. +```rust + use lebe::Endian; + + fn main(){ + let mut numbers: &[i32] = &[ 32, 102, 420, 594 ]; + numbers.convert_current_to_little_endian(); + } +``` + + +# Why not use [byteorder](https://crates.io/crates/byteorder)? +This crate supports batch-writing slices with native speed +where the os has the matching endianness. Writing slices in `byteorder` +must be done manually, and may be slower than expected. +This crate does provide u8 and i8 slice operations for completeness. +Also, the API of this crate looks simpler. + +# Why not use [endianness](https://crates.io/crates/endianness)? +This crate has no runtime costs, just as `byteorder`. + +# Why not use this crate? +The other crates probably have better documentation. + + +# Fun Facts +LEBE is made up from 'le' for little endian and 'be' for big endian. +If you say that word using english pronounciation, +a german might think you said the german word for 'love'. diff --git a/vendor/lebe/benches/benches.rs b/vendor/lebe/benches/benches.rs new file mode 100644 index 0000000..eca67f5 --- /dev/null +++ b/vendor/lebe/benches/benches.rs @@ -0,0 +1,137 @@ +#[macro_use] +extern crate bencher; + +use bencher::Bencher; +use lebe::prelude::*; +use byteorder::{ReadBytesExt, LittleEndian, BigEndian, WriteBytesExt}; +use std::io::{Read, Write, Cursor}; + +const COUNT_8: usize = 2048; +const COUNT_16: usize = COUNT_8 / 2; +const COUNT_32: usize = COUNT_8 / 4; +const COUNT_64: usize = COUNT_8 / 8; + + +fn bytes(count: usize) -> Cursor<Vec<u8>> { + let vec: Vec<u8> = (0..count).map(|i| (i % 256) as u8).collect(); + Cursor::new(vec) +} + +fn floats(count: usize) -> Vec<f32> { + (0..count).map(|i| i as f32).collect() +} + +fn read_slice_f32_le_crate(bench: &mut Bencher) { + bench.iter(move ||{ + let mut target = vec![ 0_f32; COUNT_32 ]; + bencher::black_box(bytes(COUNT_8).read_from_little_endian_into(target.as_mut_slice())).unwrap(); + bencher::black_box(target); + }) +} + +fn read_slice_f32_le_byteorder(bench: &mut Bencher) { + bench.iter(move ||{ + let mut target = vec![ 0_f32; COUNT_32 ]; + bencher::black_box(bytes(COUNT_8).read_f32_into::<LittleEndian>(target.as_mut_slice())).unwrap(); + bencher::black_box(target); + }) +} + +fn read_slice_f32_be_crate(bench: &mut Bencher) { + bench.iter(move ||{ + let mut target = vec![ 0_f32; COUNT_32 ]; + bencher::black_box(bytes(COUNT_8).read_from_big_endian_into(target.as_mut_slice())).unwrap(); + bencher::black_box(target); + }) +} + +fn read_slice_f32_be_byteorder(bench: &mut Bencher) { + bench.iter(move ||{ + let mut target = vec![ 0_f32; COUNT_32 ]; + bencher::black_box(bytes(COUNT_8).read_f32_into::<BigEndian>(target.as_mut_slice())).unwrap(); + bencher::black_box(target); + }) +} + +// FIXME faster than baseline?!?!! +fn write_slice_f32_le_crate(bench: &mut Bencher) { + bench.iter(move ||{ + let data = floats(COUNT_32); + let mut output = Vec::with_capacity(COUNT_8); + + bencher::black_box(output.write_as_little_endian(data.as_slice())).unwrap(); + assert_eq!(output.len(), COUNT_8); + bencher::black_box(output); + }) +} + +fn write_slice_f32_le_byteorder(bench: &mut Bencher) { + bench.iter(move ||{ + let data = floats(COUNT_32); + let mut output = Vec::with_capacity(COUNT_8); + + for number in data { + bencher::black_box(output.write_f32::<LittleEndian>(number)).unwrap(); + } + + assert_eq!(output.len(), COUNT_8); + bencher::black_box(output); + }) +} + + +fn write_slice_f32_be_crate(bench: &mut Bencher) { + bench.iter(move ||{ + let data = floats(COUNT_32); + let mut output = Vec::with_capacity(COUNT_8); + + bencher::black_box(output.write_as_big_endian(data.as_slice())).unwrap(); + assert_eq!(output.len(), COUNT_8); + bencher::black_box(output); + }) +} + +fn write_slice_f32_be_byteorder(bench: &mut Bencher) { + bench.iter(move ||{ + let data = floats(COUNT_32); + let mut output = Vec::with_capacity(COUNT_8); + + for number in data { + bencher::black_box(output.write_f32::<BigEndian>(number)).unwrap(); + } + + assert_eq!(output.len(), COUNT_8); + bencher::black_box(output); + }) +} + + + +fn read_slice_baseline(bench: &mut Bencher) { + bench.iter(move ||{ + let mut target = vec![ 0_u8; COUNT_8 ]; + bencher::black_box(bytes(COUNT_8).read_exact(target.as_mut_slice())).unwrap(); + bencher::black_box(target); + }) +} + + +fn write_slice_baseline(bench: &mut Bencher) { + bench.iter(move ||{ + let data = bytes(COUNT_8).into_inner(); + let mut output = Vec::with_capacity(COUNT_8); + + bencher::black_box(output.write_all(data.as_slice())).unwrap(); + bencher::black_box(output); + }) +} + +benchmark_group!( + benches, + read_slice_f32_be_byteorder, read_slice_f32_be_crate, read_slice_f32_le_byteorder, + read_slice_f32_le_crate, write_slice_f32_le_byteorder, write_slice_f32_le_crate, + write_slice_f32_be_byteorder, write_slice_f32_be_crate, + read_slice_baseline, write_slice_baseline +); + +benchmark_main!(benches);
\ No newline at end of file diff --git a/vendor/lebe/src/lib.rs b/vendor/lebe/src/lib.rs new file mode 100644 index 0000000..fbb4482 --- /dev/null +++ b/vendor/lebe/src/lib.rs @@ -0,0 +1,578 @@ +#![warn( + missing_docs, unused, + trivial_numeric_casts, + future_incompatible, + rust_2018_compatibility, + rust_2018_idioms, + clippy::all +)] + +#![doc(html_root_url = "https://docs.rs/lebe/0.5.0")] + +//! Dead simple endianness conversions. +//! The following operations are implemented on +//! `u8`, `i8`, `u16`, `i16`, `u32`, `i32`, `u64`, `i64`, `u128`, `i128`, `f32`, `f64`: +//! +//! +//! ### Read Numbers +//! ```rust +//! use lebe::prelude::*; +//! let mut reader: &[u8] = &[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]; +//! +//! let number : u64 = reader.read_from_little_endian()?; +//! let number = u64::read_from_big_endian(&mut reader)?; +//! # Ok::<(), std::io::Error>(()) +//! ``` +//! +//! ### Read Slices +//! ```rust +//! use std::io::Read; +//! use lebe::prelude::*; +//! let mut reader: &[u8] = &[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]; +//! +//! let mut numbers: &mut [u64] = &mut [0, 0]; +//! reader.read_from_little_endian_into(numbers)?; +//! # Ok::<(), std::io::Error>(()) +//! ``` +//! +//! ### Write Numbers +//! ```rust +//! use std::io::Read; +//! use lebe::prelude::*; +//! let mut writer: Vec<u8> = Vec::new(); +//! +//! let number: u64 = 1237691; +//! writer.write_as_big_endian(&number)?; +//! # Ok::<(), std::io::Error>(()) +//! ``` +//! +//! ### Write Slices +//! ```rust +//! use std::io::Write; +//! use lebe::prelude::*; +//! let mut writer: Vec<u8> = Vec::new(); +//! +//! let numbers: &[u64] = &[1_u64, 234545_u64]; +//! writer.write_as_little_endian(numbers)?; +//! # Ok::<(), std::io::Error>(()) +//! ``` +//! + + +/// Exports some of the most common types. +pub mod prelude { + pub use super::Endian; + pub use super::io::{ WriteEndian, ReadEndian, ReadPrimitive }; +} + +/// Represents values that can swap their bytes to reverse their endianness. +/// +/// Supports converting values in-place using [`swap_bytes`] or [`convert_current_to_little_endian`]: +/// Supports converting while transferring ownership using +/// [`from_little_endian_into_current`] or [`from_current_into_little_endian`]. +/// +/// +/// For the types `u8`, `i8`, `&[u8]` and `&[i8]`, this trait will never transform any data, +/// as they are just implemented for completeness. +pub trait Endian { + + /// Swaps all bytes in this value, inverting its endianness. + fn swap_bytes(&mut self); + + /// On a little endian machine, this does nothing. + /// On a big endian machine, the bytes of this value are reversed. + #[inline] fn convert_current_to_little_endian(&mut self) { + #[cfg(target_endian = "big")] { + self.swap_bytes(); + } + } + + /// On a big endian machine, this does nothing. + /// On a little endian machine, the bytes of this value are reversed. + #[inline] fn convert_current_to_big_endian(&mut self) { + #[cfg(target_endian = "little")] { + self.swap_bytes(); + } + } + + /// On a little endian machine, this does nothing. + /// On a big endian machine, the bytes of this value are reversed. + #[inline] fn convert_little_endian_to_current(&mut self) { + #[cfg(target_endian = "big")] { + self.swap_bytes(); + } + } + + /// On a big endian machine, this does nothing. + /// On a little endian machine, the bytes of this value are reversed. + #[inline] fn convert_big_endian_to_current(&mut self) { + #[cfg(target_endian = "little")] { + self.swap_bytes(); + } + } + + /// On a little endian machine, this does nothing. + /// On a big endian machine, the bytes of this value are reversed. + #[inline] fn from_current_into_little_endian(mut self) -> Self where Self: Sized { + self.convert_current_to_little_endian(); + self + } + + /// On a big endian machine, this does nothing. + /// On a little endian machine, the bytes of this value are reversed. + #[inline] fn from_current_into_big_endian(mut self) -> Self where Self: Sized { + self.convert_current_to_big_endian(); + self + } + + /// On a little endian machine, this does nothing. + /// On a big endian machine, the bytes of this value are reversed. + #[inline] fn from_little_endian_into_current(mut self) -> Self where Self: Sized { + self.convert_little_endian_to_current(); + self + } + + /// On a big endian machine, this does nothing. + /// On a little endian machine, the bytes of this value are reversed. + #[inline] fn from_big_endian_into_current(mut self) -> Self where Self: Sized { + self.convert_big_endian_to_current(); + self + } +} + + +// call a macro for each argument +macro_rules! call_single_arg_macro_for_each { + ($macro: ident, $( $arguments: ident ),* ) => { + $( $macro! { $arguments } )* + }; +} + +// implement this interface for primitive signed and unsigned integers +macro_rules! implement_simple_primitive_endian { + ($type: ident) => { + impl Endian for $type { + fn swap_bytes(&mut self) { + *self = $type::swap_bytes(*self); + } + } + }; +} + + +call_single_arg_macro_for_each! { + implement_simple_primitive_endian, + u16, u32, u64, u128, i16, i32, i64, i128 +} + +// no-op implementations +impl Endian for u8 { fn swap_bytes(&mut self) {} } +impl Endian for i8 { fn swap_bytes(&mut self) {} } +impl Endian for [u8] { fn swap_bytes(&mut self) {} } +impl Endian for [i8] { fn swap_bytes(&mut self) {} } + +// implement this interface for primitive floats, because they do not have a `swap_bytes()` in `std` +macro_rules! implement_float_primitive_by_bits { + ($type: ident) => { + impl Endian for $type { + fn swap_bytes(&mut self) { + *self = Self::from_bits(self.to_bits().swap_bytes()); + } + } + }; +} + + +implement_float_primitive_by_bits!(f32); +implement_float_primitive_by_bits!(f64); + +macro_rules! implement_slice_by_element { + ($type: ident) => { + impl Endian for [$type] { + fn swap_bytes(&mut self) { + for number in self.iter_mut() { // TODO SIMD? + number.swap_bytes(); + } + } + } + }; +} + +call_single_arg_macro_for_each! { + implement_slice_by_element, + u16, u32, u64, u128, + i16, i32, i64, i128, + f64, f32 +} + +/// Easily write primitives and slices of primitives to +/// binary `std::io::Write` streams and easily read from binary `std::io::Read` streams. +/// +/// Also contains the unsafe `bytes` module for reinterpreting values as byte slices and vice versa. +pub mod io { + use super::Endian; + use std::io::{Read, Write, Result}; + + /// Reinterpret values as byte slices and byte slices as values unsafely. + pub mod bytes { + use std::io::{Read, Write, Result}; + + /// View this slice of values as a slice of bytes. + #[inline] + pub unsafe fn slice_as_bytes<T>(value: &[T]) -> &[u8] { + std::slice::from_raw_parts( + value.as_ptr() as *const u8, + value.len() * std::mem::size_of::<T>() + ) + } + + /// View this slice of values as a mutable slice of bytes. + #[inline] + pub unsafe fn slice_as_bytes_mut<T>(value: &mut [T]) -> &mut [u8] { + std::slice::from_raw_parts_mut( + value.as_mut_ptr() as *mut u8, + value.len() * std::mem::size_of::<T>() + ) + } + + /// View this reference as a slice of bytes. + #[inline] + pub unsafe fn value_as_bytes<T: Sized>(value: &T) -> &[u8] { + std::slice::from_raw_parts( + value as *const T as *const u8, + std::mem::size_of::<T>() + ) + } + + /// View this reference as a mutable slice of bytes. + #[inline] + pub unsafe fn value_as_bytes_mut<T: Sized>(value: &mut T) ->&mut [u8] { + std::slice::from_raw_parts_mut( + value as *mut T as *mut u8, + std::mem::size_of::<T>() + ) + } + + /// View this slice as a mutable slice of bytes and write it. + #[inline] + pub unsafe fn write_slice<T>(write: &mut impl Write, value: &[T]) -> Result<()> { + write.write_all(slice_as_bytes(value)) + } + + /// Read a slice of bytes into the specified slice. + #[inline] + pub unsafe fn read_slice<T>(read: &mut impl Read, value: &mut [T]) -> Result<()> { + read.read_exact(slice_as_bytes_mut(value)) + } + + /// View this reference as a mutable slice of bytes and write it. + #[inline] + pub unsafe fn write_value<T: Sized>(write: &mut impl Write, value: &T) -> Result<()> { + write.write_all(value_as_bytes(value)) + } + + /// Read a slice of bytes into the specified reference. + #[inline] + pub unsafe fn read_value<T: Sized>(read: &mut impl Read, value: &mut T) -> Result<()> { + read.read_exact(value_as_bytes_mut(value)) + } + } + + /// A `std::io::Write` output stream which supports writing any primitive values as bytes. + /// Will encode the values to be either little endian or big endian, as desired. + /// + /// This extension trait is implemented for all `Write` types. + /// Add `use lebe::io::WriteEndian;` to your code + /// to automatically unlock this functionality for all types that implement `Write`. + pub trait WriteEndian<T: ?Sized> { + + /// Write the byte value of the specified reference, converting it to little endianness + fn write_as_little_endian(&mut self, value: &T) -> Result<()>; + + /// Write the byte value of the specified reference, converting it to big endianness + fn write_as_big_endian(&mut self, value: &T) -> Result<()>; + + /// Write the byte value of the specified reference, not converting it + fn write_as_native_endian(&mut self, value: &T) -> Result<()> { + #[cfg(target_endian = "little")] { self.write_as_little_endian(value) } + #[cfg(target_endian = "big")] { self.write_as_big_endian(value) } + } + } + + /// A `std::io::Read` input stream which supports reading any primitive values from bytes. + /// Will decode the values from either little endian or big endian, as desired. + /// + /// This extension trait is implemented for all `Read` types. + /// Add `use lebe::io::ReadEndian;` to your code + /// to automatically unlock this functionality for all types that implement `Read`. + pub trait ReadEndian<T: ?Sized> { + + /// Read into the supplied reference. Acts the same as `std::io::Read::read_exact`. + fn read_from_little_endian_into(&mut self, value: &mut T) -> Result<()>; + + /// Read into the supplied reference. Acts the same as `std::io::Read::read_exact`. + fn read_from_big_endian_into(&mut self, value: &mut T) -> Result<()>; + + /// Read into the supplied reference. Acts the same as `std::io::Read::read_exact`. + fn read_from_native_endian_into(&mut self, value: &mut T) -> Result<()> { + #[cfg(target_endian = "little")] { self.read_from_little_endian_into(value) } + #[cfg(target_endian = "big")] { self.read_from_big_endian_into(value) } + } + + /// Read the byte value of the inferred type + #[inline] + fn read_from_little_endian(&mut self) -> Result<T> where T: Sized + Default { + let mut value = T::default(); + self.read_from_little_endian_into(&mut value)?; + Ok(value) + } + + /// Read the byte value of the inferred type + #[inline] + fn read_from_big_endian(&mut self) -> Result<T> where T: Sized + Default { + let mut value = T::default(); + self.read_from_big_endian_into(&mut value)?; + Ok(value) + } + + /// Read the byte value of the inferred type + #[inline] + fn read_from_native_endian(&mut self) -> Result<T> where T: Sized + Default { + #[cfg(target_endian = "little")] { self.read_from_little_endian() } + #[cfg(target_endian = "big")] { self.read_from_big_endian() } + } + } + + // implement primitive for all types that are implemented by `Read` + impl<R: Read + ReadEndian<P>, P: Default> ReadPrimitive<R> for P {} + + + /// Offers a prettier versions of reading a primitive number. + /// + /// The default way of reading a value is: + /// ```rust + /// # use std::io::Read; + /// # use lebe::prelude::*; + /// # let mut reader : &[u8] = &[2, 1]; + /// + /// let number: u16 = reader.read_from_little_endian()?; + /// println!("{}", number); + /// # Ok::<(), std::io::Error>(()) + /// + /// ``` + /// + /// This trait enables you to use expressions: + /// ```rust + /// # use std::io::Read; + /// # use lebe::prelude::*; + /// # let mut reader : &[u8] = &[2, 1]; + /// + /// println!("{}", u16::read_from_little_endian(&mut reader)?); + /// # Ok::<(), std::io::Error>(()) + /// ``` + /// . + /// + pub trait ReadPrimitive<R: Read + ReadEndian<Self>> : Sized + Default { + /// Read this value from the supplied reader. Same as `ReadEndian::read_from_little_endian()`. + fn read_from_little_endian(read: &mut R) -> Result<Self> { + read.read_from_little_endian() + } + + /// Read this value from the supplied reader. Same as `ReadEndian::read_from_big_endian()`. + fn read_from_big_endian(read: &mut R) -> Result<Self> { + read.read_from_big_endian() + } + + /// Read this value from the supplied reader. Same as `ReadEndian::read_from_native_endian()`. + fn read_from_native_endian(read: &mut R) -> Result<Self> { + read.read_from_native_endian() + } + } + + macro_rules! implement_simple_primitive_write { + ($type: ident) => { + impl<W: Write> WriteEndian<$type> for W { + fn write_as_little_endian(&mut self, value: &$type) -> Result<()> { + unsafe { bytes::write_value(self, &value.from_current_into_little_endian()) } + } + + fn write_as_big_endian(&mut self, value: &$type) -> Result<()> { + unsafe { bytes::write_value(self, &value.from_current_into_big_endian()) } + } + } + + impl<R: Read> ReadEndian<$type> for R { + #[inline] + fn read_from_little_endian_into(&mut self, value: &mut $type) -> Result<()> { + unsafe { bytes::read_value(self, value)?; } + value.convert_little_endian_to_current(); + Ok(()) + } + + #[inline] + fn read_from_big_endian_into(&mut self, value: &mut $type) -> Result<()> { + unsafe { bytes::read_value(self, value)?; } + value.convert_big_endian_to_current(); + Ok(()) + } + } + }; + } + + call_single_arg_macro_for_each! { + implement_simple_primitive_write, + u8, u16, u32, u64, u128, + i8, i16, i32, i64, i128, + f32, f64 + } + + + macro_rules! implement_slice_io { + ($type: ident) => { + impl<W: Write> WriteEndian<[$type]> for W { + fn write_as_little_endian(&mut self, value: &[$type]) -> Result<()> { + #[cfg(target_endian = "big")] { + for number in value { // TODO SIMD! + self.write_as_little_endian(number)?; + } + } + + // else write whole slice + #[cfg(target_endian = "little")] + unsafe { bytes::write_slice(self, value)?; } + + Ok(()) + } + + fn write_as_big_endian(&mut self, value: &[$type]) -> Result<()> { + #[cfg(target_endian = "little")] { + for number in value { // TODO SIMD! + self.write_as_big_endian(number)?; + } + } + + // else write whole slice + #[cfg(target_endian = "big")] + unsafe { bytes::write_slice(self, value)?; } + + Ok(()) + } + } + + impl<R: Read> ReadEndian<[$type]> for R { + fn read_from_little_endian_into(&mut self, value: &mut [$type]) -> Result<()> { + unsafe { bytes::read_slice(self, value)? }; + value.convert_little_endian_to_current(); + Ok(()) + } + + fn read_from_big_endian_into(&mut self, value: &mut [$type]) -> Result<()> { + unsafe { bytes::read_slice(self, value)? }; + value.convert_big_endian_to_current(); + Ok(()) + } + } + }; + } + + call_single_arg_macro_for_each! { + implement_slice_io, + u8, u16, u32, u64, u128, + i8, i16, i32, i64, i128, + f64, f32 + } + + + + // TODO: SIMD + /*impl<R: Read> ReadEndian<[f32]> for R { + fn read_from_little_endian_into(&mut self, value: &mut [f32]) -> Result<()> { + unsafe { bytes::read_slice(self, value)? }; + value.convert_little_endian_to_current(); + Ok(()) + } + + fn read_from_big_endian_into(&mut self, value: &mut [f32]) -> Result<()> { + unsafe { bytes::read_slice(self, value)? }; + value.convert_big_endian_to_current(); + Ok(()) + } + } + + impl<W: Write> WriteEndian<[f32]> for W { + fn write_as_big_endian(&mut self, value: &[f32]) -> Result<()> { + if cfg!(target_endian = "little") { + + // FIX ME this SIMD optimization makes no difference ... why? like, ZERO difference, not even worse +// #[cfg(feature = "simd")] + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + unsafe { + if is_x86_feature_detected!("avx2") { + write_bytes_avx(self, value); + return Ok(()); + } + } + + // otherwise (no avx2 available) +// for number in value { +// self.write_as_little_endian(number); +// } +// +// return Ok(()); + unimplemented!(); + + #[target_feature(enable = "avx2")] + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + unsafe fn write_bytes_avx(write: &mut impl Write, slice: &[f32]) -> Result<()> { + #[cfg(target_arch = "x86")] use std::arch::x86 as mm; + #[cfg(target_arch = "x86_64")] use std::arch::x86_64 as mm; + + let bytes: &[u8] = crate::io::bytes::slice_as_bytes(slice); + let mut chunks = bytes.chunks_exact(32); + + let indices = mm::_mm256_set_epi8( + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 +// 3,2,1,0, 7,6,5,4, 11,10,9,8, 15,14,13,12, +// 3,2,1,0, 7,6,5,4, 11,10,9,8, 15,14,13,12 + ); + + for chunk in &mut chunks { + let data = mm::_mm256_loadu_si256(chunk.as_ptr() as _); + let result = mm::_mm256_shuffle_epi8(data, indices); + let mut out = [0_u8; 32]; + mm::_mm256_storeu_si256(out.as_mut_ptr() as _, result); + write.write_all(&out)?; + } + + let remainder = chunks.remainder(); + + { // copy remainder into larger slice, with zeroes at the end + let mut last_chunk = [0_u8; 32]; + last_chunk[0..remainder.len()].copy_from_slice(remainder); + let data = mm::_mm256_loadu_si256(last_chunk.as_ptr() as _); + let result = mm::_mm256_shuffle_epi8(data, indices); + mm::_mm256_storeu_si256(last_chunk.as_mut_ptr() as _, result); + write.write_all(&last_chunk[0..remainder.len()])?; + } + + Ok(()) + } + } + + else { + unsafe { bytes::write_slice(self, value)?; } + Ok(()) + } + } + + fn write_as_little_endian(&mut self, value: &[f32]) -> Result<()> { + for number in value { + self.write_as_little_endian(number)?; + } + + Ok(()) + } + }*/ +} + diff --git a/vendor/lebe/tests/tests.rs b/vendor/lebe/tests/tests.rs new file mode 100644 index 0000000..fb88bdd --- /dev/null +++ b/vendor/lebe/tests/tests.rs @@ -0,0 +1,213 @@ +extern crate lebe; + +use lebe::prelude::*; +use std::mem; + +use byteorder::{WriteBytesExt, LittleEndian, BigEndian, ReadBytesExt}; + +#[test] +fn make_le_u32_slice() { + // as seen on https://doc.rust-lang.org/std/primitive.u32.html#method.to_le + let n = 0x1Au32; + + let mut n_le = [n]; + n_le.convert_current_to_little_endian(); + + if cfg!(target_endian = "little") { + assert_eq!(n_le, [n]) + } + else { + assert_eq!(n_le, [u32::swap_bytes(n)]) + } + +// assert_eq!(n_le, byteorder::LittleEndian::from_) +} + +#[test] +fn make_be_u32_slice() { + // as seen on https://doc.rust-lang.org/std/primitive.u32.html#method.to_be + let n = 0x1Au32; + + let mut n_be = [n]; + n_be.convert_current_to_big_endian(); + + if cfg!(target_endian = "big") { + assert_eq!(n_be, [n]) + } + else { + assert_eq!(n_be, [n.swap_bytes()]) + } +} + +#[test] +fn make_le_u16_slice() { + // as seen on https://doc.rust-lang.org/std/primitive.u16.html#method.to_le + let n = 0x1Au16; + + let mut n_le = [n]; + n_le.convert_current_to_little_endian(); + + if cfg!(target_endian = "little") { + assert_eq!(n_le, [n]) + } + else { + assert_eq!(n_le, [n.swap_bytes()]) + } +} + +#[test] +fn make_le_i64_slice() { + // as seen on https://doc.rust-lang.org/std/primitive.u64.html#method.to_be + let n1 = 0x14F3EEBCCD93895A_i64; + let n2 = 0x114F3EF99B81CC5A_i64; + + let mut n_be = [n1, n2]; + n_be.convert_current_to_big_endian(); + + if cfg!(target_endian = "big") { + assert_eq!(n_be, [n1, n2]) + } + else { + assert_eq!(n_be, [n1.swap_bytes(), n2.swap_bytes()]) + } +} + +#[test] +fn make_be_f64() { + let i = 0x14F3EEBCCD93895A_u64; + + let mut f: f64 = unsafe { mem::transmute(i) }; + f.convert_current_to_big_endian(); + + assert_eq!(f, unsafe { mem::transmute(i.to_be()) }) +} + +#[test] +fn into_be_f64() { + let i = 0x14F3EEBCCD93895A_u64; + + let f: f64 = unsafe { mem::transmute(i) }; + let f = f.from_current_into_big_endian(); + + assert_eq!(f, unsafe { mem::transmute(i.to_be()) }) +} + +#[test] +fn into_be_i16() { + let i = 0x195A_i16; + let be = i.from_current_into_big_endian(); + + if cfg!(target_endian = "big") { + assert_eq!(be, i) + } + else { + assert_eq!(be, i.swap_bytes()) + } +} + +#[test] +fn into_be_u32() { + let i = 0x1220943_u32; + let be = i.from_current_into_big_endian(); + + if cfg!(target_endian = "big") { + assert_eq!(be, i) + } + else { + assert_eq!(be, i.swap_bytes()) + } +} + +#[test] +fn cmp_read_be_u16() { + let read: &[u8] = &[0x33, 0xbb]; + let a = u16::read_from_big_endian(&mut read.clone()).unwrap(); + let b: u16 = read.clone().read_from_big_endian().unwrap(); + let c = read.clone().read_u16::<BigEndian>().unwrap(); + + assert_eq!(a, b); + assert_eq!(a, c); +} + +#[test] +fn cmp_read_le_u16() { + let read: &[u8] = &[0x33, 0xbb]; + let a = u16::read_from_little_endian(&mut read.clone()).unwrap(); + let b: u16 = read.clone().read_from_little_endian().unwrap(); + let c = read.clone().read_u16::<LittleEndian>().unwrap(); + + assert_eq!(a, b); + assert_eq!(a, c); +} + +#[test] +fn cmp_read_le_f32() { + let read: &[u8] = &[0x33, 0xBB, 0x44, 0xCC]; + let a = f32::read_from_little_endian(&mut read.clone()).unwrap(); + let b: f32 = read.clone().read_from_little_endian().unwrap(); + let c = read.clone().read_f32::<LittleEndian>().unwrap(); + + assert_eq!(a, b); + assert_eq!(a, c); +} + +#[test] +fn cmp_read_be_slice() { + let mut write_expected = Vec::new(); + let mut write_actual = Vec::new(); + + let data: Vec<f32> = (0..31*31).map(|i| i as f32).collect(); + + for number in &data { + write_expected.write_f32::<BigEndian>(*number).unwrap(); + } + + write_actual.write_as_big_endian(data.as_slice()).unwrap(); + assert_eq!(write_actual, write_expected); +} + +#[test] +fn cmp_write_le_slice() { + let mut write_expected = Vec::new(); + let mut write_actual = Vec::new(); + + let data: Vec<f32> = (0..31*31).map(|i| i as f32).collect(); + + for number in &data { + write_expected.write_f32::<LittleEndian>(*number).unwrap(); + } + + write_actual.write_as_little_endian(data.as_slice()).unwrap(); + + assert_eq!(write_actual, write_expected); +} + +#[test] +fn cmp_write_le_u32() { + let mut write_expected = Vec::new(); + let mut write_actual = Vec::new(); + + let data = 0x23573688_u32; + write_expected.write_u32::<LittleEndian>(data).unwrap(); + write_actual.write_as_little_endian(&data).unwrap(); + + assert_eq!(write_actual, write_expected); +} + + + +#[test] +fn cmp_write_le_slice_u64() { + let mut write_expected = Vec::new(); + let mut write_actual = Vec::new(); + + let data: Vec<u64> = (1000..1000+310*31).map(|i| i as u64).collect(); + + for number in &data { + write_expected.write_u64::<LittleEndian>(*number).unwrap(); + } + + write_actual.write_as_little_endian(data.as_slice()).unwrap(); + + assert_eq!(write_actual, write_expected); +}
\ No newline at end of file |