dope-uring 0.26.0

Owned io_uring backend for dope
Documentation
use std::{mem, ptr};

use dope_sys::io::{reactor::complete, request, socket};
use o3::base::marker::ThreadBound;

use crate::reactor::{
    op::{self, buffers, messages, sockets},
    ring,
    sq::{self, Flags},
};

#[derive(Clone, Debug)]
#[repr(C, align(8))]
pub struct Entry([u8; 64], ThreadBound);

pub(crate) struct Fields<'a>(&'a mut Entry);

impl Entry {
    pub(crate) const NOP: op::Code = op::Code::new(ring::ffi::NOP);

    pub(crate) fn new(opcode: op::Code, fd: sq::Descriptor) -> Self {
        let (raw, fixed) = fd.encode();
        let mut entry = Self([0; 64], ThreadBound::NEW);
        opcode.write(&mut entry.0[0]);
        entry.0[4..8].copy_from_slice(&raw.to_ne_bytes());
        if fixed {
            entry.0[1] = Flags::FIXED_FILE.raw();
        }
        entry
    }

    pub(crate) fn fields(&mut self) -> Fields<'_> {
        Fields(self)
    }

    pub(crate) fn flags(mut self, flags: Flags) -> Self {
        self.0[1] |= flags.raw();
        self
    }

    pub(crate) fn user_data<T: complete::raw::Token>(self, token: T) -> sq::Owned<T> {
        let mut entry = self;
        entry.fields().token(token);
        sq::Owned::new(entry)
    }

    pub(crate) fn bind<'a, T: complete::raw::Token>(mut self, token: T) -> sq::Submit<'a, T> {
        self.fields().token(token);
        sq::Submit::new(self)
    }
}

impl request::Lower for Entry {
    type Target = sq::Fixed;
    type Outbound = sq::Fixed;
    type Domain = socket::Domain;
    type Datagram = sq::Fixed;
    type Borrowed<'a> = sq::Borrowed<'a>;

    fn socket(slot: Self::Outbound, domain: Self::Domain) -> Self {
        let mut entry = Self::new(sockets::CREATE, sq::Descriptor::File(domain.raw()));
        let mut fields = entry.fields();
        fields.offset(libc::SOCK_STREAM as u64);
        fields.index(slot.encode());
        entry
    }

    fn accept_multi(listener: Self::Target) -> Self {
        use crate::reactor::ring::ffi;

        let mut entry = sockets::accept(listener);
        entry.fields().priority(ffi::ACCEPT_MULTISHOT);
        entry
    }

    fn recv<const GROUP: u16>(slot: Self::Target) -> Self {
        use crate::reactor::ring::ffi;

        let mut entry = Self::new(buffers::RECEIVE, sq::Descriptor::Fixed(slot))
            .flags(sq::Flags::BUFFER_SELECT);
        let mut fields = entry.fields();
        fields.priority(ffi::RECEIVE_MULTISHOT);
        fields.group(GROUP);
        entry
    }

    fn recv_msg<const GROUP: u16>(datagram: Self::Datagram) -> Self {
        use crate::reactor::ring::ffi;

        let mut entry = Self::new(messages::RECEIVE, sq::Descriptor::Fixed(datagram))
            .flags(sq::Flags::BUFFER_SELECT);
        let mut fields = entry.fields();
        fields.address(ptr::from_ref(op::RECEIVE_HEADER) as u64);
        fields.length(1);
        fields.group(GROUP);
        fields.priority(ffi::RECEIVE_MULTISHOT);
        entry
    }

    fn shutdown(slot: Self::Target) -> Self {
        sockets::shutdown(slot, dope_sys::io::socket::How::WRITE)
    }
}

impl Fields<'_> {
    pub(crate) fn token<T: complete::raw::Token>(&mut self, token: T) {
        self.write_u64(32, sq::raw::Word::encode(token).get());
    }

    pub(crate) fn offset(&mut self, value: u64) {
        self.write_u64(8, value);
    }

    pub(crate) fn address(&mut self, value: u64) {
        self.write_u64(16, value);
    }

    pub(crate) fn length(&mut self, value: u32) {
        self.write_u32(24, value);
    }

    pub(crate) fn options(&mut self, value: u32) {
        self.write_u32(28, value);
    }

    pub(crate) fn priority(&mut self, value: u16) {
        self.write_u16(2, value);
    }

    pub(crate) fn group(&mut self, value: u16) {
        self.write_u16(40, value);
    }

    pub(crate) fn index(&mut self, value: u32) {
        self.write_u32(44, value);
    }

    pub(crate) fn address3(&mut self, value: u64) {
        self.write_u64(48, value);
    }

    pub(crate) fn command(&mut self, value: u32) {
        self.write_u32(8, value);
    }

    fn write_u16(&mut self, offset: usize, value: u16) {
        self.0.0[offset..offset + 2].copy_from_slice(&value.to_ne_bytes());
    }

    fn write_u32(&mut self, offset: usize, value: u32) {
        self.0.0[offset..offset + 4].copy_from_slice(&value.to_ne_bytes());
    }

    fn write_u64(&mut self, offset: usize, value: u64) {
        self.0.0[offset..offset + 8].copy_from_slice(&value.to_ne_bytes());
    }
}

const _: () = {
    assert!(mem::size_of::<Entry>() == 64);
    assert!(mem::align_of::<Entry>() == 8);
};