interprocess_docfix/os/windows/named_pipe/
enums.rs

1use super::super::imports::*;
2use std::{convert::TryFrom, mem};
3
4/// The direction of a named pipe connection, designating who can read data and who can write 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`] always means client → server, for example.
5///
6/// [`ClientToServer`]: enum.PipeDirection.html#variant.ClientToServer " "
7// I had to type out both the link to the page and the name of the variant since the link can be clicked from module-level documentation so please don't touch it.
8#[repr(u32)]
9// We depend on the fact that DWORD always maps to u32, which, thankfully, will always stay true
10// since the public WinAPI is supposed to be ABI-compatible. Just keep in mind that the
11// #[repr(u32)] means that we can transmute this enumeration to the Windows DWORD type.
12#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
13pub enum PipeDirection {
14    /// Represents a server ← client data flow: clients write data, the server reads it.
15    ClientToServer = PIPE_ACCESS_INBOUND,
16    /// Represents a server → client data flow: the server writes data, clients read it.
17    ServerToClient = PIPE_ACCESS_OUTBOUND,
18    /// Represents a server ⇄ client data flow: the server can write data which then is read by the client, while the client writes data which is read by the server.
19    Duplex = PIPE_ACCESS_DUPLEX,
20}
21impl PipeDirection {
22    /// Returns the role which the pipe client will have in this direction setting.
23    ///
24    /// # Usage
25    /// ```
26    /// # #[cfg(windows)] {
27    /// # use interprocess::os::windows::named_pipe::{PipeDirection, PipeStreamRole};
28    /// assert_eq!(
29    ///     PipeDirection::ClientToServer.client_role(),
30    ///     PipeStreamRole::Writer,
31    /// );
32    /// assert_eq!(
33    ///     PipeDirection::ServerToClient.client_role(),
34    ///     PipeStreamRole::Reader,
35    /// );
36    /// assert_eq!(
37    ///     PipeDirection::Duplex.client_role(),
38    ///     PipeStreamRole::ReaderAndWriter,
39    /// );
40    /// # }
41    /// ```
42    pub const fn client_role(self) -> PipeStreamRole {
43        match self {
44            Self::ClientToServer => PipeStreamRole::Writer,
45            Self::ServerToClient => PipeStreamRole::Reader,
46            Self::Duplex => PipeStreamRole::ReaderAndWriter,
47        }
48    }
49    /// Returns the role which the pipe server will have in this direction setting.
50    ///
51    /// # Usage
52    /// ```
53    /// # #[cfg(windows)] {
54    /// # use interprocess::os::windows::named_pipe::{PipeDirection, PipeStreamRole};
55    /// assert_eq!(
56    ///     PipeDirection::ClientToServer.server_role(),
57    ///     PipeStreamRole::Reader,
58    /// );
59    /// assert_eq!(
60    ///     PipeDirection::ServerToClient.server_role(),
61    ///     PipeStreamRole::Writer,
62    /// );
63    /// assert_eq!(
64    ///     PipeDirection::Duplex.server_role(),
65    ///     PipeStreamRole::ReaderAndWriter,
66    /// );
67    /// # }
68    /// ```
69    pub const fn server_role(self) -> PipeStreamRole {
70        match self {
71            Self::ClientToServer => PipeStreamRole::Reader,
72            Self::ServerToClient => PipeStreamRole::Writer,
73            Self::Duplex => PipeStreamRole::ReaderAndWriter,
74        }
75    }
76}
77impl TryFrom<DWORD> for PipeDirection {
78    type Error = ();
79    /// Converts a Windows constant to a `PipeDirection` if it's in range.
80    ///
81    /// # Errors
82    /// Returns `Err` if the value is not a valid pipe direction constant.
83    fn try_from(op: DWORD) -> Result<Self, ()> {
84        assert!((1..=3).contains(&op));
85        // See the comment block above for why this is safe.
86        unsafe { mem::transmute(op) }
87    }
88}
89impl From<PipeDirection> for DWORD {
90    fn from(op: PipeDirection) -> Self {
91        unsafe { mem::transmute(op) }
92    }
93}
94/// Describes the role of a named pipe stream. In constrast to [`PipeDirection`], the meaning of values here is relative – for example, [`Reader`] means [`ServerToClient`] if you're creating a server and [`ClientToServer`] if you're creating a client.
95///
96/// This enumeration is also not layout-compatible with the `PIPE_ACCESS_*` constants, in contrast to [`PipeDirection`].
97///
98/// [`PipeDirection`]: enum.PipeDirection.html " "
99/// [`Reader`]: #variant.Reader " "
100/// [`ServerToClient`]: enum.PipeDirection.html#variant.ServerToClient " "
101/// [`ClientToServer`]: enum.PipeDirection.html#variant.ClientToServer " "
102#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
103#[repr(u32)]
104pub enum PipeStreamRole {
105    /// The stream only reads data.
106    Reader,
107    /// The stream only writes data.
108    Writer,
109    /// The stream both reads and writes data.
110    ReaderAndWriter,
111}
112impl PipeStreamRole {
113    /// Returns the data flow direction of the data stream, assuming that the value describes the role of the server.
114    ///
115    /// # Usage
116    /// ```
117    /// # #[cfg(windows)] {
118    /// # use interprocess::os::windows::named_pipe::{PipeDirection, PipeStreamRole};
119    /// assert_eq!(
120    ///     PipeStreamRole::Reader.direction_as_server(),
121    ///     PipeDirection::ClientToServer,
122    /// );
123    /// assert_eq!(
124    ///     PipeStreamRole::Writer.direction_as_server(),
125    ///     PipeDirection::ServerToClient,
126    /// );
127    /// assert_eq!(
128    ///     PipeStreamRole::ReaderAndWriter.direction_as_server(),
129    ///     PipeDirection::Duplex,
130    /// );
131    /// # }
132    /// ```
133    pub const fn direction_as_server(self) -> PipeDirection {
134        match self {
135            Self::Reader => PipeDirection::ClientToServer,
136            Self::Writer => PipeDirection::ServerToClient,
137            Self::ReaderAndWriter => PipeDirection::Duplex,
138        }
139    }
140    /// Returns the data flow direction of the data stream, assuming that the value describes the role of the client.
141    ///
142    /// # Usage
143    /// ```
144    /// # #[cfg(windows)] {
145    /// # use interprocess::os::windows::named_pipe::{PipeDirection, PipeStreamRole};
146    /// assert_eq!(
147    ///     PipeStreamRole::Reader.direction_as_client(),
148    ///     PipeDirection::ServerToClient,
149    /// );
150    /// assert_eq!(
151    ///     PipeStreamRole::Writer.direction_as_client(),
152    ///     PipeDirection::ClientToServer,
153    /// );
154    /// assert_eq!(
155    ///     PipeStreamRole::ReaderAndWriter.direction_as_client(),
156    ///     PipeDirection::Duplex,
157    /// );
158    /// # }
159    /// ```
160    pub const fn direction_as_client(self) -> PipeDirection {
161        match self {
162            Self::Reader => PipeDirection::ServerToClient,
163            Self::Writer => PipeDirection::ClientToServer,
164            Self::ReaderAndWriter => PipeDirection::Duplex,
165        }
166    }
167}
168
169/// Specifies the mode for a pipe stream.
170#[repr(u32)]
171#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
172pub enum PipeMode {
173    /// Designates that the pipe stream works in byte stream mode, erasing the boundaries of separate messages.
174    Bytes = PIPE_TYPE_BYTE,
175    /// Designates that the pipe stream works in message stream mode, preserving the boundaries of separate messages yet still allowing to read them in byte stream mode.
176    Messages = PIPE_TYPE_MESSAGE,
177}
178impl PipeMode {
179    /// Converts the value into a raw `DWORD`-typed constant, either `PIPE_TYPE_BYTE` or `PIPE_TYPE_MESSAGE` depending on the value.
180    pub const fn to_pipe_type(self) -> DWORD {
181        self as _
182    }
183    /// Converts the value into a raw `DWORD`-typed constant, either `PIPE_READMODE_BYTE` or `PIPE_READMODE_MESSAGE` depending on the value.
184    pub const fn to_readmode(self) -> DWORD {
185        match self {
186            Self::Bytes => PIPE_READMODE_BYTE,
187            Self::Messages => PIPE_READMODE_MESSAGE,
188        }
189    }
190}
191impl TryFrom<DWORD> for PipeMode {
192    type Error = ();
193    /// Converts a Windows constant to a `PipeMode` if it's in range. Both `PIPE_TYPE_*` and `PIPE_READMODE_*` are supported.
194    ///
195    /// # Errors
196    /// Returns `Err` if the value is not a valid pipe stream mode constant.
197    fn try_from(op: DWORD) -> Result<Self, ()> {
198        // It's nicer to only match than to check and transmute
199        #[allow(unreachable_patterns)] // PIPE_READMODE_BYTE and PIPE_TYPE_BYTE are equal
200        match op {
201            PIPE_TYPE_BYTE | PIPE_READMODE_BYTE => Ok(Self::Bytes),
202            PIPE_READMODE_MESSAGE | PIPE_TYPE_MESSAGE => Ok(Self::Messages),
203            _ => Err(()),
204        }
205    }
206}