multi-codec 1.0.2

Implementation of the Multicodec specification
// SPDX-License-Identifier: MIT or Apache-2.0
//! Performance benchmarks for multi-codec

use std::hint::black_box;

use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use multi_codec::Codec;
use multi_trait::TryDecodeFrom;

/// Benchmark conversions from u64
fn bench_from_u64(c: &mut Criterion) {
    c.bench_function("codec_from_u64_valid", |b| {
        b.iter(|| Codec::try_from(black_box(0xEDu64)))
    });

    c.bench_function("codec_from_u64_invalid", |b| {
        b.iter(|| Codec::try_from(black_box(0xDEADBEEFu64)))
    });
}

/// Benchmark conversions to u64
fn bench_to_u64(c: &mut Criterion) {
    let codec = Codec::Ed25519Pub;

    c.bench_function("codec_to_u64", |b| {
        b.iter(|| {
            let _code: u64 = black_box(codec).into();
        })
    });

    c.bench_function("codec_code_method", |b| b.iter(|| black_box(codec).code()));
}

/// Benchmark conversions from string
fn bench_from_str(c: &mut Criterion) {
    c.bench_function("codec_from_str_valid", |b| {
        b.iter(|| Codec::try_from(black_box("ed25519-pub")))
    });

    c.bench_function("codec_from_str_invalid", |b| {
        b.iter(|| Codec::try_from(black_box("unknown-codec")))
    });
}

/// Benchmark conversions to string
fn bench_to_str(c: &mut Criterion) {
    c.bench_function("codec_as_str", |b| {
        let codec = Codec::Ed25519Pub;
        b.iter(|| {
            let s = codec.as_str();
            black_box(s.len())
        })
    });
}

/// Benchmark encoding
fn bench_encoding(c: &mut Criterion) {
    let mut group = c.benchmark_group("encoding");

    let codecs = vec![
        ("Identity", Codec::Identity),
        ("Sha2256", Codec::Sha2256),
        ("Ed25519Pub", Codec::Ed25519Pub),
    ];

    for (name, codec) in codecs {
        group.bench_with_input(BenchmarkId::new("into_vec", name), &codec, |b, &codec| {
            b.iter(|| {
                let _v: Vec<u8> = black_box(codec).into();
            })
        });
    }

    group.finish();
}

/// Benchmark decoding
fn bench_decoding(c: &mut Criterion) {
    let mut group = c.benchmark_group("decoding");

    let test_cases = vec![
        ("Identity", vec![0x00]),
        ("Sha2256", vec![0x12]),
        ("Ed25519Pub", vec![0xED, 0x01]),
    ];

    for (name, bytes) in test_cases {
        group.bench_with_input(
            BenchmarkId::new("try_decode_from", name),
            &bytes,
            |b, bytes| b.iter(|| Codec::try_decode_from(black_box(bytes.as_slice()))),
        );
    }

    group.finish();
}

/// Benchmark hash operations
fn bench_hash(c: &mut Criterion) {
    use std::collections::hash_map::DefaultHasher;
    use std::hash::{Hash, Hasher};

    let codec = Codec::Ed25519Pub;

    c.bench_function("codec_hash", |b| {
        b.iter(|| {
            let mut hasher = DefaultHasher::new();
            black_box(codec).hash(&mut hasher);
            hasher.finish()
        })
    });
}

/// Benchmark roundtrip operations
fn bench_roundtrip(c: &mut Criterion) {
    let mut group = c.benchmark_group("roundtrip");

    group.bench_function("encode_decode", |b| {
        let codec = Codec::Ed25519Pub;
        b.iter(|| {
            let encoded: Vec<u8> = black_box(codec).into();
            let (decoded, _) = Codec::try_decode_from(black_box(&encoded)).unwrap();
            black_box(decoded);
        })
    });

    group.bench_function("str_codec_str", |b| {
        b.iter(|| {
            let codec = Codec::try_from(black_box("ed25519-pub")).unwrap();
            let len = codec.as_str().len();
            black_box(len);
        })
    });

    group.bench_function("u64_codec_u64", |b| {
        b.iter(|| {
            let codec = Codec::try_from(black_box(0xEDu64)).unwrap();
            let _code: u64 = codec.into();
        })
    });

    group.finish();
}

/// Benchmark serde operations
#[cfg(feature = "serde")]
fn bench_serde(c: &mut Criterion) {
    use serde_json;

    let mut group = c.benchmark_group("serde");

    let codec = Codec::Ed25519Pub;

    group.bench_function("json_serialize", |b| {
        b.iter(|| serde_json::to_string(&black_box(codec)))
    });

    let json = serde_json::to_string(&codec).unwrap();
    group.bench_function("json_deserialize", |b| {
        b.iter(|| serde_json::from_str::<Codec>(black_box(&json)))
    });

    group.bench_function("cbor_serialize", |b| {
        b.iter(|| serde_cbor::to_vec(&black_box(codec)))
    });

    let cbor = serde_cbor::to_vec(&codec).unwrap();
    group.bench_function("cbor_deserialize", |b| {
        b.iter(|| serde_cbor::from_slice::<Codec>(black_box(&cbor)))
    });

    group.finish();
}

#[cfg(feature = "serde")]
criterion_group!(
    benches,
    bench_from_u64,
    bench_to_u64,
    bench_from_str,
    bench_to_str,
    bench_encoding,
    bench_decoding,
    bench_hash,
    bench_roundtrip,
    bench_serde
);

#[cfg(not(feature = "serde"))]
criterion_group!(
    benches,
    bench_from_u64,
    bench_to_u64,
    bench_from_str,
    bench_to_str,
    bench_encoding,
    bench_decoding,
    bench_hash,
    bench_roundtrip
);

criterion_main!(benches);