simple_endian/lib.rs
1#![cfg_attr(not(feature = "std"), no_std)]
2#![cfg_attr(test, feature(test))]
3//! Many byte-order-handling libraries focus on providing code to convert to and from big- or little-endian. However,
4//! this requires users of those libraries to use a lot of explicit logic. This library uses the Rust type system to
5//! enforce conversions invisibly, and also ensure that they are done consistently. A struct member can be read and written
6//! simply using the standard From and Into trait methods (from() and into()). No explicit endian checks are required.
7//!
8//! # Example 1:
9//!
10//!```rust
11//! use simple_endian::*;
12//!
13//! fn init() {
14//! #[repr(C)]
15//! struct BinPacket {
16//! a: u64be,
17//! b: u32be,
18//! }
19//! let mut bp = BinPacket{a: 0xfe.into(), b: 10.into()};
20//! let new_a = bp.a.to_native() * 1234;
21
22//! bp.a = new_a.into();
23//! bp.b = 1234.into();
24//! }
25//! ```
26//!
27//! Trying to write `bp.a = new_a;` causes an error because the type u64 can't be directly stored.
28//!
29//! # Example 2: Writing a portable struct to a file.
30//!
31//! Of course, just storing things in memory isn't that useful unless you write somewhere.
32//!
33//! ```rust
34//! use simple_endian::*;
35//! use std::fs::File;
36//! use std::io::prelude::*;
37//! use std::mem::{transmute, size_of};
38//!
39//! // We have to specify a representation in order to define the layout.
40//! #[repr(C)]
41//! struct BinBEStruct {
42//! pub a: u64be,
43//! b: u64be,
44//! c: f64be,
45//! }
46//!
47//! fn main() -> std::io::Result<()> {
48//! let bin_struct = BinBEStruct{a: 345.into(), b: 0xfee.into(), c: 9.345.into()};
49//!
50//! let mut pos = 0;
51//! let mut data_file = File::create(".test.bin")?;
52//! let buffer = unsafe { transmute::<&BinBEStruct, &[u8; size_of::<BinBEStruct>()]>(&bin_struct) };
53//!
54//! while pos < buffer.len() {
55//! let bytes_written = data_file.write(&buffer[pos..])?;
56//! pos += bytes_written;
57//! }
58//! Ok(())
59//! }
60//! ```
61//! # Example 3: Mmapping a portable struct with the memmap crate.
62//!
63//! You'll need to add memmap to your Cargo.toml to get this to actually work:
64//!
65//! ```rust
66//! #![feature(rustc_private)]
67//! extern crate memmap;
68//!
69//! use std::{
70//! io::Error,
71//! fs::OpenOptions,
72//! mem::size_of,
73//! };
74//!
75//! use memmap::MmapOptions;
76//! use simple_endian::*;
77//!
78//! #[repr(C)]
79//! struct MyBEStruct {
80//! header: u64be,
81//! label: [u8; 8],
82//! count: u128be,
83//! }
84//!
85//! fn main() -> Result<(), Error> {
86//! let file = OpenOptions::new()
87//! .read(true).write(true).create(true)
88//! .open(".test.bin")?;
89//!
90//! // Truncate the file to the size of the header.
91//! file.set_len(size_of::<MyBEStruct>() as u64)?;
92//! let mut mmap = unsafe { MmapOptions::new().map_mut(&file)? };
93//!
94//! let mut ptr = mmap.as_mut_ptr() as *mut MyBEStruct;
95//!
96//! unsafe {
97//! // Set the magic number
98//! (*ptr).header = 0xfeedface.into();
99//!
100//! // Increment the counter each time we run.
101//! (*ptr).count += 1.into();
102//!
103//! (*ptr).label = *b"Iamhere!";
104//! }
105//!
106//! println!("done.");
107//! Ok(())
108//! }
109//! ```
110//!
111
112/// The main part of the library. Contains the trait SpecificEndian<T> and BigEndian<T> and LittleEndian<T> structs, as well as the
113/// implementation of those on the primitive types.
114mod specific_endian;
115pub use specific_endian::*;
116
117/// Bitwise operations. These should be equally fast in any endian.
118#[cfg(feature = "bitwise")] mod bitwise_ops;
119
120/// Ops for comparisons and ordering.
121#[cfg(feature = "comparisons")] mod comparison_ops;
122
123/// Shift operations.
124#[cfg(feature = "shift_ops")] mod shift_ops;
125
126/// General math operations.
127#[cfg(feature = "math_ops")] mod math_ops;
128
129/// Negations.
130#[cfg(feature = "neg_ops")] mod neg_ops;
131
132/// Formatter impls.
133#[cfg(feature = "format")] mod formatting_ops;
134
135/// The shorthand types (e.g u64be, f32le, etc)
136mod shorthand_types;
137pub use shorthand_types::*;
138
139#[cfg(test)]
140mod tests {
141 extern crate test;
142 use crate::*;
143 use test::Bencher;
144
145 #[bench]
146 fn bench_integer_be(b: &mut Bencher) {
147 b.iter(|| {
148 let mut a = BigEndian::from(1234567890);
149 for _ in 0..10 {
150 a += BigEndian::from(101010);
151 a &= BigEndian::from(0xf0f0f0);
152 a *= BigEndian::from(123);
153 a /= BigEndian::from(543);
154 }
155 println!("{}", a);
156 });
157 }
158 #[bench]
159 fn bench_integer_le(b: &mut Bencher) {
160 b.iter(|| {
161 let mut a = LittleEndian::from(1234567890);
162 for _ in 0..10 {
163 a += LittleEndian::from(101010);
164 a &= LittleEndian::from(0xf0f0f0);
165 a *= LittleEndian::from(123);
166 a /= LittleEndian::from(543);
167 }
168 println!("{}", a);
169 });
170 }
171 #[bench]
172 fn bench_integer_ne(b: &mut Bencher) {
173 b.iter(|| {
174 let mut a = 1234567890;
175 for _ in 0..10 {
176 a += 101010;
177 a &= 0xf0f0f0;
178 a *= 123;
179 a /= 543;
180 }
181 println!("{}", a);
182 });
183 }
184
185 #[bench]
186 fn bench_fp_be(b: &mut Bencher) {
187 b.iter(|| {
188 let mut a = BigEndian::from(1234567890.1);
189 for _ in 0..10 {
190 a += BigEndian::from(101010.0);
191 a *= BigEndian::from(123.0);
192 a /= BigEndian::from(543.0);
193 }
194 println!("{}", a);
195 });
196 }
197 #[bench]
198 fn bench_fp_le(b: &mut Bencher) {
199 b.iter(|| {
200 let mut a = LittleEndian::from(1234567890.1);
201 for _ in 0..10 {
202 a += LittleEndian::from(101010.0);
203 a *= LittleEndian::from(123.0);
204 a /= LittleEndian::from(543.0);
205 }
206 println!("{}", a);
207 });
208 }
209 #[bench]
210 fn bench_fp_ne(b: &mut Bencher) {
211 b.iter(|| {
212 let mut a = 1234567890.1;
213 for _ in 0..10 {
214 a += 101010.0;
215 a *= 123.0;
216 a /= 543.0;
217 }
218 println!("{}", a);
219 });
220 }
221
222 #[bench]
223 fn base_endian_test_be(b: &mut Bencher) {
224 b.iter(|| {
225 for _ in 0..1000 {
226 let a = i32::from_be(0xa5a5a5);
227 println!("{}", a);
228 }
229 });
230 }
231 #[bench]
232 fn base_endian_test_le(b: &mut Bencher) {
233 b.iter(|| {
234 for _ in 0..1000 {
235 let a = i32::from_le(0xa5a5a5);
236 println!("{}", a);
237 }
238 });
239 }
240 #[bench]
241 fn base_endian_test_ne(b: &mut Bencher) {
242 b.iter(|| {
243 for _ in 0..1000 {
244 let a = 0xa5a5a5_i32;
245 println!("{}", a);
246 }
247 });
248 }
249 #[bench]
250 fn base_endian_test_structured(b: &mut Bencher) {
251 b.iter(|| {
252 for _ in 0..1000 {
253 let a = LittleEndian{_v: 0xa5a5a5_i32};
254 println!("{}", a);
255 }
256 });
257 }
258
259}