summaryrefslogtreecommitdiffstats
path: root/third_party/rust/comedy/src/handle.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/comedy/src/handle.rs')
-rw-r--r--third_party/rust/comedy/src/handle.rs91
1 files changed, 91 insertions, 0 deletions
diff --git a/third_party/rust/comedy/src/handle.rs b/third_party/rust/comedy/src/handle.rs
new file mode 100644
index 0000000000..e31d53773e
--- /dev/null
+++ b/third_party/rust/comedy/src/handle.rs
@@ -0,0 +1,91 @@
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// All files in the project carrying such notice may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Wrapping and automatically closing handles.
+
+use winapi::shared::minwindef::DWORD;
+use winapi::shared::ntdef::NULL;
+use winapi::um::errhandlingapi::GetLastError;
+use winapi::um::handleapi::{CloseHandle, INVALID_HANDLE_VALUE};
+use winapi::um::winnt::HANDLE;
+
+/// Check and automatically close a Windows `HANDLE`.
+#[repr(transparent)]
+#[derive(Debug)]
+pub struct Handle(HANDLE);
+
+impl Handle {
+ /// Take ownership of a `HANDLE`, which will be closed with `CloseHandle` upon drop.
+ /// Returns an error in case of `INVALID_HANDLE_VALUE` or `NULL`.
+ ///
+ /// # Safety
+ ///
+ /// `h` should be the only copy of the handle. `GetLastError()` is called to
+ /// return an error, so the last Windows API called on this thread should have been
+ /// what produced the invalid handle.
+ pub unsafe fn new(h: HANDLE) -> Result<Handle, DWORD> {
+ if h == NULL || h == INVALID_HANDLE_VALUE {
+ Err(GetLastError())
+ } else {
+ Ok(Handle(h))
+ }
+ }
+
+ /// Obtains the raw `HANDLE` without transferring ownership.
+ ///
+ /// Do __not__ close this handle because it is still owned by the `Handle`.
+ ///
+ /// Do __not__ use this handle beyond the lifetime of the `Handle`.
+ pub fn as_raw(&self) -> HANDLE {
+ self.0
+ }
+}
+
+impl Drop for Handle {
+ fn drop(&mut self) {
+ unsafe {
+ CloseHandle(self.0);
+ }
+ }
+}
+
+/// Call a function that returns a `HANDLE` (`NULL` or `INVALID_HANDLE_VALUE` on failure), wrap result.
+///
+/// The handle is wrapped in a [`Handle`](handle/struct.Handle.html) which will automatically call
+/// `CloseHandle()` on it. If the function fails, the error is retrieved via `GetLastError()` and
+/// augmented with the name of the function and the file and line number of the macro usage.
+///
+/// # Example
+///
+/// ```no_run
+/// # extern crate winapi;
+/// # use std::ptr;
+/// # use winapi::um::fileapi::FindFirstFileW;
+/// # use winapi::um::minwinbase::WIN32_FIND_DATAW;
+/// # use comedy::handle::Handle;
+/// # use comedy::{call_handle_getter, Win32Error};
+/// #
+/// unsafe fn find_first(name: &[u16], data: &mut WIN32_FIND_DATAW) -> Result<Handle, Win32Error> {
+/// call_handle_getter!(FindFirstFileW(name.as_ptr(), data))
+/// }
+/// ```
+#[macro_export]
+macro_rules! call_handle_getter {
+ ($f:ident ( $($arg:expr),* )) => {
+ {
+ use $crate::error::{ErrorCode, FileLine, ResultExt, Win32Error};
+ $crate::handle::Handle::new($f($($arg),*))
+ .map_err(Win32Error::new)
+ .function(stringify!($f))
+ .file_line(file!(), line!())
+ }
+ };
+
+ // support for trailing comma in argument list
+ ($f:ident ( $($arg:expr),+ , )) => {
+ $crate::call_valid_handle_getter!($f($($arg),*))
+ };
+}