use super::imports::*;
use super::FileHandleOps;
use crate::unnamed_pipe::{UnnamedPipeReader as PubReader, UnnamedPipeWriter as PubWriter};
use std::{
fmt::{self, Debug, Formatter},
io::{self, Read, Write},
mem::{size_of, zeroed, ManuallyDrop},
num::NonZeroUsize,
ptr,
};
#[non_exhaustive]
#[derive(Copy, Clone, Debug)]
pub struct UnnamedPipeCreationOptions {
pub inheritable: bool,
pub security_descriptor: LPVOID,
pub buffer_size_hint: Option<NonZeroUsize>,
}
impl UnnamedPipeCreationOptions {
pub const fn new() -> Self {
Self {
inheritable: true,
security_descriptor: ptr::null_mut(),
buffer_size_hint: None,
}
}
#[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
}
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
}
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 = unsafe {
CreatePipe(
&mut reader as *mut _,
&mut writer as *mut _,
&mut self.extract_security_attributes() as *mut _,
hint_raw,
)
} != 0;
if success {
let (writer, reader) = unsafe {
let writer = PubWriter {
inner: UnnamedPipeWriter::from_raw_handle(writer),
};
let reader = PubReader {
inner: UnnamedPipeReader::from_raw_handle(reader),
};
(writer, reader)
};
Ok((writer, reader))
} else {
Err(io::Error::last_os_error())
}
}
}
impl Default for UnnamedPipeCreationOptions {
fn default() -> Self {
Self::new()
}
}
unsafe impl Send for UnnamedPipeCreationOptions {}
unsafe impl Sync for UnnamedPipeCreationOptions {}
pub(crate) fn pipe() -> io::Result<(PubWriter, PubReader)> {
unsafe { UnnamedPipeCreationOptions::default().build() }
}
pub(crate) struct UnnamedPipeReader(FileHandleOps);
impl Read for UnnamedPipeReader {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
}
#[cfg(windows)]
impl AsRawHandle for UnnamedPipeReader {
fn as_raw_handle(&self) -> HANDLE {
self.0.as_raw_handle()
}
}
#[cfg(windows)]
impl IntoRawHandle for UnnamedPipeReader {
fn into_raw_handle(self) -> HANDLE {
let self_ = ManuallyDrop::new(self);
self_.as_raw_handle()
}
}
#[cfg(windows)]
impl FromRawHandle for UnnamedPipeReader {
unsafe fn from_raw_handle(handle: HANDLE) -> Self {
let fho = unsafe {
FileHandleOps::from_raw_handle(handle)
};
Self(fho)
}
}
impl Debug for UnnamedPipeReader {
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 {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.0.flush()
}
}
#[cfg(windows)]
impl AsRawHandle for UnnamedPipeWriter {
fn as_raw_handle(&self) -> HANDLE {
self.0.as_raw_handle()
}
}
#[cfg(windows)]
impl IntoRawHandle for UnnamedPipeWriter {
fn into_raw_handle(self) -> HANDLE {
let self_ = ManuallyDrop::new(self);
self_.as_raw_handle()
}
}
#[cfg(windows)]
impl FromRawHandle for UnnamedPipeWriter {
unsafe fn from_raw_handle(handle: HANDLE) -> Self {
Self(FileHandleOps(handle))
}
}
impl Debug for UnnamedPipeWriter {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("UnnamedPipeWriter")
.field("handle", &self.as_raw_handle())
.finish()
}
}