1use std::{io, fs};
22use std::fmt;
23
24pub struct CloseError {
28 previous: io::Error,
29 file: Option<fs::File>,
30}
31
32impl CloseError {
33 pub fn into_file_handle(self) -> Option<fs::File> {
38 self.file
39 }
40
41 pub fn unwrap(self) -> io::Error {
42 self.previous
43 }
44}
45
46impl std::error::Error for CloseError {}
47
48pub trait Closable {
49 fn close(self) -> Result<(), CloseError>;
50}
51
52impl fmt::Display for CloseError {
53 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54 fmt::Display::fmt(&self.previous, f)
55 }
56}
57
58impl fmt::Debug for CloseError {
59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 fmt::Debug::fmt(&self.previous, f)
61 }
62}
63
64#[cfg(unix)]
65mod imp {
66 use std::os::unix::prelude::*;
67 use std::{io, fs};
68 use crate::CloseError;
69
70 impl crate::Closable for fs::File {
71 fn close(self) -> Result<(), CloseError> {
72 let fd = self.into_raw_fd();
73 let rc = unsafe {
74 libc::close(fd)
75 };
76 if rc == -1 {
77 Ok(())
78 } else {
79 Err(CloseError { previous: io::Error::last_os_error(), file: Some(unsafe { fs::File::from_raw_fd(fd) }) })
80 }
81 }
82 }
83}
84
85#[cfg(windows)]
86mod imp {
87 use std::os::windows::prelude::*;
88 use std::{io, fs};
89 use crate::CloseError;
90
91 impl crate::Closable for fs::File {
92 fn close(self) -> Result<(), CloseError> {
93 let handle = self.into_raw_handle();
94 let rc = unsafe {
95 kernel32::CloseHandle(handle)
96 };
97 if rc != 0 {
98 Ok(())
99 } else {
100 Err(CloseError { previous: io::Error::last_os_error(), file: Some(unsafe { fs::File::from_raw_handle(handle) }) })
101 }
102 }
103 }
104}