std/os/windows/io/mod.rs
1//! Windows-specific extensions to general I/O primitives.
2//!
3//! Just like raw pointers, raw Windows handles and sockets point to resources
4//! with dynamic lifetimes, and they can dangle if they outlive their resources
5//! or be forged if they're created from invalid values.
6//!
7//! This module provides three types for representing raw handles and sockets
8//! with different ownership properties: raw, borrowed, and owned, which are
9//! analogous to types used for representing pointers. These types reflect concepts of [I/O
10//! safety][io-safety] on Windows.
11//!
12//! | Type | Analogous to |
13//! | ---------------------- | ------------ |
14//! | [`RawHandle`] | `*const _` |
15//! | [`RawSocket`] | `*const _` |
16//! | | |
17//! | [`BorrowedHandle<'a>`] | `&'a _` |
18//! | [`BorrowedSocket<'a>`] | `&'a _` |
19//! | | |
20//! | [`OwnedHandle`] | `Box<_>` |
21//! | [`OwnedSocket`] | `Box<_>` |
22//!
23//! Like raw pointers, `RawHandle` and `RawSocket` values are primitive values.
24//! And in new code, they should be considered unsafe to do I/O on (analogous
25//! to dereferencing them). Rust did not always provide this guidance, so
26//! existing code in the Rust ecosystem often doesn't mark `RawHandle` and
27//! `RawSocket` usage as unsafe.
28//! Libraries are encouraged to migrate, either by adding `unsafe` to APIs
29//! that dereference `RawHandle` and `RawSocket` values, or by using to
30//! `BorrowedHandle`, `BorrowedSocket`, `OwnedHandle`, or `OwnedSocket`.
31//!
32//! Like references, `BorrowedHandle` and `BorrowedSocket` values are tied to a
33//! lifetime, to ensure that they don't outlive the resource they point to.
34//! These are safe to use. `BorrowedHandle` and `BorrowedSocket` values may be
35//! used in APIs which provide safe access to any system call except for
36//! `CloseHandle`, `closesocket`, or any other call that would end the
37//! dynamic lifetime of the resource without ending the lifetime of the
38//! handle or socket.
39//!
40//! `BorrowedHandle` and `BorrowedSocket` values may be used in APIs which
41//! provide safe access to `DuplicateHandle` and `WSADuplicateSocketW` and
42//! related functions, so types implementing `AsHandle`, `AsSocket`,
43//! `From<OwnedHandle>`, or `From<OwnedSocket>` should not assume they always
44//! have exclusive access to the underlying object.
45//!
46//! Like boxes, `OwnedHandle` and `OwnedSocket` values conceptually own the
47//! resource they point to, and free (close) it when they are dropped.
48//!
49//! See the [`io` module docs][io-safety] for a general explanation of I/O safety.
50//!
51//! [`BorrowedHandle<'a>`]: crate::os::windows::io::BorrowedHandle
52//! [`BorrowedSocket<'a>`]: crate::os::windows::io::BorrowedSocket
53//! [io-safety]: crate::io#io-safety
54
55#![stable(feature = "rust1", since = "1.0.0")]
56
57mod handle;
58mod raw;
59mod socket;
60
61#[stable(feature = "io_safety", since = "1.63.0")]
62pub use handle::*;
63#[stable(feature = "rust1", since = "1.0.0")]
64pub use raw::*;
65#[stable(feature = "io_safety", since = "1.63.0")]
66pub use socket::*;
67
68use crate::io::{self, Stderr, StderrLock, Stdin, StdinLock, Stdout, StdoutLock, Write};
69use crate::ptr;
70#[cfg(not(doc))]
71use crate::sys::c;
72
73#[cfg(test)]
74mod tests;
75
76#[unstable(feature = "stdio_swap", issue = "150667", reason = "recently added")]
77pub impl(self) trait StdioExt {
78 /// Sets the stdio console handle to `handle`, or `NULL` if it is `None`.
79 /// The old handle, if any, will not be closed, i.e. it is leaked because
80 /// console handles are shared global resources.
81 ///
82 /// Rust std::io write buffers (if any) are flushed, but other runtimes
83 /// (e.g. C stdio) or libraries that acquire a clone of the file handle
84 /// will not be aware of this change.
85 ///
86 /// ```
87 /// #![feature(stdio_swap)]
88 /// use std::io::{self, Read, Write};
89 /// use std::os::windows::io::StdioExt;
90 ///
91 /// fn main() -> io::Result<()> {
92 /// let (reader, mut writer) = io::pipe()?;
93 /// let mut stdin = io::stdin();
94 /// stdin.set_handle(Some(reader))?;
95 /// writer.write_all(b"Hello, world!")?;
96 /// let mut buffer = vec![0; 13];
97 /// assert_eq!(stdin.read(&mut buffer)?, 13);
98 /// assert_eq!(&buffer, b"Hello, world!");
99 /// Ok(())
100 /// }
101 /// ```
102 fn set_handle<T: Into<OwnedHandle>>(&mut self, handle: Option<T>) -> io::Result<()>;
103
104 /// Sets the stdio console handle to `replace_with`. The previous handle is returned, or
105 /// `None` if it was `NULL`.
106 ///
107 /// The returned handle is a `BorrowedHandle<'static>` because console handles are shared global resources
108 /// and may have been obtained by other functions or threads.
109 /// Only if you have ensured that no other part of the program has borrowed this handle you can convert it into
110 /// an `OwnedHandle` and drop that to close it.
111 ///
112 /// Like `set_handle()`, Rust std::io write buffers (if any) are flushed.
113 fn replace_handle<T: Into<OwnedHandle>>(
114 &mut self,
115 replace_with: T,
116 ) -> io::Result<Option<BorrowedHandle<'static>>>;
117
118 /// Sets the stdio console handle to `NULL` and returns the old one
119 ///
120 /// See [`set_handle()`] for additional details.
121 ///
122 /// [`set_handle()`]: StdioExt::set_handle
123 fn take_handle(&mut self) -> io::Result<Option<BorrowedHandle<'static>>>;
124}
125
126macro io_ext_impl($stdio_ty:ty, $stdio_lock_ty:ty, $handle:path, $writer:literal) {
127 #[unstable(feature = "stdio_swap", issue = "150667", reason = "recently added")]
128 impl StdioExt for $stdio_ty {
129 fn set_handle<T: Into<OwnedHandle>>(&mut self, handle: Option<T>) -> io::Result<()> {
130 self.lock().set_handle(handle)
131 }
132
133 fn replace_handle<T: Into<OwnedHandle>>(
134 &mut self,
135 replace_with: T,
136 ) -> io::Result<Option<BorrowedHandle<'static>>> {
137 self.lock().replace_handle(replace_with)
138 }
139
140 fn take_handle(&mut self) -> io::Result<Option<BorrowedHandle<'static>>> {
141 self.lock().take_handle()
142 }
143 }
144
145 #[unstable(feature = "stdio_swap", issue = "150667", reason = "recently added")]
146 impl StdioExt for $stdio_lock_ty {
147 fn set_handle<T: Into<OwnedHandle>>(&mut self, handle: Option<T>) -> io::Result<()> {
148 #[cfg($writer)]
149 self.flush()?;
150 let raw = handle.map(|h| h.into().into_raw_handle()).unwrap_or(ptr::null_mut());
151 unsafe { c::SetStdHandle($handle, raw) };
152 Ok(())
153 }
154
155 fn replace_handle<T: Into<OwnedHandle>>(
156 &mut self,
157 replace_with: T,
158 ) -> io::Result<Option<BorrowedHandle<'static>>> {
159 let old = unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) };
160 self.set_handle(Some(replace_with))?;
161 let handle = if old.as_raw_handle().is_null() { None } else { Some(old) };
162 Ok(handle)
163 }
164
165 fn take_handle(&mut self) -> io::Result<Option<BorrowedHandle<'static>>> {
166 let old = unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) };
167 #[cfg($writer)]
168 self.flush()?;
169 unsafe { c::SetStdHandle($handle, ptr::null_mut()) };
170 let handle = if old.as_raw_handle().is_null() { None } else { Some(old) };
171 Ok(handle)
172 }
173 }
174}
175
176io_ext_impl!(Stdout, StdoutLock<'_>, c::STD_OUTPUT_HANDLE, true);
177io_ext_impl!(Stdin, StdinLock<'_>, c::STD_INPUT_HANDLE, false);
178io_ext_impl!(Stderr, StderrLock<'_>, c::STD_ERROR_HANDLE, true);