binserde 0.1.7

A crate for serializing data structures into a binary format
Documentation
use std::io;
use std::io::{Read, Write};

use byteorder::ReadBytesExt;

pub fn encode_min(num: i64) -> u64 {
    let u_num = num as u64;
    (u_num << 1 ^ (num >> 63) as u64) | u_num >> 63
}

pub fn decode_min(num: u64) -> i64 {
    (num >> 1) as i64 ^ ((num << 63) as i64) >> 63
}

pub fn varint_write<W: Write>(num: u64, mut pipe: W) -> io::Result<usize> {
    let mut num_pos = 0;
    let mut idx = 0;
    let mut buf = [0; 9];
    let data_bits = 64 - num.leading_zeros();

    loop {
        let next = if data_bits - num_pos > 7 {
            0b10000000
        } else {
            0
        };
        let piece = (num >> num_pos) as u8 & 0b01111111 | next;
        buf[idx] = piece;
        idx += 1;
        num_pos += 7;

        if !(num_pos < data_bits) {
            break;
        }
    }

    pipe.write(&buf[..idx])?;

    Ok(idx)
}

pub fn varint_read<R: Read>(mut pipe: R) -> io::Result<u64> {
    let mut offset = 0;
    let mut num = 0;

    loop {
        let byte = pipe.read_u8()?;
        let has_next = byte & 0b10000000 != 0;
        num |= (byte as u64 & 0b01111111) << offset;
        offset += 7;

        if !has_next {
            break;
        }
    }

    Ok(num)
}

#[cfg(test)]
mod test {
    use crate::varint::{decode_min, encode_min, varint_read, varint_write};

    #[test]
    fn test_encode_min() {
        for i in -5..5 {
            let r = encode_min(i);
            println!("{} = {:016X}", i, r);
            assert_eq!(i, decode_min(r));
        }

        for i in i64::MAX - 5..=i64::MAX {
            let r = encode_min(i);
            println!("{} = {:016X}", i, r);
            assert_eq!(i, decode_min(r));
        }

        for i in i64::MIN..i64::MIN + 5 {
            let r = encode_min(i);
            println!("{} = {:016X}", i, r);
            assert_eq!(i, decode_min(r));
        }
    }

    #[test]
    fn test_varint() {
        use std::io::Cursor;

        let mut buf = Cursor::new(Vec::new());

        varint_write(0, &mut buf).unwrap();
        varint_write(16, &mut buf).unwrap();
        varint_write(234567892322414124, &mut buf).unwrap();
        varint_write(encode_min(-18), &mut buf).unwrap();
        varint_write(encode_min(20000000), &mut buf).unwrap();

        buf.set_position(0);
        for item in buf.get_ref().iter() {
            print!("{:02X}", item);
            if item & 0b10000000 == 0 {
                print!("] ");
            } else {
                print!(" ");
            }
        }
        println!();

        assert_eq!(0, varint_read(&mut buf).unwrap());
        assert_eq!(16, varint_read(&mut buf).unwrap());
        assert_eq!(234567892322414124, varint_read(&mut buf).unwrap());
        assert_eq!(encode_min(-18), varint_read(&mut buf).unwrap());
        assert_eq!(encode_min(20000000), varint_read(&mut buf).unwrap());
    }
}