interprocess 2.2.2

Interprocess communication toolkit
Documentation
use super::PipeModeTag;
use std::mem;
use windows_sys::Win32::{
	Storage::FileSystem::{PIPE_ACCESS_DUPLEX, PIPE_ACCESS_INBOUND, PIPE_ACCESS_OUTBOUND},
	System::Pipes::{
		PIPE_READMODE_BYTE, PIPE_READMODE_MESSAGE, PIPE_TYPE_BYTE, PIPE_TYPE_MESSAGE,
	},
};

/// The direction of a named pipe connection, designating who can receive data and who can send it.
/// This describes the direction of the data flow unambiguously, so that the meaning of the values
/// is the same for the client and server – [`ClientToServer`](PipeDirection::ClientToServer) always
/// means client → server, for example.
#[repr(u32)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum PipeDirection {
	/// Represents server ← client data flow: clients send data, the server receives it.
	ClientToServer = PIPE_ACCESS_INBOUND,
	/// Represents server → client data flow: the server sends data, clients receive it.
	ServerToClient = PIPE_ACCESS_OUTBOUND,
	/// Represents server ⇄ client data flow: the server can send data which is then received by the
	/// client, while the client sends data which is received by the server.
	Duplex = PIPE_ACCESS_DUPLEX,
}
impl PipeDirection {
	/// Returns the role which the pipe client will have in this direction setting.
	///
	/// # Usage
	/// ```
	/// # use interprocess::os::windows::named_pipe::{PipeDirection, PipeStreamRole};
	/// assert_eq!(
	/// 	PipeDirection::ClientToServer.client_role(),
	/// 	PipeStreamRole::Sender,
	/// );
	/// assert_eq!(
	/// 	PipeDirection::ServerToClient.client_role(),
	/// 	PipeStreamRole::Recver,
	/// );
	/// assert_eq!(
	/// 	PipeDirection::Duplex.client_role(),
	/// 	PipeStreamRole::RecverAndSender,
	/// );
	/// ```
	pub const fn client_role(self) -> PipeStreamRole {
		match self {
			Self::ClientToServer => PipeStreamRole::Sender,
			Self::ServerToClient => PipeStreamRole::Recver,
			Self::Duplex => PipeStreamRole::RecverAndSender,
		}
	}
	/// Returns the role which the pipe server will have in this direction setting.
	///
	/// # Usage
	/// ```
	/// # use interprocess::os::windows::named_pipe::{PipeDirection, PipeStreamRole};
	/// assert_eq!(
	/// 	PipeDirection::ClientToServer.server_role(),
	/// 	PipeStreamRole::Recver,
	/// );
	/// assert_eq!(
	/// 	PipeDirection::ServerToClient.server_role(),
	/// 	PipeStreamRole::Sender,
	/// );
	/// assert_eq!(
	/// 	PipeDirection::Duplex.server_role(),
	/// 	PipeStreamRole::RecverAndSender,
	/// );
	/// ```
	pub const fn server_role(self) -> PipeStreamRole {
		match self {
			Self::ClientToServer => PipeStreamRole::Recver,
			Self::ServerToClient => PipeStreamRole::Sender,
			Self::Duplex => PipeStreamRole::RecverAndSender,
		}
	}
}
impl TryFrom<u32> for PipeDirection {
	type Error = ();
	/// Converts a Windows constant to a `PipeDirection` if it's in range.
	///
	/// # Errors
	/// Returns `Err` if the value is not a valid pipe direction constant.
	fn try_from(op: u32) -> Result<Self, ()> {
		Ok(match op {
			PIPE_ACCESS_INBOUND => Self::ClientToServer,
			PIPE_ACCESS_OUTBOUND => Self::ServerToClient,
			PIPE_ACCESS_DUPLEX => Self::Duplex,
			_ => return Err(()),
		})
	}
}
impl From<PipeDirection> for u32 {
	fn from(op: PipeDirection) -> Self {
		unsafe { mem::transmute(op) }
	}
}
/// Describes the role of a named pipe stream. In constrast to [`PipeDirection`], the meaning of
/// values here is relative – for example, [`Recver`](PipeStreamRole::Recver) means
/// [`ServerToClient`](PipeDirection::ServerToClient) if you're creating a server and
/// [`ClientToServer`](PipeDirection::ClientToServer) if you're creating a client.
///
/// This enumeration is not layout-compatible with the `PIPE_ACCESS_*` constants, in contrast
/// to [`PipeDirection`].
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum PipeStreamRole {
	/// The stream only receives data.
	Recver,
	/// The stream only sends data.
	Sender,
	/// The stream both receives and sends data.
	RecverAndSender,
}
impl PipeStreamRole {
	/// Returns the data flow direction of the data stream, assuming that the value describes the
	/// role of the server.
	///
	/// # Usage
	/// ```
	/// # use interprocess::os::windows::named_pipe::{PipeDirection, PipeStreamRole};
	/// assert_eq!(
	/// 	PipeStreamRole::Recver.direction_as_server(),
	/// 	PipeDirection::ClientToServer,
	/// );
	/// assert_eq!(
	/// 	PipeStreamRole::Sender.direction_as_server(),
	/// 	PipeDirection::ServerToClient,
	/// );
	/// assert_eq!(
	/// 	PipeStreamRole::RecverAndSender.direction_as_server(),
	/// 	PipeDirection::Duplex,
	/// );
	/// ```
	pub const fn direction_as_server(self) -> PipeDirection {
		match self {
			Self::Recver => PipeDirection::ClientToServer,
			Self::Sender => PipeDirection::ServerToClient,
			Self::RecverAndSender => PipeDirection::Duplex,
		}
	}
	/// Returns the data flow direction of the data stream, assuming that the value describes the
	/// role of the client.
	///
	/// # Usage
	/// ```
	/// # use interprocess::os::windows::named_pipe::{PipeDirection, PipeStreamRole};
	/// assert_eq!(
	/// 	PipeStreamRole::Recver.direction_as_client(),
	/// 	PipeDirection::ServerToClient,
	/// );
	/// assert_eq!(
	/// 	PipeStreamRole::Sender.direction_as_client(),
	/// 	PipeDirection::ClientToServer,
	/// );
	/// assert_eq!(
	/// 	PipeStreamRole::RecverAndSender.direction_as_client(),
	/// 	PipeDirection::Duplex,
	/// );
	/// ```
	pub const fn direction_as_client(self) -> PipeDirection {
		match self {
			Self::Recver => PipeDirection::ServerToClient,
			Self::Sender => PipeDirection::ClientToServer,
			Self::RecverAndSender => PipeDirection::Duplex,
		}
	}

