dat 4.7.0

DAT - Distributed Access Token
Documentation
use dat::certificate::DatCertificate;
use dat::crypto::DatCryptoAlgorithm;
use dat::error::DatError;
use dat::manager::DatManager;
use dat::payload::DatPayload;
use dat::signature::DatSignatureAlgorithm;
use dat::util::now_unix_timestamp;
use rand::RngExt;
use std::time::Instant;
use tokio::task::JoinSet;

fn rand_string() -> String {
    let mut rng = rand::rng();
    (0..100)
        .map(|_| rng.sample(rand::distr::Alphanumeric) as char)
        .collect()
}

async fn loops(
    multi_thread: bool,
    loops: i64,
    certificates: &'static [DatCertificate],
    plain: &'static String,
    secure: &'static String,
) -> Result<(), DatError> {
    println!(
        "\n{}",
        if multi_thread {
            "Multi-Thread"
        } else {
            "Single-Thread"
        }
    );

    for certificate in certificates {
        let pre = format!(
            "{} {}",
            certificate.signature_algorithm(),
            certificate.crypto_algorithm()
        );

        let mut dat = String::new();

        let start = Instant::now();
        if multi_thread {
            let mut futures: JoinSet<String> = JoinSet::new();
            for _ in 0..loops {
                futures.spawn(async move {
                    DatManager::_issue(certificate, plain.as_bytes(), secure.as_bytes()).unwrap()
                });
            }
            while let Some(res) = futures.join_next().await {
                dat = res.unwrap();
            }
        } else {
            for _ in 0..loops {
                dat = DatManager::_issue(certificate, plain.as_bytes(), secure.as_bytes())?;
            }
        }
        let duration = start.elapsed();
        println!("{pre} Issue * {loops} : {}ms", duration.as_millis());

        let dat: &'static String = Box::leak(Box::new(dat));
        let mut payload = DatManager::_parse(certificate, dat.clone().try_into()?)?;

        let start = Instant::now();
        if multi_thread {
            let mut futures: JoinSet<DatPayload> = JoinSet::new();
            for _ in 0..loops {
                futures.spawn(async move {
                    DatManager::_parse(certificate, dat.clone().try_into().unwrap()).unwrap()
                });
            }
            while let Some(res) = futures.join_next().await {
                payload = res.unwrap();
            }
        } else {
            for _ in 0..loops {
                payload = DatManager::_parse(certificate, dat.clone().try_into()?)?;
            }
        }
        let duration = start.elapsed();
        println!("{pre} Parse * {loops} : {}ms", duration.as_millis());

        assert_eq!(plain, &payload.plain_text()?);
        assert_eq!(secure, &payload.secure_text()?);
    }

    Ok(())
}

async fn benchmark(loop_size: i64) -> Result<(), DatError> {
    let plain: &'static String = Box::leak(Box::new(rand_string()));
    let secure: &'static String = Box::leak(Box::new(rand_string()));

    println!("performance test (plain, secure)");
    println!("plain: {}", plain);
    println!("secure: {}", secure);

    let mut certificates = Vec::with_capacity(6);

    for signature_algorithm in DatSignatureAlgorithm::list() {
        for crypto_algorithm in DatCryptoAlgorithm::list() {
            certificates.push(DatCertificate::generate(
                0,
                now_unix_timestamp() - 10,
                200,
                100,
                *signature_algorithm,
                *crypto_algorithm,
            )?)
        }
    }

    let certificates: &'static Vec<DatCertificate> = Box::leak(Box::new(certificates));

    loops(true, loop_size, certificates, plain, secure).await?;
    loops(false, loop_size, certificates, plain, secure).await?;

    Ok(())
}

#[tokio::test(flavor = "multi_thread")]
async fn test() {
    if cfg!(debug_assertions) {
        println!("performance test is disabled in debug mode.");
        return;
    }

    let loop_size = std::env::var("DAT_BENCH_LOOPS")
        .ok()
        .and_then(|value| value.parse().ok())
        .unwrap_or(10000);

    benchmark(loop_size).await.unwrap();
}