use std::fs::File;
use std::hash::{Hash, Hasher};
use std::io;
use std::os::windows::io::{
AsRawHandle, IntoRawHandle, RawHandle,
};
use std::path::Path;
use winapi_util as winutil;
#[derive(Debug)]
pub struct Handle {
kind: HandleKind,
key: Option<Key>,
}
#[derive(Debug)]
enum HandleKind {
Owned(winutil::Handle),
Borrowed(winutil::HandleRef),
}
#[derive(Debug, Eq, PartialEq, Hash)]
struct Key {
volume: u64,
index: u64,
}
impl Eq for Handle {}
impl PartialEq for Handle {
fn eq(&self, other: &Handle) -> bool {
if self as *const Handle == other as *const Handle {
return true;
} else if self.key.is_none() || other.key.is_none() {
return false;
}
self.key == other.key
}
}
impl AsRawHandle for ::Handle {
fn as_raw_handle(&self) -> RawHandle {
match self.0.kind {
HandleKind::Owned(ref h) => h.as_raw_handle(),
HandleKind::Borrowed(ref h) => h.as_raw_handle(),
}
}
}
impl IntoRawHandle for ::Handle {
fn into_raw_handle(self) -> RawHandle {
match self.0.kind {
HandleKind::Owned(h) => h.into_raw_handle(),
HandleKind::Borrowed(h) => h.as_raw_handle(),
}
}
}
impl Hash for Handle {
fn hash<H: Hasher>(&self, state: &mut H) {
self.key.hash(state);
}
}
impl Handle {
pub fn from_path<P: AsRef<Path>>(p: P) -> io::Result<Handle> {
let h = winutil::Handle::from_path_any(p)?;
let info = winutil::file::information(&h)?;
Ok(Handle::from_info(HandleKind::Owned(h), info))
}
pub fn from_file(file: File) -> io::Result<Handle> {
let h = winutil::Handle::from_file(file);
let info = winutil::file::information(&h)?;
Ok(Handle::from_info(HandleKind::Owned(h), info))
}
fn from_std_handle(h: winutil::HandleRef) -> io::Result<Handle> {
match winutil::file::information(&h) {
Ok(info) => Ok(Handle::from_info(HandleKind::Borrowed(h), info)),
Err(_) => Ok(Handle { kind: HandleKind::Borrowed(h), key: None }),
}
}
fn from_info(
kind: HandleKind,
info: winutil::file::Information,
) -> Handle {
Handle {
kind: kind,
key: Some(Key {
volume: info.volume_serial_number(),
index: info.file_index(),
}),
}
}
pub fn stdin() -> io::Result<Handle> {
Handle::from_std_handle(winutil::HandleRef::stdin())
}
pub fn stdout() -> io::Result<Handle> {
Handle::from_std_handle(winutil::HandleRef::stdout())
}
pub fn stderr() -> io::Result<Handle> {
Handle::from_std_handle(winutil::HandleRef::stderr())
}
pub fn as_file(&self) -> &File {
match self.kind {
HandleKind::Owned(ref h) => h.as_file(),
HandleKind::Borrowed(ref h) => h.as_file(),
}
}
pub fn as_file_mut(&mut self) -> &mut File {
match self.kind {
HandleKind::Owned(ref mut h) => h.as_file_mut(),
HandleKind::Borrowed(ref mut h) => h.as_file_mut(),
}
}
}