serde_buf 0.1.3

Generic buffering for serde
Documentation
use std::hint::black_box;

use criterion::{criterion_group, criterion_main, Criterion};

use serde_buf::{Owned, Ref};
use serde_core::de::IntoDeserializer;

#[path = "data.rs"]
mod data;

use data::*;

fn export_logs_service_request(c: &mut Criterion) {
    c.bench_function("export_logs_service_request", |b| {
        b.iter(export_logs_service_request_data)
    });

    c.bench_function("export_logs_service_request_buffer", |b| {
        b.iter(|| {
            let data = export_logs_service_request_data();
            black_box(Owned::buffer(&data).unwrap());
        })
    });
}

fn borrowed(c: &mut Criterion) {
    c.bench_function("borrowed", |b| b.iter(borrowed_data));

    c.bench_function("borrowed_buffer", |b| {
        b.iter(|| {
            let data = borrowed_data();
            black_box(Owned::buffer(&data).unwrap());
        })
    });

    c.bench_function("borrowed_build_ref", |b| {
        b.iter(|| {
            let data = borrowed_data();
            black_box(borrowed_data_ref(&data));
        })
    });
}

fn owned(c: &mut Criterion) {
    c.bench_function("owned", |b| b.iter(owned_data));

    c.bench_function("owned_buffer", |b| {
        b.iter(|| {
            let data = owned_data();
            black_box(Owned::buffer(&data).unwrap());
        })
    });
}

fn clone(c: &mut Criterion) {
    c.bench_function("clone_borrowed_ref", |b| {
        let data = borrowed_data();
        let value = borrowed_data_ref(&data);

        b.iter(|| black_box(value.clone()))
    });

    c.bench_function("clone_owned", |b| {
        let data = borrowed_data();
        let value = Owned::buffer(&data).unwrap();

        b.iter(|| black_box(value.clone()))
    });

    c.bench_function("clone_owned_export_logs_service_request", |b| {
        let data = export_logs_service_request_data();
        let value = Owned::buffer(&data).unwrap();

        b.iter(|| black_box(value.clone()))
    });
}

fn stream(c: &mut Criterion) {
    // Streaming a buffered value back out through a real format
    c.bench_function("stream_borrowed_ref_to_json", |b| {
        let data = borrowed_data();
        let value = borrowed_data_ref(&data);
        let mut out = Vec::new();

        b.iter(|| {
            out.clear();
            serde_json::to_writer(&mut out, &value).unwrap();
            black_box(&out);
        })
    });

    c.bench_function("stream_owned_to_json", |b| {
        let data = export_logs_service_request_data();
        let value = Owned::buffer(&data).unwrap();
        let mut out = Vec::new();

        b.iter(|| {
            out.clear();
            serde_json::to_writer(&mut out, &value).unwrap();
            black_box(&out);
        })
    });
}

fn deserialize(c: &mut Criterion) {
    c.bench_function("deserialize_owned", |b| {
        let value = Owned::buffer(&owned_data()).unwrap();

        b.iter(|| {
            let value: OwnedData =
                serde_core::Deserialize::deserialize(black_box(value.clone()).into_deserializer())
                    .unwrap();
            black_box(value)
        })
    });
}

fn text_heavy(c: &mut Criterion) {
    // Many small strings: the per-text costs dominate
    let attributes: Vec<String> = (0..16).map(|i| format!("attribute-value-{i}")).collect();
    let attributes: Vec<&str> = attributes.iter().map(|a| a.as_str()).collect();
    let attributes = attributes.as_slice();

    c.bench_function("text_heavy_buffer", |b| {
        b.iter(|| black_box(Owned::buffer(black_box(&attributes)).unwrap()))
    });

    c.bench_function("text_heavy_build_ref", |b| {
        b.iter(|| black_box(Ref::seq(black_box(attributes).iter().map(|a| Ref::str(*a)))))
    });

    c.bench_function("text_heavy_clone_owned", |b| {
        let value = Owned::buffer(&attributes).unwrap();

        b.iter(|| black_box(value.clone()))
    });
}

fn histogram(c: &mut Criterion) {
    // An exponential histogram: pure container and primitive encoding,
    // with nothing borrowed or owned
    let buckets = histogram_data();
    let buckets = buckets.as_slice();

    c.bench_function("histogram_buffer", |b| {
        b.iter(|| black_box(Owned::buffer(black_box(&buckets)).unwrap()))
    });

    c.bench_function("histogram_stream_to_json", |b| {
        let value = Owned::buffer(&buckets).unwrap();
        let mut out = Vec::new();

        b.iter(|| {
            out.clear();
            serde_json::to_writer(&mut out, &value).unwrap();
            black_box(&out);
        })
    });
}

fn small_key_map(c: &mut Criterion) {
    // A map of 32 small string keys to integers: the per-key costs
    // dominate
    let map = small_key_map_data();

    c.bench_function("small_key_map_buffer", |b| {
        b.iter(|| black_box(Owned::buffer(black_box(&map)).unwrap()))
    });

    c.bench_function("small_key_map_deserialize", |b| {
        let value = Owned::buffer(&map).unwrap();

        b.iter(|| {
            let map: std::collections::BTreeMap<String, u64> =
                serde_core::Deserialize::deserialize(black_box(value.clone()).into_deserializer())
                    .unwrap();
            black_box(map)
        })
    });
}

criterion_group!(
    benches,
    borrowed,
    owned,
    clone,
    stream,
    deserialize,
    text_heavy,
    histogram,
    small_key_map,
    export_logs_service_request
);
criterion_main!(benches);