#[derive(Clone, Copy, Debug)]
#[repr(transparent)]
pub struct IoVec {
    raw: libc::iovec,
}

impl IoVec {
    #[must_use]
    pub const fn empty() -> Self {
        Self {
            raw: libc::iovec {
                iov_base: std::ptr::null_mut(),
                iov_len: 0,
            },
        }
    }

    #[must_use]
    pub fn from_slice(buf: &[u8], off: usize) -> Self {
        let start = off.min(buf.len());
        let tail = &buf[start..];
        Self {
            raw: libc::iovec {
                iov_base: tail.as_ptr() as *mut libc::c_void,
                iov_len: tail.len(),
            },
        }
    }

    #[inline(always)]
    #[must_use]
    pub fn raw(ptr: *const u8, len: usize) -> libc::iovec {
        libc::iovec {
            iov_base: ptr as *mut libc::c_void,
            iov_len: len,
        }
    }

    #[must_use]
    pub fn from_mut_slice(buf: &mut [u8]) -> Self {
        Self {
            raw: libc::iovec {
                iov_base: buf.as_mut_ptr() as *mut libc::c_void,
                iov_len: buf.len(),
            },
        }
    }

    pub fn set_len(&mut self, len: usize) {
        self.raw.iov_len = len;
    }

    pub fn len(&self) -> usize {
        self.raw.iov_len
    }

    pub fn is_empty(&self) -> bool {
        self.raw.iov_len == 0
    }

    pub fn as_ptr(&self) -> *const u8 {
        self.raw.iov_base.cast()
    }

    #[inline(always)]
    pub fn as_libc(&self) -> libc::iovec {
        self.raw
    }

    pub fn advance(&mut self, n: usize) {
        let step = n.min(self.raw.iov_len);
        self.raw.iov_base = unsafe { (self.raw.iov_base as *mut u8).add(step) }.cast();
        self.raw.iov_len -= step;
    }
}