	pub(crate) const fn get_for_rm_sm<Rm: PipeModeTag, Sm: PipeModeTag>() -> Self {
		match (Rm::MODE, Sm::MODE) {
			(Some(..), Some(..)) => Self::RecverAndSender,
			(Some(..), None) => Self::Recver,
			(None, Some(..)) => Self::Sender,
			(None, None) => unimplemented!(),
		}
	}
}

/// Specifies the mode for a pipe stream.
#[repr(u32)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum PipeMode {
	/// Designates that the pipe stream works in byte stream mode, erasing the boundaries of
	/// separate messages.
	Bytes = PIPE_TYPE_BYTE,
	/// Designates that the pipe stream works in message stream mode, preserving the boundaries of
	/// separate messages, though still allowing them to be received via a byte stream named pipe
	/// object.
	Messages = PIPE_TYPE_MESSAGE,
}
impl PipeMode {
	/// Converts the value into a raw `u32`-typed constant, either `PIPE_TYPE_BYTE` or
	/// `PIPE_TYPE_MESSAGE` depending on the value.
	#[inline]
	#[allow(clippy::as_conversions)]
	pub const fn to_pipe_type(self) -> u32 {
		self as _
	}
	/// Converts the value into a raw `u32`-typed constant, either `PIPE_READMODE_BYTE` or
	/// `PIPE_READMODE_MESSAGE` depending on the value.
	pub const fn to_readmode(self) -> u32 {
		match self {
			Self::Bytes => PIPE_READMODE_BYTE,
			Self::Messages => PIPE_READMODE_MESSAGE,
		}
	}
}
impl TryFrom<u32> for PipeMode {
	type Error = ();
	/// Converts a Windows constant to a `PipeMode` if it's in range. Both `PIPE_TYPE_*` and
	/// `PIPE_READMODE_*` are supported.
	///
	/// # Errors
	/// Returns `Err` if the value is not a valid pipe stream mode constant.
	fn try_from(op: u32) -> Result<Self, ()> {
		// It's nicer to only match than to check and transmute
		#[allow(unreachable_patterns)] // PIPE_READMODE_BYTE and PIPE_TYPE_BYTE are equal
		match op {
			PIPE_TYPE_BYTE | PIPE_READMODE_BYTE => Ok(Self::Bytes),
			PIPE_READMODE_MESSAGE | PIPE_TYPE_MESSAGE => Ok(Self::Messages),
			_ => Err(()),
		}
	}
}