Crate endiannezz[−][src]
Expand description
This crate provides the ability to encode and decode all primitive types into different endianness
How it works?
Crate automatically implements Primitive
trait for each primitive type.
This allows to write abstractions and call the appropriate method depending on
the byte order that you passed to the function template. Endian
it’s something
like a proxy to do it.
Macros create implementations for I/O endianness:
NativeEndian
, LittleEndian
and BigEndian
All these types are enums, which means that you cannot create them, only pass to the template.
Now it’s possible to have traits that expand Read
and Write
with new methods.
Simple example
use endiannezz::ext::{EndianReader, EndianWriter}; use endiannezz::{BigEndian, LittleEndian, NativeEndian}; use std::io::Result; fn main() -> Result<()> { let mut vec = Vec::new(); vec.try_write::<LittleEndian, i32>(1)?; vec.try_write::<BigEndian, _>(2)?; vec.try_write::<NativeEndian, _>(3_u16)?; let mut slice = vec.as_slice(); slice.try_read::<LittleEndian, i32>()?; let _num32: i32 = slice.try_read::<BigEndian, _>()?; let _num16: u16 = slice.try_read::<NativeEndian, _>()?; Ok(()) }
You can also use this syntax:
use endiannezz::{BigEndian, Endian, LittleEndian}; use std::io::Result; fn main() -> Result<()> { let mut vec = Vec::new(); BigEndian::write(1, &mut vec)?; LittleEndian::write::<u16, _>(2, &mut vec)?; assert_eq!(vec.as_slice(), &[0, 0, 0, 1, 2, 0]); Ok(()) }
Using #[derive(Io)]
to describe complex binary formats
use endiannezz::ext::{EndianReader, EndianWriter}; use endiannezz::{Io, LittleEndian}; use std::io::{Read, Result, Write}; struct Bytes(Vec<u8>); //Custom implementation of read and write //Use it for complex types, which can be built from primitives impl Io for Bytes { fn write<W: Write>(&self, mut w: W) -> Result<()> { w.try_write::<LittleEndian, u32>(self.0.len() as u32)?; w.write_all(self.0.as_slice())?; Ok(()) } fn read<R: Read>(mut r: R) -> Result<Self> { let capacity = r.try_read::<LittleEndian, u32>()? as usize; let mut vec = vec![0; capacity]; r.read_exact(&mut vec)?; Ok(Self(vec)) } } #[derive(Io)] //default endian for fields of struct (except custom impl, such as Bytes) #[endian(little)] //There are 3 types of endianness and they can be written in the `#[endian]` attribute as follows: // - NativeEndian: `_`, `ne`, `native` // - LittleEndian: `le`, `little` // - BigEndian: `be`, `big` struct Message { //will read/write data as is (according to implementation) bytes: Bytes, //u16 in little-endian distance: u16, //f32 in big-endian, you can override default endian! #[endian(big)] delta: f32, //machine byte order #[endian(native)] machine_data: u32, } fn main() -> Result<()> { let message = Message { bytes: Bytes(vec![0xde, 0xad, 0xbe, 0xef]), distance: 5, delta: 2.41, machine_data: 41, }; //writing message into Vec let mut vec = Vec::new(); message.write(&mut vec)?; //explain let mut excepted = vec![ 4, 0, 0, 0, //bytes len in little-endian 0xde, 0xad, 0xbe, 0xef, //buffer 5, 0, //distance in little-endian 0x40, 0x1a, 0x3d, 0x71, //delta in big-endian ]; if cfg!(target_endian = "little") { excepted.extend(&[41, 0, 0, 0]); //machine_data on little-endian CPUs } else { excepted.extend(&[0, 0, 0, 41]); //machine_data on big-endian CPUs } assert_eq!(vec, excepted); //reading message from slice let mut slice = vec.as_slice(); let _message1 = Message::read(&mut slice)?; Ok(()) }
Modules
Internal module to simplify proc_macro
implementation
Enums
Traits
Proxy for reading and writing primitive types
Allows the type to be encoded/decoded using binary format
This trait is implemented for all primitive types that exist in rust, and allows to read types from bytes or write them into bytes