#![feature(test)]

extern crate rmpv;
extern crate test;

use test::Bencher;

use rmpv::decode::*;

// Encoded value: [1, 0, [[["127.0.0.1", 59074]], 1, {0: ["read", {}, {0: ["value", {}], 1: ["error", {}]}], 1: ["write", {}, {0: ["value", {}], 1: ["error", {}]}], 2: ["remove", {}, {0: ["value", {}], 1: ["error", {}]}], 3: ["find", {}, {0: ["value", {}], 1: ["error", {}]}]}], [[80, 81, 82]]].
const COMPLEX: &[u8] = [
    0x94, 0x01, 0x00, 0x93, 0x91, 0x92, 0xa9, 0x31,
    0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31,
    0xcd, 0xe6, 0xc2, 0x01, 0x84, 0x00, 0x93, 0xa4,
    0x72, 0x65, 0x61, 0x64, 0x80, 0x82, 0x00, 0x92,
    0xa5, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x80, 0x01,
    0x92, 0xa5, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x80,
    0x01, 0x93, 0xa5, 0x77, 0x72, 0x69, 0x74, 0x65,
    0x80, 0x82, 0x00, 0x92, 0xa5, 0x76, 0x61, 0x6c,
    0x75, 0x65, 0x80, 0x01, 0x92, 0xa5, 0x65, 0x72,
    0x72, 0x6f, 0x72, 0x80, 0x02, 0x93, 0xa6, 0x72,
    0x65, 0x6d, 0x6f, 0x76, 0x65, 0x80, 0x82, 0x00,
    0x92, 0xa5, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x80,
    0x01, 0x92, 0xa5, 0x65, 0x72, 0x72, 0x6f, 0x72,
    0x80, 0x03, 0x93, 0xa4, 0x66, 0x69, 0x6e, 0x64,
    0x80, 0x82, 0x00, 0x92, 0xa5, 0x76, 0x61, 0x6c,
    0x75, 0x65, 0x80, 0x01, 0x92, 0xa5, 0x65, 0x72,
    0x72, 0x6f, 0x72, 0x80, 0x91, 0x93, 0x50, 0x51,
    0x52,
];

#[bench]
fn from_string_read_value(b: &mut Bencher) {
    // Lorem ipsum dolor sit amet.
    let buf = [
        0xbb, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73, 0x75,
        0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74,
        0x20, 0x61, 0x6d, 0x65, 0x74, 0x2e
    ];

    b.iter(|| {
        let res = read_value(&mut &buf[..]).unwrap();
        test::black_box(res);
    });
}

#[bench]
fn from_string_read_value_ref(b: &mut Bencher) {
    // Lorem ipsum dolor sit amet.
    let buf = [
        0xbb, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73, 0x75,
        0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74,
        0x20, 0x61, 0x6d, 0x65, 0x74, 0x2e
    ];

    b.iter(|| {
        let res = read_value_ref(&mut &buf[..]).unwrap();
        test::black_box(res);
    });
}

#[bench]
fn from_complex_read_value(b: &mut Bencher) {
    b.iter(|| {
        let res = read_value(&mut &COMPLEX[..]).unwrap();
        test::black_box(res);
    });
    b.bytes = buf.len() as u64;
}

#[bench]
fn from_complex_read_value_ref(b: &mut Bencher) {
    b.iter(|| {
        let res = read_value_ref(&mut &COMPLEX[..]).unwrap();
        test::black_box(res);
    });
    b.bytes = buf.len() as u64;
}

#[bench]
fn from_complex_write_value_ref(b: &mut Bencher) {
    use rmpv::ValueRef::*;
    use rmpv::encode::write_value_ref;

    let val = Array(vec![Nil, U64(42), F64(3.1415),
        String("Lorem ipsum dolor sit amet."), Map(vec![(String("key"), String("value"))])]);

    let mut buf = [0u8; 64];

    b.iter(|| {
        let res = write_value_ref(&mut &mut buf[..], &val).unwrap();
        test::black_box(res);
    });
    b.bytes = 51;
}

#[bench]
fn from_complex_read_value_ref_to_owned(b: &mut Bencher) {
    let buf = [
        0x95, // Fixed array with 5 len.
        0xc0, // Nil.
        0x2a, // 42.
        0xcb, 0x40, 0x9, 0x21, 0xca, 0xc0, 0x83, 0x12, 0x6f, // 3.1415
        // Fixed string with "Lorem ipsum dolor sit amet." content.
        0xbb, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73, 0x75,
        0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74,
        0x20, 0x61, 0x6d, 0x65, 0x74, 0x2e,
        0x81, // Fixed map with 1 len.
        0xa3, 0x6b, 0x65, 0x79, // Key "key".
        0xa5, 0x76, 0x61, 0x6c, 0x75, 0x65 // Value: "value".
    ];

    b.iter(|| {
        let res = read_value_ref(&mut &buf[..]).unwrap().to_owned();
        test::black_box(res);
    });
    b.bytes = buf.len() as u64;
}
