curio 0.0.3

A blazing fast http client
Documentation
#[allow(non_snake_case)]
use std::time::Instant;

const LIMIT: usize = 10000;

#[test]
fn bench_response_parsing() {
    bench("parse response", LIMIT, || {
        let header_line: Vec<String> = vec!["HTTP/1.1 301 TLS Redirect\r\n".to_string()];
        let test_body: Vec<String> = vec![
            "HTTP/1.1 301 TLS Redirect\r\n".to_string(),
            "Date: Fri, 21 Aug 2020 17:42:29 GMT\r\n".to_string(),
            "Content-Type: application/json; charset=utf-8\r\n".to_string(),
            "Connection: keep-alive\r\n".to_string(),
            "Set-Cookie: __cfduid=d1cd636ec4303be8a4ac9d8d01f93e1e71598031749; expires=Sun, 20-Sep-20 17:42:29 GMT; path=/; domain=.typicode.com; HttpOnly; SameSite=Lax\r\n".to_string(),
            "X-Powered-By: Express\r\n".to_string(),
            "X-Ratelimit-Limit: 1000\r\n".to_string(),
            "X-Ratelimit-Remaining: 999\r\n".to_string(),
            "X-Ratelimit-Reset: 1597842544\r\n".to_string(),
            "Vary: Origin, Accept-Encoding\r\n".to_string(),
            "Access-Control-Allow-Credentials: true\r\n".to_string(),
            "Cache-Control: max-age=43200\r\n".to_string(),
            "Pragma: no-cache\r\n".to_string(),
            "Expires: -1\r\n".to_string(),
            "X-Content-Type-Options: nosniff\r\n".to_string(),
            "Etag: W/\"5ef7-4Ad6/n39KWY9q6Ykm/ULNQ2F5IM\"\r\n".to_string(),
            "Via: 1.1 vegur\r\n".to_string(),
            "CF-Cache-Status: HIT\r\n".to_string(),
            "Age: 10212\r\n".to_string(),
            "cf-request-id: 04b3b67aed0000e608b91e0200000001\r\n".to_string(),
            "Server: cloudflare\r\n".to_string(),
            "CF-RAY: 5c6626a4ad9ae608-LHR".to_string()
        ];
        crate::structs::Response::new(test_body.join(""), header_line);
    })
}

#[test]
fn bench_cookie_parsing() {
    let cookie = "Set-Cookie: has_recent_activity=1; path=/; expires=Fri, 21 Aug 2020 21:11:53 GMT; secure; HttpOnly; SameSite=Lax";
    bench("parse cookie", LIMIT, || {
        crate::utils::parsers::parse_cookie(cookie.to_string());
    })
}

#[test]
fn bench_header_parsing() {
    let header = "Date: Fri, 21 Aug 2020 17:42:29 GMT";
    bench("parse header", LIMIT, || {
        crate::utils::parsers::parse_header(header.to_string());
    })
}

fn bench<A, B>(name: A, passes: usize, call: B) -> () where A: Into<String>, B: Fn() -> () {
    let mut passed = 0;

    let mut times = Vec::<u128>::new();

    while passed < passes {
        let start = Instant::now();

        call();

        times.push(start.elapsed().as_micros());

        passed += 1;
    }

    let mut total: usize = 0;

    let mut high: usize = 0;
    let mut low: usize = 10000;

    for time in times.clone() {
        let t = time as usize;
        total += t;
        if t > high {
            high = t;
        } else if t < low {
            low = t;
        }
    }

    let avg: usize = total / LIMIT;

    println!("{}; ({} passes): Avg: {} us  |  High: {} us  |  Low: {} us  |  S.D: {} us", name.into(), passes, avg.clone(), high, low, std_deviation(times, avg).unwrap_or(0));

    return assert_eq!(1, 1);
}

fn std_deviation(data: Vec<u128>, mean: usize) -> Option<usize> {
    let mut data2 = Vec::<u32>::new();
    let mean2 = mean as u32;
    for x in data {
        data2.push(x as u32)
    }

    let mean3 = mean2 as f32;

    match (mean3, data2.len()) {
        (data_mean, count) if count > 0 => {
            let variance = data2.iter().map(|value| {
                let diff = data_mean - (*value as f32);

                diff * diff
            }).sum::<f32>() / count as f32;

            Some(variance.sqrt() as usize)
        }
        _ => None
    }
}