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

Provides extensions for Read and Write traits

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