use std::{future::Future, marker::PhantomData, mem::MaybeUninit};
use crate::{ffi, try_d3xx, util::PhantomLifetime, D3xxError, Device, Result};
pub struct Overlapped<'a> {
handle: ffi::HANDLE,
inner: ffi::_OVERLAPPED,
_lifetime_constraint: PhantomLifetime<'a>,
}
impl<'a> Overlapped<'a> {
#[allow(unused)]
pub(crate) fn new(device: &'a Device) -> Result<Self> {
Self::with_handle(device.handle())
}
pub(crate) fn with_handle(handle: ffi::FT_HANDLE) -> Result<Self> {
let mut overlapped: MaybeUninit<ffi::_OVERLAPPED> = MaybeUninit::uninit();
try_d3xx!(unsafe {
ffi::FT_InitializeOverlapped(handle, std::ptr::addr_of_mut!(overlapped).cast())
})?;
let overlapped = unsafe { overlapped.assume_init() };
Ok(Self {
handle,
inner: overlapped,
_lifetime_constraint: PhantomData,
})
}
#[inline]
#[must_use]
#[allow(unused)]
pub fn inner(&self) -> &ffi::_OVERLAPPED {
&self.inner
}
#[inline]
#[must_use]
pub fn inner_mut(&mut self) -> &mut ffi::_OVERLAPPED {
&mut self.inner
}
fn poll_once(&mut self, wait: bool) -> Result<usize> {
let mut transferred: ffi::ULONG = 0;
try_d3xx!(unsafe {
ffi::FT_GetOverlappedResult(
self.handle,
self.inner_mut(),
std::ptr::addr_of_mut!(transferred),
ffi::BOOL::from(wait),
)
})?;
Ok(transferred as usize)
}
}
impl Future for Overlapped<'_> {
type Output = Result<usize>;
fn poll(
mut self: std::pin::Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Self::Output> {
match self.poll_once(false) {
Ok(transferred) => std::task::Poll::Ready(Ok(transferred)),
Err(D3xxError::IoPending | D3xxError::IoIncomplete) => {
cx.waker().wake_by_ref();
std::task::Poll::Pending
}
Err(e) => std::task::Poll::Ready(Err(e)),
}
}
}
impl Drop for Overlapped<'_> {
fn drop(&mut self) {
unsafe {
ffi::FT_ReleaseOverlapped(self.handle, self.inner_mut() as *mut ffi::_OVERLAPPED);
}
}
}