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}