lebe/
lib.rs

1#![warn(
2    missing_docs, unused,
3    trivial_numeric_casts,
4    future_incompatible,
5    rust_2018_compatibility,
6    rust_2018_idioms,
7    clippy::all
8)]
9
10#![doc(html_root_url = "https://docs.rs/lebe/0.5.0")]
11
12//! Dead simple endianness conversions.
13//! The following operations are implemented on
14//! `u8`, `i8`, `u16`, `i16`, `u32`, `i32`, `u64`, `i64`, `u128`, `i128`, `f32`, `f64`:
15//!
16//!
17//! ### Read Numbers
18//! ```rust
19//! use lebe::prelude::*;
20//! let mut reader: &[u8] = &[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
21//!
22//! let number : u64 = reader.read_from_little_endian()?;
23//! let number = u64::read_from_big_endian(&mut reader)?;
24//! # Ok::<(), std::io::Error>(())
25//! ```
26//!
27//! ### Read Slices
28//! ```rust
29//! use std::io::Read;
30//! use lebe::prelude::*;
31//! let mut reader: &[u8] = &[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
32//!
33//! let mut numbers: &mut [u64] = &mut [0, 0];
34//! reader.read_from_little_endian_into(numbers)?;
35//! # Ok::<(), std::io::Error>(())
36//! ```
37//!
38//! ### Write Numbers
39//! ```rust
40//! use std::io::Read;
41//! use lebe::prelude::*;
42//! let mut writer: Vec<u8> = Vec::new();
43//!
44//! let number: u64 = 1237691;
45//! writer.write_as_big_endian(&number)?;
46//! # Ok::<(), std::io::Error>(())
47//! ```
48//!
49//! ### Write Slices
50//! ```rust
51//! use std::io::Write;
52//! use lebe::prelude::*;
53//! let mut writer: Vec<u8> = Vec::new();
54//!
55//! let numbers: &[u64] = &[1_u64, 234545_u64];
56//! writer.write_as_little_endian(numbers)?;
57//! # Ok::<(), std::io::Error>(())
58//! ```
59//!
60
61
62/// Exports some of the most common types.
63pub mod prelude {
64    pub use super::Endian;
65    pub use super::io::{ WriteEndian, ReadEndian, ReadPrimitive };
66}
67
68/// Represents values that can swap their bytes to reverse their endianness.
69///
70/// Supports converting values in-place using [`swap_bytes`] or [`convert_current_to_little_endian`]:
71/// Supports converting while transferring ownership using
72/// [`from_little_endian_into_current`] or [`from_current_into_little_endian`].
73///
74///
75/// For the types `u8`, `i8`, `&[u8]` and `&[i8]`, this trait will never transform any data,
76/// as they are just implemented for completeness.
77pub trait Endian {
78
79    /// Swaps all bytes in this value, inverting its endianness.
80    fn swap_bytes(&mut self);
81
82    /// On a little endian machine, this does nothing.
83    /// On a big endian machine, the bytes of this value are reversed.
84    #[inline] fn convert_current_to_little_endian(&mut self) {
85        #[cfg(target_endian = "big")] {
86            self.swap_bytes();
87        }
88    }
89
90    /// On a big endian machine, this does nothing.
91    /// On a little endian machine, the bytes of this value are reversed.
92    #[inline] fn convert_current_to_big_endian(&mut self) {
93        #[cfg(target_endian = "little")] {
94            self.swap_bytes();
95        }
96    }
97
98    /// On a little endian machine, this does nothing.
99    /// On a big endian machine, the bytes of this value are reversed.
100    #[inline] fn convert_little_endian_to_current(&mut self) {
101        #[cfg(target_endian = "big")] {
102            self.swap_bytes();
103        }
104    }
105
106    /// On a big endian machine, this does nothing.
107    /// On a little endian machine, the bytes of this value are reversed.
108    #[inline] fn convert_big_endian_to_current(&mut self) {
109        #[cfg(target_endian = "little")] {
110            self.swap_bytes();
111        }
112    }
113
114    /// On a little endian machine, this does nothing.
115    /// On a big endian machine, the bytes of this value are reversed.
116    #[inline] fn from_current_into_little_endian(mut self) -> Self where Self: Sized {
117        self.convert_current_to_little_endian();
118        self
119    }
120
121    /// On a big endian machine, this does nothing.
122    /// On a little endian machine, the bytes of this value are reversed.
123    #[inline] fn from_current_into_big_endian(mut self) -> Self where Self: Sized {
124        self.convert_current_to_big_endian();
125        self
126    }
127
128    /// On a little endian machine, this does nothing.
129    /// On a big endian machine, the bytes of this value are reversed.
130    #[inline] fn from_little_endian_into_current(mut self) -> Self where Self: Sized {
131        self.convert_little_endian_to_current();
132        self
133    }
134
135    /// On a big endian machine, this does nothing.
136    /// On a little endian machine, the bytes of this value are reversed.
137    #[inline] fn from_big_endian_into_current(mut self) -> Self where Self: Sized {
138        self.convert_big_endian_to_current();
139        self
140    }
141}
142
143
144// call a macro for each argument
145macro_rules! call_single_arg_macro_for_each {
146    ($macro: ident, $( $arguments: ident ),* ) => {
147        $( $macro! { $arguments }  )*
148    };
149}
150
151// implement this interface for primitive signed and unsigned integers
152macro_rules! implement_simple_primitive_endian {
153    ($type: ident) => {
154        impl Endian for $type {
155            fn swap_bytes(&mut self) {
156                *self = $type::swap_bytes(*self);
157            }
158        }
159    };
160}
161
162
163call_single_arg_macro_for_each! {
164    implement_simple_primitive_endian,
165    u16, u32, u64, u128, i16, i32, i64, i128
166}
167
168// no-op implementations
169impl Endian for u8 { fn swap_bytes(&mut self) {} }
170impl Endian for i8 { fn swap_bytes(&mut self) {} }
171impl Endian for [u8] { fn swap_bytes(&mut self) {} }
172impl Endian for [i8] { fn swap_bytes(&mut self) {} }
173
174// implement this interface for primitive floats, because they do not have a `swap_bytes()` in `std`
175macro_rules! implement_float_primitive_by_bits {
176    ($type: ident) => {
177        impl Endian for $type {
178            fn swap_bytes(&mut self) {
179                *self = Self::from_bits(self.to_bits().swap_bytes());
180            }
181        }
182    };
183}
184
185
186implement_float_primitive_by_bits!(f32);
187implement_float_primitive_by_bits!(f64);
188
189macro_rules! implement_slice_by_element {
190    ($type: ident) => {
191        impl Endian for [$type] {
192            fn swap_bytes(&mut self) {
193                for number in self.iter_mut() { // TODO SIMD?
194                    number.swap_bytes();
195                }
196            }
197        }
198    };
199}
200
201call_single_arg_macro_for_each! {
202    implement_slice_by_element,
203    u16, u32, u64, u128,
204    i16, i32, i64, i128,
205    f64, f32
206}
207
208/// Easily write primitives and slices of primitives to
209/// binary `std::io::Write` streams and easily read from binary `std::io::Read` streams.
210///
211/// Also contains the unsafe `bytes` module for reinterpreting values as byte slices and vice versa.
212pub mod io {
213    use super::Endian;
214    use std::io::{Read, Write, Result};
215
216    /// Reinterpret values as byte slices and byte slices as values unsafely.
217    pub mod bytes {
218        use std::io::{Read, Write, Result};
219
220        /// View this slice of values as a slice of bytes.
221        #[inline]
222        pub unsafe fn slice_as_bytes<T>(value: &[T]) -> &[u8] {
223            std::slice::from_raw_parts(
224                value.as_ptr() as *const u8,
225                value.len() * std::mem::size_of::<T>()
226            )
227        }
228
229        /// View this slice of values as a mutable slice of bytes.
230        #[inline]
231        pub unsafe fn slice_as_bytes_mut<T>(value: &mut [T]) -> &mut [u8] {
232            std::slice::from_raw_parts_mut(
233                value.as_mut_ptr() as *mut u8,
234                value.len() * std::mem::size_of::<T>()
235            )
236        }
237
238        /// View this reference as a slice of bytes.
239        #[inline]
240        pub unsafe fn value_as_bytes<T: Sized>(value: &T) -> &[u8] {
241            std::slice::from_raw_parts(
242                value as *const T as *const u8,
243                std::mem::size_of::<T>()
244            )
245        }
246
247        /// View this reference as a mutable slice of bytes.
248        #[inline]
249        pub unsafe fn value_as_bytes_mut<T: Sized>(value: &mut T) ->&mut [u8] {
250            std::slice::from_raw_parts_mut(
251                value as *mut T as *mut u8,
252                std::mem::size_of::<T>()
253            )
254        }
255
256        /// View this slice as a mutable slice of bytes and write it.
257        #[inline]
258        pub unsafe fn write_slice<T>(write: &mut impl Write, value: &[T]) -> Result<()> {
259            write.write_all(slice_as_bytes(value))
260        }
261
262        /// Read a slice of bytes into the specified slice.
263        #[inline]
264        pub unsafe fn read_slice<T>(read: &mut impl Read, value: &mut [T]) -> Result<()> {
265            read.read_exact(slice_as_bytes_mut(value))
266        }
267
268        /// View this reference as a mutable slice of bytes and write it.
269        #[inline]
270        pub unsafe fn write_value<T: Sized>(write: &mut impl Write, value: &T) -> Result<()> {
271            write.write_all(value_as_bytes(value))
272        }
273
274        /// Read a slice of bytes into the specified reference.
275        #[inline]
276        pub unsafe fn read_value<T: Sized>(read: &mut impl Read, value: &mut T) -> Result<()> {
277            read.read_exact(value_as_bytes_mut(value))
278        }
279    }
280
281    /// A `std::io::Write` output stream which supports writing any primitive values as bytes.
282    /// Will encode the values to be either little endian or big endian, as desired.
283    ///
284    /// This extension trait is implemented for all `Write` types.
285    /// Add `use lebe::io::WriteEndian;` to your code
286    /// to automatically unlock this functionality for all types that implement `Write`.
287    pub trait WriteEndian<T: ?Sized> {
288
289        /// Write the byte value of the specified reference, converting it to little endianness
290        fn write_as_little_endian(&mut self, value: &T) -> Result<()>;
291
292        /// Write the byte value of the specified reference, converting it to big endianness
293        fn write_as_big_endian(&mut self, value: &T) -> Result<()>;
294
295        /// Write the byte value of the specified reference, not converting it
296        fn write_as_native_endian(&mut self, value: &T) -> Result<()> {
297            #[cfg(target_endian = "little")] { self.write_as_little_endian(value) }
298            #[cfg(target_endian = "big")] { self.write_as_big_endian(value) }
299        }
300    }
301
302    /// A `std::io::Read` input stream which supports reading any primitive values from bytes.
303    /// Will decode the values from either little endian or big endian, as desired.
304    ///
305    /// This extension trait is implemented for all `Read` types.
306    /// Add `use lebe::io::ReadEndian;` to your code
307    /// to automatically unlock this functionality for all types that implement `Read`.
308    pub trait ReadEndian<T: ?Sized> {
309
310        /// Read into the supplied reference. Acts the same as `std::io::Read::read_exact`.
311        fn read_from_little_endian_into(&mut self, value: &mut T) -> Result<()>;
312
313        /// Read into the supplied reference. Acts the same as `std::io::Read::read_exact`.
314        fn read_from_big_endian_into(&mut self, value: &mut T) -> Result<()>;
315
316        /// Read into the supplied reference. Acts the same as `std::io::Read::read_exact`.
317        fn read_from_native_endian_into(&mut self, value: &mut T) -> Result<()> {
318            #[cfg(target_endian = "little")] { self.read_from_little_endian_into(value) }
319            #[cfg(target_endian = "big")] { self.read_from_big_endian_into(value) }
320        }
321
322        /// Read the byte value of the inferred type
323        #[inline]
324        fn read_from_little_endian(&mut self) -> Result<T> where T: Sized + Default {
325            let mut value = T::default();
326            self.read_from_little_endian_into(&mut value)?;
327            Ok(value)
328        }
329
330        /// Read the byte value of the inferred type
331        #[inline]
332        fn read_from_big_endian(&mut self) -> Result<T> where T: Sized + Default {
333            let mut value = T::default();
334            self.read_from_big_endian_into(&mut value)?;
335            Ok(value)
336        }
337
338        /// Read the byte value of the inferred type
339        #[inline]
340        fn read_from_native_endian(&mut self) -> Result<T> where T: Sized + Default {
341            #[cfg(target_endian = "little")] { self.read_from_little_endian() }
342            #[cfg(target_endian = "big")] { self.read_from_big_endian() }
343        }
344    }
345
346    // implement primitive for all types that are implemented by `Read`
347    impl<R: Read + ReadEndian<P>, P: Default> ReadPrimitive<R> for P {}
348
349
350    /// Offers a prettier versions of reading a primitive number.
351    ///
352    /// The default way of reading a value is:
353    /// ```rust
354    /// # use std::io::Read;
355    /// # use lebe::prelude::*;
356    /// # let mut reader : &[u8] = &[2, 1];
357    ///
358    /// let number: u16 = reader.read_from_little_endian()?;
359    /// println!("{}", number);
360    /// # Ok::<(), std::io::Error>(())
361    ///
362    /// ```
363    ///
364    /// This trait enables you to use expressions:
365    /// ```rust
366    /// # use std::io::Read;
367    /// # use lebe::prelude::*;
368    /// # let mut reader : &[u8] = &[2, 1];
369    ///
370    /// println!("{}", u16::read_from_little_endian(&mut reader)?);
371    /// # Ok::<(), std::io::Error>(())
372    /// ```
373    /// .
374    ///
375    pub trait ReadPrimitive<R: Read + ReadEndian<Self>> : Sized + Default {
376        /// Read this value from the supplied reader. Same as `ReadEndian::read_from_little_endian()`.
377        fn read_from_little_endian(read: &mut R) -> Result<Self> {
378            read.read_from_little_endian()
379        }
380
381        /// Read this value from the supplied reader. Same as `ReadEndian::read_from_big_endian()`.
382        fn read_from_big_endian(read: &mut R) -> Result<Self> {
383            read.read_from_big_endian()
384        }
385
386        /// Read this value from the supplied reader. Same as `ReadEndian::read_from_native_endian()`.
387        fn read_from_native_endian(read: &mut R) -> Result<Self> {
388            read.read_from_native_endian()
389        }
390    }
391
392    macro_rules! implement_simple_primitive_write {
393        ($type: ident) => {
394            impl<W: Write> WriteEndian<$type> for W {
395                fn write_as_little_endian(&mut self, value: &$type) -> Result<()> {
396                    unsafe { bytes::write_value(self, &value.from_current_into_little_endian()) }
397                }
398
399                fn write_as_big_endian(&mut self, value: &$type) -> Result<()> {
400                    unsafe { bytes::write_value(self, &value.from_current_into_big_endian()) }
401                }
402            }
403
404            impl<R: Read> ReadEndian<$type> for R {
405                #[inline]
406                fn read_from_little_endian_into(&mut self, value: &mut $type) -> Result<()> {
407                    unsafe { bytes::read_value(self, value)?; }
408                    value.convert_little_endian_to_current();
409                    Ok(())
410                }
411
412                #[inline]
413                fn read_from_big_endian_into(&mut self, value: &mut $type) -> Result<()> {
414                    unsafe { bytes::read_value(self, value)?; }
415                    value.convert_big_endian_to_current();
416                    Ok(())
417                }
418            }
419        };
420    }
421
422    call_single_arg_macro_for_each! {
423        implement_simple_primitive_write,
424        u8, u16, u32, u64, u128,
425        i8, i16, i32, i64, i128,
426        f32, f64
427    }
428
429
430    macro_rules! implement_slice_io {
431        ($type: ident) => {
432            impl<W: Write> WriteEndian<[$type]> for W {
433                fn write_as_little_endian(&mut self, value: &[$type]) -> Result<()> {
434                    #[cfg(target_endian = "big")] {
435                        for number in value { // TODO SIMD!
436                            self.write_as_little_endian(number)?;
437                        }
438                    }
439
440                    // else write whole slice
441                    #[cfg(target_endian = "little")]
442                    unsafe { bytes::write_slice(self, value)?; }
443
444                    Ok(())
445                }
446
447                fn write_as_big_endian(&mut self, value: &[$type]) -> Result<()> {
448                    #[cfg(target_endian = "little")] {
449                        for number in value { // TODO SIMD!
450                            self.write_as_big_endian(number)?;
451                        }
452                    }
453
454                    // else write whole slice
455                    #[cfg(target_endian = "big")]
456                    unsafe { bytes::write_slice(self, value)?; }
457
458                    Ok(())
459                }
460            }
461
462            impl<R: Read> ReadEndian<[$type]> for R {
463                fn read_from_little_endian_into(&mut self, value: &mut [$type]) -> Result<()> {
464                    unsafe { bytes::read_slice(self, value)? };
465                    value.convert_little_endian_to_current();
466                    Ok(())
467                }
468
469                fn read_from_big_endian_into(&mut self, value: &mut [$type]) -> Result<()> {
470                    unsafe { bytes::read_slice(self, value)? };
471                    value.convert_big_endian_to_current();
472                    Ok(())
473                }
474            }
475        };
476    }
477
478    call_single_arg_macro_for_each! {
479        implement_slice_io,
480        u8, u16, u32, u64, u128,
481        i8, i16, i32, i64, i128,
482        f64, f32
483    }
484
485
486
487    // TODO: SIMD
488    /*impl<R: Read> ReadEndian<[f32]> for R {
489        fn read_from_little_endian_into(&mut self, value: &mut [f32]) -> Result<()> {
490            unsafe { bytes::read_slice(self, value)? };
491            value.convert_little_endian_to_current();
492            Ok(())
493        }
494
495        fn read_from_big_endian_into(&mut self, value: &mut [f32]) -> Result<()> {
496            unsafe { bytes::read_slice(self, value)? };
497            value.convert_big_endian_to_current();
498            Ok(())
499        }
500    }
501
502    impl<W: Write> WriteEndian<[f32]> for W {
503        fn write_as_big_endian(&mut self, value: &[f32]) -> Result<()> {
504            if cfg!(target_endian = "little") {
505
506                // FIX ME this SIMD optimization makes no difference ... why? like, ZERO difference, not even worse
507//                #[cfg(feature = "simd")]
508                #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
509                unsafe {
510                    if is_x86_feature_detected!("avx2") {
511                        write_bytes_avx(self, value);
512                        return Ok(());
513                    }
514                }
515
516                // otherwise (no avx2 available)
517//                for number in value {
518//                    self.write_as_little_endian(number);
519//                }
520//
521//                return Ok(());
522                unimplemented!();
523
524                #[target_feature(enable = "avx2")]
525                #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
526                unsafe fn write_bytes_avx(write: &mut impl Write, slice: &[f32]) -> Result<()> {
527                    #[cfg(target_arch = "x86")] use std::arch::x86 as mm;
528                    #[cfg(target_arch = "x86_64")] use std::arch::x86_64 as mm;
529
530                    let bytes: &[u8] = crate::io::bytes::slice_as_bytes(slice);
531                    let mut chunks = bytes.chunks_exact(32);
532
533                    let indices = mm::_mm256_set_epi8(
534                        0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
535                        0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
536//                        3,2,1,0, 7,6,5,4, 11,10,9,8, 15,14,13,12,
537//                        3,2,1,0, 7,6,5,4, 11,10,9,8, 15,14,13,12
538                    );
539
540                    for chunk in &mut chunks {
541                        let data = mm::_mm256_loadu_si256(chunk.as_ptr() as _);
542                        let result = mm::_mm256_shuffle_epi8(data, indices);
543                        let mut out = [0_u8; 32];
544                        mm::_mm256_storeu_si256(out.as_mut_ptr() as _, result);
545                        write.write_all(&out)?;
546                    }
547
548                    let remainder = chunks.remainder();
549
550                    { // copy remainder into larger slice, with zeroes at the end
551                        let mut last_chunk = [0_u8; 32];
552                        last_chunk[0..remainder.len()].copy_from_slice(remainder);
553                        let data = mm::_mm256_loadu_si256(last_chunk.as_ptr() as _);
554                        let result = mm::_mm256_shuffle_epi8(data, indices);
555                        mm::_mm256_storeu_si256(last_chunk.as_mut_ptr() as _, result);
556                        write.write_all(&last_chunk[0..remainder.len()])?;
557                    }
558
559                    Ok(())
560                }
561            }
562
563            else {
564                unsafe { bytes::write_slice(self, value)?; }
565                Ok(())
566            }
567        }
568
569        fn write_as_little_endian(&mut self, value: &[f32]) -> Result<()> {
570            for number in value {
571                self.write_as_little_endian(number)?;
572            }
573
574            Ok(())
575        }
576    }*/
577}
578