use std::{io, fs};
use std::fmt;
pub struct CloseError {
previous: io::Error,
file: Option<fs::File>,
}
impl CloseError {
pub fn into_file_handle(self) -> Option<fs::File> {
self.file
}
pub fn unwrap(self) -> io::Error {
self.previous
}
}
impl std::error::Error for CloseError {}
pub trait Closable {
fn close(self) -> Result<(), CloseError>;
}
impl fmt::Display for CloseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.previous, f)
}
}
impl fmt::Debug for CloseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.previous, f)
}
}
#[cfg(unix)]
mod imp {
use std::os::unix::prelude::*;
use std::{io, fs};
use crate::CloseError;
impl crate::Closable for fs::File {
fn close(self) -> Result<(), CloseError> {
let fd = self.into_raw_fd();
let rc = unsafe {
libc::close(fd)
};
if rc == -1 {
Ok(())
} else {
Err(CloseError { previous: io::Error::last_os_error(), file: Some(unsafe { fs::File::from_raw_fd(fd) }) })
}
}
}
}
#[cfg(windows)]
mod imp {
use std::os::windows::prelude::*;
use std::{io, fs};
use crate::CloseError;
impl crate::Closable for fs::File {
fn close(self) -> Result<(), CloseError> {
let handle = self.into_raw_handle();
let rc = unsafe {
kernel32::CloseHandle(handle)
};
if rc != 0 {
Ok(())
} else {
Err(CloseError { previous: io::Error::last_os_error(), file: Some(unsafe { fs::File::from_raw_handle(handle) }) })
}
}
}
}