scanf 1.2.1

Parse text inputs (inverse of print! and format!)
Documentation
#![allow(unused_must_use)]
#![allow(clippy::needless_return)]

use std::{any::Any, error::Error, str::FromStr};

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

use scanf::sscanf;

const TEN_U16_NUMBERS_SEPARATED_BY_COMMAS: [&str; 10] = [
    "1,2,3,4,5,6,7,8,9,0",
    "11,12,13,14,15,16,17,18,19,20",
    "161,162,163,164,165,166,167,168,169,161",
    "12453,22325,35645,47872,57834,63276,63876,09283,45673,04132",
    "65535,65535,65535,65535,65535,65535,65535,65535,65535,65535",
    "18456,24574,45673,36754,35675,64673,45547,23458,46549,34620",
    "45641,13422,24233,34124,55423,45236,23457,24578,06239,00000",
    "56336,43532,45324,45345,34534,34789,32474,35853,26994,43530",
    "56981,52353,13123,14241,24445,03466,42357,24658,63469,18760",
    "53669,53456,45613,14241,53435,23426,23567,35248,34539,34534",
];

fn sscanf_10_same_elements_of<T: Default + FromStr + Any>(
    input: &str,
) -> (T, T, T, T, T, T, T, T, T, T)
where
    <T as FromStr>::Err: Error + Send + Sync,
{
    let (
        mut number0,
        mut number1,
        mut number2,
        mut number3,
        mut number4,
        mut number5,
        mut number6,
        mut number7,
        mut number8,
        mut number9,
    ) = (
        T::default(),
        T::default(),
        T::default(),
        T::default(),
        T::default(),
        T::default(),
        T::default(),
        T::default(),
        T::default(),
        T::default(),
    );
    sscanf!(
        input,
        "{},{},{},{},{},{},{},{},{},{}",
        number0,
        number1,
        number2,
        number3,
        number4,
        number5,
        number6,
        number7,
        number8,
        number9
    )
    .unwrap();
    return (
        number0, number1, number2, number3, number4, number5, number6, number7, number8, number9,
    );
}

const INPUT_FORMATS: [&str; 4] = ["", "{}", "{},{}", "{string},{u64}"];

fn sscanf_benchmark(c: &mut Criterion) {
    let mut group = c.benchmark_group("input-format-parse-benchmark");
    for input_format in INPUT_FORMATS {
        group.throughput(Throughput::Bytes(input_format.len() as u64));
        group.bench_with_input(
            format!("Parse input format {:?}", input_format),
            input_format,
            |b, input_format| {
                b.iter(|| {
                    let input_parser = scanf::format::InputFormatParser::new(input_format).unwrap();
                    black_box(input_parser);
                })
            },
        );
    }
    group.finish();

    let mut group = c.benchmark_group("throughput-benchmark");
    for (i, &input) in TEN_U16_NUMBERS_SEPARATED_BY_COMMAS.iter().enumerate() {
        group.throughput(Throughput::Bytes(input.len() as u64));
        group.bench_with_input(
            format!("Sscanf 10 u16 as u16 separated by commas {}", i),
            input,
            |b, input| b.iter(|| sscanf_10_same_elements_of::<u16>(input)),
        );
        group.bench_with_input(
            format!("Sscanf 10 u16 as u32 separated by commas {}", i),
            input,
            |b, input| b.iter(|| sscanf_10_same_elements_of::<u32>(input)),
        );
        group.bench_with_input(
            format!("Sscanf 10 u16 as u64 separated by commas {}", i),
            input,
            |b, input| b.iter(|| sscanf_10_same_elements_of::<u64>(input)),
        );
        group.bench_with_input(
            format!("Sscanf 10 u16 as u128 separated by commas {}", i),
            input,
            |b, input| b.iter(|| sscanf_10_same_elements_of::<u128>(input)),
        );
        group.bench_with_input(
            format!("Sscanf 10 u16 as String separated by commas {}", i),
            input,
            |b, input| b.iter(|| sscanf_10_same_elements_of::<String>(input)),
        );
    }
    group.finish();

    let input = black_box("-5");
    c.bench_function("Sscanf i32", |b| {
        b.iter(|| {
            let mut first_number: i32 = 0;
            sscanf!(input, "{}", first_number);
            black_box(first_number);
        })
    });

    let input = black_box("-5");
    c.bench_function("Sscanf i64", |b| {
        b.iter(|| {
            let mut first_number: i64 = 0;
            sscanf!(input, "{}", first_number);
            black_box(first_number);
        })
    });

    let input = black_box("5");
    c.bench_function("Sscanf u32", |b| {
        b.iter(|| {
            let mut first_number: u32 = 0;
            sscanf!(input, "{}", first_number);
            black_box(first_number);
        })
    });

    let input = black_box("5");
    c.bench_function("Sscanf u64", |b| {
        b.iter(|| {
            let mut first_number: u64 = 0;
            sscanf!(input, "{}", first_number);
            black_box(first_number);
        })
    });

    let input = black_box("2.5");
    c.bench_function("Sscanf f32", |b| {
        b.iter(|| {
            let mut first_number: f32 = 0.0;
            sscanf!(input, "{}", first_number);
            black_box(first_number);
        })
    });

    let input = black_box("2.5");
    c.bench_function("Sscanf f64", |b| {
        b.iter(|| {
            let mut first_number: f64 = 0.0;
            sscanf!(input, "{}", first_number);
            black_box(first_number);
        })
    });

    let input = black_box("Candy");
    c.bench_function("Sscanf string", |b| {
        b.iter(|| {
            let mut product: String = String::new();
            sscanf!(input, "{}", product);
            black_box(product);
        })
    });

    let input = black_box("{Candy}");
    c.bench_function("Sscanf string with brackets", |b| {
        b.iter(|| {
            let mut product: String = String::new();
            sscanf!(input, "{}", product);
            black_box(product);
        })
    });

    let input = black_box("{Candy}");
    c.bench_function("Sscanf string with brackets ignored", |b| {
        b.iter(|| {
            let mut product: String = String::new();
            sscanf!(input, "{{{}}}", product);
            black_box(product);
        })
    });

    let input = black_box("Candy -> 2.75");
    c.bench_function("Sscanf string & f64", |b| {
        b.iter(|| {
            let mut product: String = String::new();
            let mut price: f64 = 0.0;
            sscanf!(input, "{} -> {}", product, price);
            black_box(product);
            black_box(price);
        })
    });

    let input = black_box("5 -> 2.5");
    c.bench_function("Sscanf u32 & f64", |b| {
        b.iter(|| {
            let mut first_number: u32 = 0;
            let mut second_number: f64 = 0.0;
            sscanf!(input, "{} -> {}", first_number, second_number);
            black_box(first_number);
            black_box(second_number);
        })
    });
}

criterion_group!(benches, sscanf_benchmark);
criterion_main!(benches);