1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
//! Exposes a `close` method on files, to permit finer grained error handling.
//!
//! ```
//! use close_err::Closable;
//! use std::{fs::File, io::Write};
//!
//! let mut f = File::create("abc").unwrap();
//! f.write_all("hello".as_bytes());
//! f.close();
//! ```

use std::io;

pub trait Closable {
    fn close(self) -> Result<(), io::Error>;
}

#[cfg(unix)]
impl<T> Closable for T
where
    T: std::os::unix::io::IntoRawFd,
{
    fn close(self) -> Result<(), io::Error> {
        let success = {
            let fd = self.into_raw_fd();
            let rc = unsafe { libc::close(fd) };
            rc == 0
        };

        if success {
            Ok(())
        } else {
            Err(io::Error::last_os_error())
        }
    }
}

#[cfg(windows)]
impl<T> Closable for T
where
    T: std::os::windows::io::IntoRawHandle,
{
    fn close(self) -> Result<(), io::Error> {
        let success = {
            let handle = self.into_raw_handle();
            let rc = unsafe { kernel32::CloseHandle(handle) };
            rc != 0
        };

        if success {
            Ok(())
        } else {
            Err(io::Error::last_os_error())
        }
    }
}