actix-http 2.1.0

HTTP primitives for the Actix ecosystem
Documentation
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};

use bytes::BytesMut;
use http::Version;

const CODES: &[u16] = &[201, 303, 404, 515];

fn bench_write_status_line_11(c: &mut Criterion) {
    let mut group = c.benchmark_group("write_status_line v1.1");

    let version = Version::HTTP_11;

    for i in CODES.iter() {
        group.bench_with_input(BenchmarkId::new("Original (unsafe)", i), i, |b, &i| {
            b.iter(|| {
                let mut b = BytesMut::with_capacity(35);
                _original::write_status_line(version, i, &mut b);
            })
        });

        group.bench_with_input(BenchmarkId::new("New (safe)", i), i, |b, &i| {
            b.iter(|| {
                let mut b = BytesMut::with_capacity(35);
                _new::write_status_line(version, i, &mut b);
            })
        });

        group.bench_with_input(BenchmarkId::new("Naive", i), i, |b, &i| {
            b.iter(|| {
                let mut b = BytesMut::with_capacity(35);
                _naive::write_status_line(version, i, &mut b);
            })
        });
    }

    group.finish();
}

fn bench_write_status_line_10(c: &mut Criterion) {
    let mut group = c.benchmark_group("write_status_line v1.0");

    let version = Version::HTTP_10;

    for i in CODES.iter() {
        group.bench_with_input(BenchmarkId::new("Original (unsafe)", i), i, |b, &i| {
            b.iter(|| {
                let mut b = BytesMut::with_capacity(35);
                _original::write_status_line(version, i, &mut b);
            })
        });

        group.bench_with_input(BenchmarkId::new("New (safe)", i), i, |b, &i| {
            b.iter(|| {
                let mut b = BytesMut::with_capacity(35);
                _new::write_status_line(version, i, &mut b);
            })
        });

        group.bench_with_input(BenchmarkId::new("Naive", i), i, |b, &i| {
            b.iter(|| {
                let mut b = BytesMut::with_capacity(35);
                _naive::write_status_line(version, i, &mut b);
            })
        });
    }

    group.finish();
}

fn bench_write_status_line_09(c: &mut Criterion) {
    let mut group = c.benchmark_group("write_status_line v0.9");

    let version = Version::HTTP_09;

    for i in CODES.iter() {
        group.bench_with_input(BenchmarkId::new("Original (unsafe)", i), i, |b, &i| {
            b.iter(|| {
                let mut b = BytesMut::with_capacity(35);
                _original::write_status_line(version, i, &mut b);
            })
        });

        group.bench_with_input(BenchmarkId::new("New (safe)", i), i, |b, &i| {
            b.iter(|| {
                let mut b = BytesMut::with_capacity(35);
                _new::write_status_line(version, i, &mut b);
            })
        });

        group.bench_with_input(BenchmarkId::new("Naive", i), i, |b, &i| {
            b.iter(|| {
                let mut b = BytesMut::with_capacity(35);
                _naive::write_status_line(version, i, &mut b);
            })
        });
    }

    group.finish();
}

criterion_group!(
    benches,
    bench_write_status_line_11,
    bench_write_status_line_10,
    bench_write_status_line_09
);
criterion_main!(benches);

mod _naive {
    use bytes::{BufMut, BytesMut};
    use http::Version;

    pub(crate) fn write_status_line(version: Version, n: u16, bytes: &mut BytesMut) {
        match version {
            Version::HTTP_11 => bytes.put_slice(b"HTTP/1.1 "),
            Version::HTTP_10 => bytes.put_slice(b"HTTP/1.0 "),
            Version::HTTP_09 => bytes.put_slice(b"HTTP/0.9 "),
            _ => {
                // other HTTP version handlers do not use this method
            }
        }

        bytes.put_slice(n.to_string().as_bytes());
    }
}

mod _new {
    use bytes::{BufMut, BytesMut};
    use http::Version;

    const DIGITS_START: u8 = b'0';

    pub(crate) fn write_status_line(version: Version, n: u16, bytes: &mut BytesMut) {
        match version {
            Version::HTTP_11 => bytes.put_slice(b"HTTP/1.1 "),
            Version::HTTP_10 => bytes.put_slice(b"HTTP/1.0 "),
            Version::HTTP_09 => bytes.put_slice(b"HTTP/0.9 "),
            _ => {
                // other HTTP version handlers do not use this method
            }
        }

        let d100 = (n / 100) as u8;
        let d10 = ((n / 10) % 10) as u8;
        let d1 = (n % 10) as u8;

        bytes.put_u8(DIGITS_START + d100);
        bytes.put_u8(DIGITS_START + d10);
        bytes.put_u8(DIGITS_START + d1);

        bytes.put_u8(b' ');
    }
}

mod _original {
    use std::ptr;

    use bytes::{BufMut, BytesMut};
    use http::Version;

    const DEC_DIGITS_LUT: &[u8] = b"0001020304050607080910111213141516171819\
        2021222324252627282930313233343536373839\
        4041424344454647484950515253545556575859\
        6061626364656667686970717273747576777879\
        8081828384858687888990919293949596979899";

    pub(crate) const STATUS_LINE_BUF_SIZE: usize = 13;

    pub(crate) fn write_status_line(version: Version, mut n: u16, bytes: &mut BytesMut) {
        let mut buf: [u8; STATUS_LINE_BUF_SIZE] = *b"HTTP/1.1     ";

        match version {
            Version::HTTP_2 => buf[5] = b'2',
            Version::HTTP_10 => buf[7] = b'0',
            Version::HTTP_09 => {
                buf[5] = b'0';
                buf[7] = b'9';
            }
            _ => (),
        }

        let mut curr: isize = 12;
        let buf_ptr = buf.as_mut_ptr();
        let lut_ptr = DEC_DIGITS_LUT.as_ptr();
        let four = n > 999;

        // decode 2 more chars, if > 2 chars
        let d1 = (n % 100) << 1;
        n /= 100;
        curr -= 2;
        unsafe {
            ptr::copy_nonoverlapping(
                lut_ptr.offset(d1 as isize),
                buf_ptr.offset(curr),
                2,
            );
        }

        // decode last 1 or 2 chars
        if n < 10 {
            curr -= 1;
            unsafe {
                *buf_ptr.offset(curr) = (n as u8) + b'0';
            }
        } else {
            let d1 = n << 1;
            curr -= 2;
            unsafe {
                ptr::copy_nonoverlapping(
                    lut_ptr.offset(d1 as isize),
                    buf_ptr.offset(curr),
                    2,
                );
            }
        }

        bytes.put_slice(&buf);
        if four {
            bytes.put_u8(b' ');
        }
    }
}