use std::future::Future;
use std::io::Result;
use std::mem;
use std::net::SocketAddr;
use std::pin::Pin;
use std::task::{Context, Poll};
use std::time::{Duration, Instant};
use orengine_macros::{poll_for_io_request, poll_for_time_bounded_io_request};
use socket2::SockAddr;
use crate as orengine;
use crate::io::io_request_data::IoRequestData;
use crate::io::sys::{AsRawFd, MessageRecvHeader, RawFd};
use crate::io::worker::{local_worker, IoWorker};
use crate::BUG_MESSAGE;
pub struct RecvFrom<'fut> {
fd: RawFd,
msg_header: MessageRecvHeader<'fut>,
io_request_data: Option<IoRequestData>,
}
impl<'fut> RecvFrom<'fut> {
pub fn new(fd: RawFd, buf_ptr: *mut *mut [u8], addr: &'fut mut SockAddr) -> Self {
Self {
fd,
msg_header: MessageRecvHeader::new(addr, buf_ptr),
io_request_data: None,
}
}
}
impl Future for RecvFrom<'_> {
type Output = Result<usize>;
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let this = unsafe { self.get_unchecked_mut() };
let ret;
poll_for_io_request!((
local_worker().recv_from(this.fd, &mut this.msg_header, unsafe {
this.io_request_data.as_mut().unwrap_unchecked()
}),
ret
));
}
}
#[allow(
clippy::non_send_fields_in_send_ty,
reason = "We guarantee that `RecvFrom` is `Send`."
)]
unsafe impl Send for RecvFrom<'_> {}
pub struct RecvFromWithDeadline<'fut> {
fd: RawFd,
msg_header: MessageRecvHeader<'fut>,
deadline: Instant,
io_request_data: Option<IoRequestData>,
}
impl<'fut> RecvFromWithDeadline<'fut> {
pub fn new(
fd: RawFd,
buf_ptr: *mut *mut [u8],
addr: &'fut mut SockAddr,
deadline: Instant,
) -> Self {
Self {
fd,
msg_header: MessageRecvHeader::new(addr, buf_ptr),
deadline,
io_request_data: None,
}
}
}
impl Future for RecvFromWithDeadline<'_> {
type Output = Result<usize>;
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let this = unsafe { self.get_unchecked_mut() };
let worker = local_worker();
let ret;
poll_for_time_bounded_io_request!((
worker.recv_from_with_deadline(
this.fd,
&mut this.msg_header,
unsafe { this.io_request_data.as_mut().unwrap_unchecked() },
&mut this.deadline
),
ret
));
}
}
#[allow(
clippy::non_send_fields_in_send_ty,
reason = "We guarantee that `RecvFromWithDeadline` is `Send`."
)]
unsafe impl Send for RecvFromWithDeadline<'_> {}
pub trait AsyncRecvFrom: AsRawFd {
#[inline(always)]
async fn recv_from(&mut self, buf: &mut [u8]) -> Result<(usize, SocketAddr)> {
let mut sock_addr = unsafe { mem::zeroed() };
let n = RecvFrom::new(
self.as_raw_fd(),
&mut std::ptr::from_mut::<[u8]>(buf),
&mut sock_addr,
)
.await?;
Ok((n, sock_addr.as_socket().expect(BUG_MESSAGE)))
}
#[inline(always)]
async fn recv_from_with_deadline(
&mut self,
buf: &mut [u8],
deadline: Instant,
) -> Result<(usize, SocketAddr)> {
let mut sock_addr = unsafe { mem::zeroed() };
let n = RecvFromWithDeadline::new(
self.as_raw_fd(),
&mut std::ptr::from_mut::<[u8]>(buf),
&mut sock_addr,
deadline,
)
.await?;
Ok((n, sock_addr.as_socket().expect(BUG_MESSAGE)))
}
#[inline(always)]
async fn recv_from_with_timeout(
&mut self,
buf: &mut [u8],
timeout: Duration,
) -> Result<(usize, SocketAddr)> {
self.recv_from_with_deadline(buf, Instant::now() + timeout)
.await
}
}