use std::io;
use std::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle, OwnedHandle};
use windows_sys::Win32::Foundation::HANDLE;
use windows_sys::Win32::System::IO::{GetOverlappedResult, OVERLAPPED};
use crate::{Operation, OperationState, UnassociatedEndpoint};
#[cfg(test)]
mod tests;
#[derive(Debug)]
pub struct BlockingEndpoint {
handle: OwnedHandle,
}
impl BlockingEndpoint {
pub fn new(endpoint: UnassociatedEndpoint) -> Result<Self, TryFromEndpointError> {
if endpoint.notification_modes().skip_set_event_on_handle {
return Err(TryFromEndpointError { endpoint });
}
Ok(Self {
handle: endpoint.into_handle(),
})
}
#[must_use]
pub fn handle(&self) -> BorrowedHandle<'_> {
self.handle.as_handle()
}
pub unsafe fn run<P, F>(&self, operation: &mut Operation<P>, issue: F) -> io::Result<usize>
where
F: FnOnce(BorrowedHandle<'_>, *mut OVERLAPPED) -> io::Result<()>,
{
operation.set_state(OperationState::Submitted);
let overlapped = operation.overlapped_ptr();
issue(self.handle(), overlapped)?;
operation.set_state(OperationState::Pending);
let mut transferred: u32 = 0;
let ok = unsafe { GetOverlappedResult(self.raw_handle(), overlapped, &mut transferred, 1) };
if ok == 0 {
return Err(io::Error::last_os_error());
}
operation.set_state(OperationState::Completed);
Ok(transferred as usize)
}
fn raw_handle(&self) -> HANDLE {
self.handle.as_raw_handle()
}
}
#[derive(Debug)]
pub struct TryFromEndpointError {
endpoint: UnassociatedEndpoint,
}
impl TryFromEndpointError {
#[must_use]
pub fn into_endpoint(self) -> UnassociatedEndpoint {
self.endpoint
}
}
impl std::fmt::Display for TryFromEndpointError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"cannot construct a BlockingEndpoint from an endpoint with \
skip_set_event_on_handle set: GetOverlappedResult's wait relies \
on exactly the notification that mode suppresses"
)
}
}
impl std::error::Error for TryFromEndpointError {}
impl From<TryFromEndpointError> for io::Error {
fn from(error: TryFromEndpointError) -> Self {
io::Error::new(io::ErrorKind::InvalidInput, error)
}
}