speedy 0.8.7

A fast binary serialization framework
Documentation
#![feature(test)]

extern crate test;

use std::io::Write;
use std::borrow::Cow;
use test::{Bencher, black_box};
use speedy::{Context, Readable, Reader, Writable, Endianness};

#[bench]
fn write_manual_megabyte_buffer( b: &mut Bencher ) {
    let mut buffer: Vec< u8 > = Vec::new();
    buffer.resize( 1024 * 1024, 1 );
    buffer = black_box( buffer );
    b.iter( || {
        let mut output = Vec::new();
        Write::write_all( &mut output, &buffer ).unwrap();
        output
    })
}

// These two benchmarks should have exactly the same speeds.
#[bench]
fn write_speedy_megabyte_buffer_le( b: &mut Bencher ) {
    let mut buffer: Vec< u8 > = Vec::new();
    buffer.resize( 1024 * 1024, 1 );
    buffer = black_box( buffer );
    b.iter( || {
        let mut output = Vec::new();
        buffer.write_to_stream_with_ctx( Endianness::LittleEndian, &mut output ).unwrap();
        output
    })
}

#[bench]
fn write_speedy_megabyte_buffer_be( b: &mut Bencher ) {
    let mut buffer: Vec< u8 > = Vec::new();
    buffer.resize( 1024 * 1024, 1 );
    buffer = black_box( buffer );
    b.iter( || {
        let mut output = Vec::new();
        buffer.write_to_stream_with_ctx( Endianness::BigEndian, &mut output ).unwrap();
        output
    })
}

#[bench]
fn read_speedy_megabyte_buffer_cow_borrowed( b: &mut Bencher ) {
    let mut buffer: Vec< u8 > = Vec::new();
    buffer.resize( 1024 * 1024, 1 );
    let mut buffer = buffer.write_to_vec_with_ctx( Endianness::NATIVE ).unwrap();

    buffer = black_box( buffer );
    b.iter( || {
        let deserialized: Cow< [u8] > = Readable::read_from_buffer_with_ctx( Endianness::NATIVE, &buffer ).unwrap();
        deserialized
    })
}

#[bench]
fn read_speedy_megabyte_buffer_cow_owned( b: &mut Bencher ) {
    let mut buffer: Vec< u8 > = Vec::new();
    buffer.resize( 1024 * 1024, 1 );
    let mut buffer = buffer.write_to_vec_with_ctx( Endianness::NATIVE ).unwrap();

    buffer = black_box( buffer );
    b.iter( || {
        let deserialized: Cow< [u8] > = Readable::read_from_buffer_copying_data_with_ctx( Endianness::NATIVE, &buffer ).unwrap();
        deserialized
    })
}

#[repr(transparent)]
#[derive(Copy, Clone, Writable)]
struct Byte( u8 );

impl< 'a, C: Context > Readable< 'a, C > for Byte {
    #[inline]
    fn read_from< R: Reader< 'a, C > >( reader: &mut R ) -> Result< Self, C::Error > {
        Ok( Byte( reader.read_u8()? ) )
    }

    #[inline]
    fn minimum_bytes_needed() -> usize {
        1
    }
}

#[bench]
fn read_speedy_megabyte_buffer_vec_non_primitive( b: &mut Bencher ) {
    let mut buffer: Vec< Byte > = Vec::new();
    buffer.resize( 1024 * 1024, Byte( 1 ) );
    let mut buffer = buffer.write_to_vec_with_ctx( Endianness::NATIVE ).unwrap();

    buffer = black_box( buffer );
    b.iter( || {
        let deserialized: Vec< Byte > = Readable::read_from_buffer_copying_data_with_ctx( Endianness::NATIVE, &buffer ).unwrap();
        deserialized
    })
}

#[derive(Clone, Readable, Writable)]
struct Dummy {
    a: u64,
    b: u32,
    c: u16,
    d: u8,
    e: f32,
    f: f64,
    g: bool
}

#[bench]
fn read_speedy_many_small_structs( b: &mut Bencher ) {
    let mut buffer: Vec< Dummy > = Vec::new();
    let dummy = Dummy {
        a: 1,
        b: 2,
        c: 3,
        d: 4,
        e: 5.0,
        f: 6.0,
        g: true
    };
    buffer.resize( 1024 * 1024, dummy );
    let mut buffer = buffer.write_to_vec_with_ctx( Endianness::NATIVE ).unwrap();

    buffer = black_box( buffer );
    b.iter( || {
        let deserialized: Vec< Dummy > = Readable::read_from_buffer_copying_data_with_ctx( Endianness::NATIVE, &buffer ).unwrap();
        deserialized
    })
}

