eventson 0.1.0

An event based JSON parser with competitive performance
Documentation
use std::io::{Cursor, Read};

use divan::{Bencher, black_box, counter};
use eventson::{Event, Parser};
use serde_json::Value;
use serde_json_borrow::OwnedValue;

pub fn main() {
    divan::main();
}

const CANADA: &str = "data/other/canada.json";
const CITM_CATALOG: &str = "data/other/citm_catalog.json";
const TWITTER: &str = "data/other/twitter.json";
const CATALAN_EVENTS: &str = "data/other/catalan_events.json";
const ARGS: &[&str] = &[CANADA, CITM_CATALOG, TWITTER, CATALAN_EVENTS];

#[divan::bench(args = ARGS)]
fn bench_eventson(b: Bencher, file: &str) {
    let metadata = std::fs::metadata(file).expect("Failed to get file metadata");
    let size = metadata.len();

    b.counter(counter::BytesCount::new(size))
        .with_inputs(|| {
            let mut in_file = std::fs::File::open(file).unwrap();
            let mut buf = Vec::new();
            in_file.read_to_end(&mut buf).unwrap();
            Parser::new(Cursor::new(buf), 1024 * 2, 256)
        })
        .bench_local_values(move |mut p| {
            let mut sum = 0;

            loop {
                sum += 1;
                match p.next() {
                    Ok(Event::Eof) => break,
                    Err(e) => panic!("{:?}", e),
                    _ => {}
                }
            }

            black_box(sum);
        })
}

#[divan::bench(args = ARGS)]
fn bench_serde_value(b: Bencher, file: &str) {
    let metadata = std::fs::metadata(file).expect("Failed to get file metadata");
    let size = metadata.len();

    b.counter(counter::BytesCount::new(size))
        .with_inputs(|| {
            let mut in_file = std::fs::File::open(file).unwrap();
            let mut buf = Vec::new();
            in_file.read_to_end(&mut buf).unwrap();
            buf
        })
        .bench_local_values(move |buf| {
            let r = serde_json::Deserializer::from_slice(&buf);
            let stream = r.into_iter::<Value>();

            let mut sum = 0;
            for _value in stream {
                sum += 1;
            }

            black_box(sum);
        })
}

// This give serde_json_borrow an advantage by creating the string in advance.
// In real applications you have to pay the cost of doing utf-8 validation to
// get a string slice, so I'm not sure if this is a fair comparison.
#[divan::bench(args = ARGS)]
fn bench_serde_json_borrow_from_string(b: Bencher, file: &str) {
    let metadata = std::fs::metadata(file).expect("Failed to get file metadata");
    let size = metadata.len();

    b.counter(counter::BytesCount::new(size))
        .with_inputs(|| {
            let mut in_file = std::fs::File::open(file).unwrap();
            let mut buf = String::new();
            in_file.read_to_string(&mut buf).unwrap();
            buf
        })
        .bench_local_values(move |buf| {
            let json: OwnedValue = OwnedValue::parse_from(buf).unwrap();
            black_box(json);
        });
}

// This is probably more apples-to-apples because while we read the bytes in
// ahead of time and don't allocate for the string, we are forcing
// serde_json_borrow to pay for the not free utf-8 conversion as well.
#[divan::bench(args = ARGS)]
fn bench_serde_json_borrow(b: Bencher, file: &str) {
    let metadata = std::fs::metadata(file).expect("Failed to get file metadata");
    let size = metadata.len();

    b.counter(counter::BytesCount::new(size))
        .with_inputs(|| {
            let mut in_file = std::fs::File::open(file).unwrap();
            let mut buf = Vec::new();
            in_file.read_to_end(&mut buf).unwrap();
            buf
        })
        .bench_local_values(move |buf| {
            let str_buf = String::from_utf8(buf).unwrap();
            let json: OwnedValue = OwnedValue::parse_from(str_buf).unwrap();
            black_box(json);
        });
}

#[divan::bench(args = ARGS)]
fn bench_simd_json(b: Bencher, file: &str) {
    let metadata = std::fs::metadata(file).expect("Failed to get file metadata");
    let size = metadata.len();

    b.counter(counter::BytesCount::new(size))
        .with_inputs(|| {
            let mut in_file = std::fs::File::open(file).unwrap();
            let mut buf = Vec::new();
            in_file.read_to_end(&mut buf).unwrap();
            buf
        })
        .bench_local_values(move |mut buf| {
            let v: simd_json::BorrowedValue = simd_json::to_borrowed_value(&mut buf).unwrap();
            black_box(v);
        })
}