use crate::error::{Error, Result};
use crate::sys;
use std::io;
use std::net::SocketAddr;
use std::os::raw::{c_short, c_void};
pub type Fd = sys::llam_fd_t;
pub type Handle = sys::llam_handle_t;
pub const READABLE: i16 = 0x0001;
pub const WRITABLE: i16 = 0x0004;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct PollResult {
pub ready_count: i32,
pub revents: i16,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct AcceptedFd {
pub fd: Fd,
pub addr: Option<SocketAddr>,
}
pub fn read(fd: Fd, buf: &mut [u8]) -> io::Result<usize> {
let n = unsafe { sys::llam_read(fd, buf.as_mut_ptr() as *mut c_void, buf.len()) };
if n < 0 {
Err(Error::last().into())
} else {
Ok(n as usize)
}
}
pub fn read_handle(handle: Handle, buf: &mut [u8]) -> io::Result<usize> {
let n = unsafe { sys::llam_read_handle(handle, buf.as_mut_ptr() as *mut c_void, buf.len()) };
if n < 0 {
Err(Error::last().into())
} else {
Ok(n as usize)
}
}
pub fn read_when_ready(fd: Fd, buf: &mut [u8], timeout_ms: i32) -> io::Result<usize> {
let n = unsafe {
sys::llam_read_when_ready(fd, buf.as_mut_ptr() as *mut c_void, buf.len(), timeout_ms)
};
if n < 0 {
Err(Error::last().into())
} else {
Ok(n as usize)
}
}
pub fn write(fd: Fd, buf: &[u8]) -> io::Result<usize> {
let n = unsafe { sys::llam_write(fd, buf.as_ptr() as *const c_void, buf.len()) };
if n < 0 {
Err(Error::last().into())
} else {
Ok(n as usize)
}
}
pub fn write_handle(handle: Handle, buf: &[u8]) -> io::Result<usize> {
let n = unsafe { sys::llam_write_handle(handle, buf.as_ptr() as *const c_void, buf.len()) };
if n < 0 {
Err(Error::last().into())
} else {
Ok(n as usize)
}
}
pub fn poll_fd(fd: Fd, events: i16, timeout_ms: i32) -> Result<i16> {
poll(fd, events, timeout_ms).map(|result| result.revents)
}
pub fn poll(fd: Fd, events: i16, timeout_ms: i32) -> Result<PollResult> {
let mut revents: c_short = 0;
let rc = unsafe { sys::llam_poll_fd(fd, events as c_short, timeout_ms, &mut revents) };
if rc >= 0 {
Ok(PollResult {
ready_count: rc,
revents: revents as i16,
})
} else {
Err(Error::last())
}
}
pub fn poll_handle(handle: Handle, events: i16, timeout_ms: i32) -> Result<PollResult> {
let mut revents: c_short = 0;
let rc = unsafe { sys::llam_poll_handle(handle, events as c_short, timeout_ms, &mut revents) };
if rc >= 0 {
Ok(PollResult {
ready_count: rc,
revents: revents as i16,
})
} else {
Err(Error::last())
}
}
pub fn accept(fd: Fd) -> io::Result<Fd> {
let accepted = unsafe { sys::llam_accept(fd, std::ptr::null_mut(), std::ptr::null_mut()) };
if sys::fd_is_invalid(accepted) {
Err(Error::last().into())
} else {
Ok(accepted)
}
}
pub fn accept_with_addr(fd: Fd) -> io::Result<AcceptedFd> {
let (accepted, addr) = unsafe {
socket2::SockAddr::try_init(|storage, len| {
let mut llam_len = *len as sys::socklen_t;
let accepted = sys::llam_accept(
fd,
storage.cast::<libc::sockaddr>(),
&mut llam_len as *mut sys::socklen_t,
);
*len = llam_len as _;
if sys::fd_is_invalid(accepted) {
Err(Error::last().into())
} else {
Ok(accepted)
}
})
}?;
Ok(AcceptedFd {
fd: accepted,
addr: addr.as_socket(),
})
}
pub unsafe fn connect_raw(
fd: Fd,
addr: *const libc::sockaddr,
addrlen: sys::socklen_t,
) -> io::Result<()> {
let rc = sys::llam_connect(fd, addr, addrlen);
if rc == 0 {
Ok(())
} else {
Err(Error::last().into())
}
}
pub struct OwnedBuf {
raw: *mut sys::llam_io_buffer_t,
}
unsafe impl Send for OwnedBuf {}
impl OwnedBuf {
pub fn as_slice(&self) -> &[u8] {
if self.raw.is_null() {
return &[];
}
unsafe {
std::slice::from_raw_parts(
sys::llam_io_buffer_data(self.raw) as *const u8,
sys::llam_io_buffer_size(self.raw),
)
}
}
pub fn capacity(&self) -> usize {
if self.raw.is_null() {
0
} else {
unsafe { sys::llam_io_buffer_capacity(self.raw) }
}
}
}
impl Drop for OwnedBuf {
fn drop(&mut self) {
if !self.raw.is_null() {
unsafe { sys::llam_io_buffer_release(self.raw) };
self.raw = std::ptr::null_mut();
}
}
}
pub fn read_owned(fd: Fd, max_count: usize) -> io::Result<Option<OwnedBuf>> {
let mut raw = std::ptr::null_mut();
let n = unsafe { sys::llam_read_owned(fd, max_count, &mut raw) };
if n < 0 {
Err(Error::last().into())
} else if raw.is_null() {
Ok(None)
} else {
Ok(Some(OwnedBuf { raw }))
}
}
pub fn recv_owned(fd: Fd, max_count: usize, flags: i32) -> io::Result<Option<OwnedBuf>> {
let mut raw = std::ptr::null_mut();
let n = unsafe { sys::llam_recv_owned(fd, max_count, flags, &mut raw) };
if n < 0 {
Err(Error::last().into())
} else if raw.is_null() {
Ok(None)
} else {
Ok(Some(OwnedBuf { raw }))
}
}