#[bench]
fn write_speedy_many_small_structs( b: &mut Bencher ) {
    let mut buffer: Vec< Dummy > = Vec::new();
    let dummy = Dummy {
        a: 1,
        b: 2,
        c: 3,
        d: 4,
        e: 5.0,
        f: 6.0,
        g: true
    };
    buffer.resize( 1024 * 1024, dummy );

    buffer = black_box( buffer );
    b.iter( || {
        buffer.write_to_vec_with_ctx( Endianness::NATIVE ).unwrap()
    })
}

pub struct XorShift64 {
    a: u64,
}

impl XorShift64 {
    pub fn new( seed: u64 ) -> XorShift64 {
        XorShift64 { a: seed }
    }

    pub fn next( &mut self ) -> u64 {
        let mut x = self.a;
        x ^= x << 13;
        x ^= x >> 7;
        x ^= x << 17;
        self.a = x;
        x
    }
}

#[bench]
fn read_varint_random( b: &mut Bencher ) {
    use speedy::private::VarInt64;
    let mut rng = XorShift64 { a: 1234 };

    let buffer: Vec< VarInt64 > = (0..1024 * 1024).into_iter().map( |_| (1_u64 << (rng.next() % 63)).into() ).collect();
    let mut buffer = buffer.write_to_vec_with_ctx( Endianness::NATIVE ).unwrap();

    buffer = black_box( buffer );
    b.iter( || {
        let deserialized: Vec< VarInt64 > = Readable::read_from_buffer_copying_data_with_ctx( Endianness::NATIVE, &buffer ).unwrap();
        deserialized
    })
}

#[bench]
fn read_varint_always_one_byte( b: &mut Bencher ) {
    use speedy::private::VarInt64;
    let mut rng = XorShift64 { a: 1234 };

    let buffer: Vec< VarInt64 > = (0..1024 * 1024).into_iter().map( |_| (rng.next() % 100).into() ).collect();
    let mut buffer = buffer.write_to_vec_with_ctx( Endianness::NATIVE ).unwrap();

    buffer = black_box( buffer );
    b.iter( || {
        let deserialized: Vec< VarInt64 > = Readable::read_from_buffer_copying_data_with_ctx( Endianness::NATIVE, &buffer ).unwrap();
        deserialized
    })
}

#[bench]
fn read_varint_always_eight_bytes( b: &mut Bencher ) {
    use speedy::private::VarInt64;
    let mut rng = XorShift64 { a: 1234 };

    let buffer: Vec< VarInt64 > = (0..1024 * 1024).into_iter().map( |_| ((rng.next() % 100) | (1 << 63)).into() ).collect();
    let mut buffer = buffer.write_to_vec_with_ctx( Endianness::NATIVE ).unwrap();

    buffer = black_box( buffer );
    b.iter( || {
        let deserialized: Vec< VarInt64 > = Readable::read_from_buffer_copying_data_with_ctx( Endianness::NATIVE, &buffer ).unwrap();
        deserialized
    })
}

#[bench]
fn write_varint_random( b: &mut Bencher ) {
    use speedy::private::VarInt64;
    let mut rng = XorShift64 { a: 1234 };

    let buffer: Vec< VarInt64 > = (0..1024 * 1024).into_iter().map( |_| (1_u64 << (rng.next() % 63)).into() ).collect();
    let mut buffer = buffer.write_to_vec_with_ctx( Endianness::NATIVE ).unwrap();

    buffer = black_box( buffer );
    b.iter( || {
        buffer.write_to_vec_with_ctx( Endianness::NATIVE ).unwrap()
    })
}

#[bench]
fn write_varint_always_one_byte( b: &mut Bencher ) {
    use speedy::private::VarInt64;
    let mut rng = XorShift64 { a: 1234 };

    let buffer: Vec< VarInt64 > = (0..1024 * 1024).into_iter().map( |_| (rng.next() % 100).into() ).collect();
    let mut buffer = buffer.write_to_vec_with_ctx( Endianness::NATIVE ).unwrap();

    buffer = black_box( buffer );
    b.iter( || {
        buffer.write_to_vec_with_ctx( Endianness::NATIVE ).unwrap()
    })
}

#[bench]
fn write_varint_always_eight_bytes( b: &mut Bencher ) {
    use speedy::private::VarInt64;
    let mut rng = XorShift64 { a: 1234 };

    let buffer: Vec< VarInt64 > = (0..1024 * 1024).into_iter().map( |_| ((rng.next() % 100) | (1 << 63)).into() ).collect();
    let mut buffer = buffer.write_to_vec_with_ctx( Endianness::NATIVE ).unwrap();

    buffer = black_box( buffer );
    b.iter( || {
        buffer.write_to_vec_with_ctx( Endianness::NATIVE ).unwrap()
    })
}