hirun 0.1.13

A concurrent framework for asynchronous programming based on event-driven, non-blocking I/O mechanism
Documentation
use super::{const_buf, mut_buf, Fd};
use crate::runtime::wait_event;
use crate::{
    event::{POLLET, POLLIN, POLLOUT},
    Error, Result,
};
use core::ops::Deref;

/// 使用约束:
/// 1. 同一个Fd在一个工作线程只能有一个AioFd实例, 如果多个实例并发请求异步io事件,只会响应其中一个
///    这要求异步读写都只能在一个异步任务中完成.
/// 2. 如果必须将异步读写分离或者需要多个读写操作,需要利用Fd::clone复制Fd来实现.
/// 3. 或者Fd满足'static生命周期要求,可以利用hash调度策略,在不同工作线程中分别实现读写
#[repr(C)]
pub struct AioFd<'a> {
    fd: &'a Fd,
}

unsafe impl Send for AioFd<'_> {}

impl Deref for AioFd<'_> {
    type Target = Fd;
    fn deref(&self) -> &Self::Target {
        self.fd
    }
}

impl<'a> AioFd<'a> {
    pub fn new(fd: &'a Fd) -> Self {
        Self { fd }
    }
}

impl AioFd<'_> {
    /// 此接口一旦调用,当前异步任务就绑定在当前工作线程中运行.
    pub async fn wait(&mut self, events: u32) -> Result<()> {
        // 底层有两种实现,FdWait支持POLLET,FdWaitOnce是否使用POLLET没有影响
        wait_event(self.fd(), events | POLLET).await.map(|_| ())
    }

    /// 读取的数据填满buf后才返回,除非对端断链,此时返回Ok(size)将小于buf的长度.
    pub async fn read_all(&mut self, mut buf: &mut [u8]) -> Result<usize> {
        let mut recved = 0;
        loop {
            let ret = unsafe { libc::read(self.fd.fd, mut_buf(buf), buf.len()) };
            // 频繁调用场景,但rust无法指定分支预测功能
            #[allow(clippy::comparison_chain)]
            if ret > 0 {
                let n = ret as usize;
                recved += n;
                if n == buf.len() {
                    return Ok(recved);
                }
                buf = &mut buf[n..];
            } else if ret == 0 {
                return Ok(recved);
            } else {
                let e = Error::last();
                if e.errno == libc::EAGAIN {
                    self.wait(POLLIN).await?;
                } else if e.errno != libc::EINTR {
                    return Err(e);
                }
            }
        }
    }

    /// 将buf的数据全部发送出去后才返回. 也可能因为连接断开导致发送部分数据.
    pub async fn write_all(&mut self, mut buf: &[u8]) -> Result<usize> {
        let mut sended = 0;
        loop {
            let ret = unsafe { libc::write(self.fd.fd, const_buf(buf), buf.len()) };
            if ret >= 0 {
                let n = ret as usize;
                sended += n;
                if n == buf.len() {
                    return Ok(sended);
                }
                buf = &buf[n..];
            } else {
                let e = Error::last();
                if e.errno == libc::EAGAIN {
                    self.wait(POLLOUT).await?;
                } else if e.errno != libc::EINTR {
                    return Err(e);
                }
            }
        }
    }

    /// 将数据全部发送出去后才返回. 也可能因为连接断开,只发送了部分数据.
    pub async fn sendfile_all(&mut self, in_fd: i32, off: usize, count: usize) -> Result<usize> {
        let mut off = off as i64;
        let mut len = count;
        let end = off + count as i64;
        loop {
            let ret = unsafe { libc::sendfile(self.fd.fd, in_fd, &mut off, len) };
            if ret >= 0 {
                if off == end {
                    return Ok(count);
                }
                len -= ret as usize;
            } else {
                let e = Error::last();
                if e.errno == libc::EAGAIN {
                    self.wait(POLLOUT).await?;
                } else if e.errno != libc::EINTR {
                    return Err(e);
                }
            }
        }
    }

    /// 发送至少一个字节的数据就返回.
    pub async fn sendfile(&mut self, in_fd: i32, off: usize, count: usize) -> Result<usize> {
        let mut off = off as i64;
        loop {
            let ret = unsafe { libc::sendfile(self.fd.fd, in_fd, &mut off, count) };
            if ret >= 0 {
                return Ok(ret as usize);
            } else {
                let e = Error::last();
                if e.errno == libc::EAGAIN {
                    self.wait(POLLOUT).await?;
                } else if e.errno != libc::EINTR {
                    return Err(e);
                }
            }
        }
    }

    /// 收到至少一个字节的数据就返回,如果返回Ok(0)说明对端断开连接.
    pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        loop {
            let ret = unsafe { libc::read(self.fd.fd, mut_buf(buf), buf.len()) };
            if ret >= 0 {
                return Ok(ret as usize);
            } else {
                let e = Error::last();
                if e.errno == libc::EAGAIN {
                    self.wait(POLLIN).await?;
                } else if e.errno != libc::EINTR {
                    return Err(e);
                }
            }
        }
    }

    /// 发送至少一个字节的数据就返回.
    pub async fn write(&mut self, buf: &[u8]) -> Result<usize> {
        loop {
            let ret = unsafe { libc::write(self.fd.fd, const_buf(buf), buf.len()) };
            if ret >= 0 {
                return Ok(ret as usize);
            } else {
                let e = Error::last();
                if e.errno == libc::EAGAIN {
                    self.wait(POLLOUT).await?;
                } else if e.errno != libc::EINTR {
                    return Err(e);
                }
            }
        }
    }
}