hirun 0.1.22

A concurrent framework for asynchronous programming based on event-driven, non-blocking I/O mechanism
Documentation
use std::io;
use tokio::net::*;

type Error = io::Error;
type Fd = TcpStream;

static BODY: [u8; 4 << 20] = [0; 4 << 20];

pub struct HttpReq {
    status: u32,
}

impl HttpReq {
    pub const fn new() -> HttpReq {
        HttpReq { status: 0 }
    }

    fn parse(&mut self, data: &[u8]) {
        for c in data {
            match c {
                b'\r' => {
                    if (self.status & 0x01) == 0 {
                        self.status += 1;
                    } else {
                        self.status = 1;
                    }
                }
                b'\n' => {
                    if (self.status & 0x01) == 1 {
                        self.status += 1;
                    } else {
                        self.status = 0;
                    }
                }
                _ => self.status = 0,
            }

            if self.status == 4 {
                break;
            }
        }
    }

    fn is_ok(&self) -> bool {
        self.status == 4
    }

    fn try_read(&mut self, conn: &Fd) -> Result<(), Error> {
        let mut buf = [0_u8; 2048];
        match conn.try_read(&mut buf) {
            Ok(0) => Err(Error::new(io::ErrorKind::InvalidInput, "")),
            Ok(n) => {
                self.parse(&buf[..n]);
                Ok(())
            }
            Err(e) => Err(e),
        }
    }

    pub async fn read(&mut self, conn: &Fd) -> Result<(), Error> {
        while !self.is_ok() {
            match self.try_read(conn) {
                Ok(_) => {},
                Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
                    conn.readable().await?;
                    continue;
                }
                Err(e) => return Err(e),
            }
        }
        Ok(())
    }
}

pub struct HttpRsp {
    body_size: usize,
}

impl HttpRsp {
    pub const fn new(body_size: usize) -> Self {
        Self { body_size }
    }

    async fn write_head(&self, conn: &Fd) -> Result<(), Error> {
        let hdr = format!(
            "HTTP/1.1 200 Ok\r\nContent-Length: {}\r\n\r\n",
            self.body_size
        );
        let _ = write_all(conn, hdr.as_bytes()).await?;
        Ok(())
    }

    pub async fn write(&self, conn: &Fd) -> Result<(), Error> {
        self.write_head(conn).await?;
        let mut size = self.body_size;
        while size > 0 {
            let len = core::cmp::min(size, BODY.len());
            let _ = write_all(conn, &BODY[..len]).await?;
            size -= len;
        }
        Ok(())
    }
}

async fn write_all(conn: &Fd, mut data: &[u8]) -> Result<(), Error> {
    let mut len = data.len();
    while len > 0 {
        match conn.try_write(data) {
            Ok(n) => {
                data = &data[n..];
                len -= n;
            }
            Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
                conn.writable().await?;
                continue;
            }
            Err(e) => return Err(e),
        }
    }
    Ok(())
}