#![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")]
pub mod prelude {
pub use super::Endian;
pub use super::io::{ WriteEndian, ReadEndian, ReadPrimitive };
}
pub trait Endian {
fn swap_bytes(&mut self);
#[inline] fn convert_current_to_little_endian(&mut self) {
#[cfg(target_endian = "big")] {
self.swap_bytes();
}
}
#[inline] fn convert_current_to_big_endian(&mut self) {
#[cfg(target_endian = "little")] {
self.swap_bytes();
}
}
#[inline] fn convert_little_endian_to_current(&mut self) {
#[cfg(target_endian = "big")] {
self.swap_bytes();
}
}
#[inline] fn convert_big_endian_to_current(&mut self) {
#[cfg(target_endian = "little")] {
self.swap_bytes();
}
}
#[inline] fn from_current_into_little_endian(mut self) -> Self where Self: Sized {
self.convert_current_to_little_endian();
self
}
#[inline] fn from_current_into_big_endian(mut self) -> Self where Self: Sized {
self.convert_current_to_big_endian();
self
}
#[inline] fn from_little_endian_into_current(mut self) -> Self where Self: Sized {
self.convert_little_endian_to_current();
self
}
#[inline] fn from_big_endian_into_current(mut self) -> Self where Self: Sized {
self.convert_big_endian_to_current();
self
}
}
macro_rules! call_single_arg_macro_for_each {
($macro: ident, $( $arguments: ident ),* ) => {
$( $macro! { $arguments } )*
};
}
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
}
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) {} }
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() { number.swap_bytes();
}
}
}
};
}
call_single_arg_macro_for_each! {
implement_slice_by_element,
u16, u32, u64, u128,
i16, i32, i64, i128,
f64, f32
}
pub mod io {
use super::Endian;
use std::io::{Read, Write, Result};
pub mod bytes {
use std::io::{Read, Write, Result};
#[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>()
)
}
#[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>()
)
}
#[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>()
)
}
#[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>()
)
}
#[inline]
pub unsafe fn write_slice<T>(write: &mut impl Write, value: &[T]) -> Result<()> {
write.write_all(slice_as_bytes(value))
}
#[inline]
pub unsafe fn read_slice<T>(read: &mut impl Read, value: &mut [T]) -> Result<()> {
read.read_exact(slice_as_bytes_mut(value))
}
#[inline]
pub unsafe fn write_value<T: Sized>(write: &mut impl Write, value: &T) -> Result<()> {
write.write_all(value_as_bytes(value))
}
#[inline]
pub unsafe fn read_value<T: Sized>(read: &mut impl Read, value: &mut T) -> Result<()> {
read.read_exact(value_as_bytes_mut(value))
}
}
pub trait WriteEndian<T: ?Sized> {
fn write_as_little_endian(&mut self, value: &T) -> Result<()>;
fn write_as_big_endian(&mut self, value: &T) -> Result<()>;
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) }
}
}
pub trait ReadEndian<T: ?Sized> {
fn read_from_little_endian_into(&mut self, value: &mut T) -> Result<()>;
fn read_from_big_endian_into(&mut self, value: &mut T) -> Result<()>;
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) }
}
#[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)
}
#[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)
}
#[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() }
}
}
impl<R: Read + ReadEndian<P>, P: Default> ReadPrimitive<R> for P {}
pub trait ReadPrimitive<R: Read + ReadEndian<Self>> : Sized + Default {
fn read_from_little_endian(read: &mut R) -> Result<Self> {
read.read_from_little_endian()
}
fn read_from_big_endian(read: &mut R) -> Result<Self> {
read.read_from_big_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 { self.write_as_little_endian(number)?;
}
}
#[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 { self.write_as_big_endian(number)?;
}
}
#[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
}
}