use std::{
mem::{self, zeroed, size_of},
io::{self, Read, Write},
num::NonZeroUsize,
fmt::{self, Formatter, Debug},
};
#[cfg(windows)]
use std::os::windows::io::{FromRawHandle, AsRawHandle, IntoRawHandle};
#[cfg(windows)]
use winapi::{
shared::{
ntdef::{HANDLE, NULL},
minwindef::LPVOID,
},
um::{
minwinbase::SECURITY_ATTRIBUTES,
handleapi::INVALID_HANDLE_VALUE,
namedpipeapi::CreatePipe,
},
};
#[cfg(not(windows))]
#[doc(hidden)]
#[allow(non_camel_case_types)]
pub struct SECURITY_ATTRIBUTES {}
#[cfg(not(windows))]
#[doc(hidden)]
pub type LPVOID = *mut ();
#[cfg(not(windows))]
#[doc(hidden)]
pub const NULL: LPVOID = 0 as _;
use crate::{
unnamed_pipe::{
UnnamedPipeReader as PubReader,
UnnamedPipeWriter as PubWriter,
},
};
use super::FileHandleOps;
#[non_exhaustive]
#[derive(Copy, Clone, Debug)]
pub struct UnnamedPipeCreationOptions {
pub inheritable: bool,
pub security_descriptor: LPVOID,
pub buffer_size_hint: Option<NonZeroUsize>,
}
impl UnnamedPipeCreationOptions {
#[inline(always)]
pub const fn new() -> Self {
Self {
inheritable: true,
security_descriptor: NULL,
buffer_size_hint: None,
}
}
#[inline]
#[must_use = "this is not an in-place operation"]
pub fn inheritable(mut self, inheritable: bool) -> Self {
self.inheritable = inheritable;
self
}
#[must_use = "this is not an in-place operation"]
pub fn security_descriptor(mut self, security_descriptor: LPVOID) -> Self {
self.security_descriptor = security_descriptor;
self
}
#[must_use = "this is not an in-place operation"]
pub fn buffer_size_hint(mut self, buffer_size_hint: Option<NonZeroUsize>) -> Self {
self.buffer_size_hint = buffer_size_hint;
self
}
#[inline]
pub fn extract_security_attributes(self) -> SECURITY_ATTRIBUTES {
let mut security_attributes = unsafe {zeroed::<SECURITY_ATTRIBUTES>()};
security_attributes.nLength = size_of::<SECURITY_ATTRIBUTES>() as u32;
security_attributes.lpSecurityDescriptor = self.security_descriptor;
security_attributes.bInheritHandle = self.inheritable as i32;
security_attributes
}
#[inline]
pub unsafe fn build(self) -> io::Result<(PubWriter, PubReader)> {
let hint_raw = match self.buffer_size_hint {
Some(num) => num.get(),
None => 0,
} as u32;
let [mut writer, mut reader] = [INVALID_HANDLE_VALUE; 2];
let success = CreatePipe(
&mut reader as *mut _,
&mut writer as *mut _,
&mut self.extract_security_attributes() as *mut _,
hint_raw,
) != 0;
if success {
Ok((
PubWriter {
inner: UnnamedPipeWriter::from_raw_handle(writer),
},
PubReader {
inner: UnnamedPipeReader::from_raw_handle(reader),
},
))
} else {
Err(io::Error::last_os_error())
}
}
}
impl Default for UnnamedPipeCreationOptions {
#[inline(always)]
fn default() -> Self {
Self::new()
}
}
unsafe impl Send for UnnamedPipeCreationOptions {}
#[inline(always)]
pub(crate) fn pipe() -> io::Result<(PubWriter, PubReader)> {
unsafe {UnnamedPipeCreationOptions::default().build()}
}
pub(crate) struct UnnamedPipeReader (FileHandleOps);
impl Read for UnnamedPipeReader {
#[inline(always)]
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
}
#[cfg(windows)]
impl AsRawHandle for UnnamedPipeReader {
#[inline(always)]
fn as_raw_handle(&self) -> HANDLE {
self.0.as_raw_handle()
}
}
#[cfg(windows)]
impl IntoRawHandle for UnnamedPipeReader {
#[inline]
fn into_raw_handle(self) -> HANDLE {
let handle = self.as_raw_handle();
mem::forget(self);
handle
}
}
#[cfg(windows)]
impl FromRawHandle for UnnamedPipeReader {
#[inline(always)]
unsafe fn from_raw_handle(handle: HANDLE) -> Self {
Self(FileHandleOps::from_raw_handle(handle))
}
}
impl Debug for UnnamedPipeReader {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("UnnamedPipeReader")
.field("handle", &self.as_raw_handle())
.finish()
}
}
pub(crate) struct UnnamedPipeWriter (FileHandleOps);
impl Write for UnnamedPipeWriter {
#[inline(always)]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)
}
#[inline(always)]
fn flush(&mut self) -> io::Result<()> {
self.0.flush()
}
}
#[cfg(windows)]
impl AsRawHandle for UnnamedPipeWriter {
#[inline(always)]
fn as_raw_handle(&self) -> HANDLE {
self.0.as_raw_handle()
}
}
#[cfg(windows)]
impl IntoRawHandle for UnnamedPipeWriter {
#[inline]
fn into_raw_handle(self) -> HANDLE {
let handle = self.as_raw_handle();
mem::forget(self);
handle
}
}
#[cfg(windows)]
impl FromRawHandle for UnnamedPipeWriter {
#[inline(always)]
unsafe fn from_raw_handle(handle: HANDLE) -> Self {
Self(FileHandleOps(handle))
}
}
impl Debug for UnnamedPipeWriter {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("UnnamedPipeWriter")
.field("handle", &self.as_raw_handle())
.finish()
}
}