use std::fmt;
use windows_sys::Win32::Foundation::{NO_ERROR, SetLastError};
use windows_sys::Win32::Storage::FileSystem::{
FILE_TYPE, FILE_TYPE_CHAR, FILE_TYPE_DISK, FILE_TYPE_PIPE, FILE_TYPE_REMOTE, FILE_TYPE_UNKNOWN,
GetFileType,
};
use win_shared_os_owned_handle::SharedHandle;
use crate::handle::SharedRaw;
use crate::outcome::{Outcome, perform};
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct FileType(FILE_TYPE);
impl FileType {
pub const DISK: Self = Self(FILE_TYPE_DISK);
pub const CHAR: Self = Self(FILE_TYPE_CHAR);
pub const PIPE: Self = Self(FILE_TYPE_PIPE);
pub const REMOTE: Self = Self(FILE_TYPE_REMOTE);
pub const UNKNOWN: Self = Self(FILE_TYPE_UNKNOWN);
#[must_use]
pub const fn as_raw(self) -> FILE_TYPE {
self.0
}
#[must_use]
pub const fn from_raw(value: FILE_TYPE) -> Self {
Self(value)
}
}
impl fmt::Debug for FileType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Self::DISK => f.write_str("FileType::DISK"),
Self::CHAR => f.write_str("FileType::CHAR"),
Self::PIPE => f.write_str("FileType::PIPE"),
Self::REMOTE => f.write_str("FileType::REMOTE"),
Self::UNKNOWN => f.write_str("FileType::UNKNOWN"),
Self(other) => write!(f, "FileType({other:#x})"),
}
}
}
#[derive(Clone, Debug)]
#[must_use = "an unperformed request queries nothing"]
pub struct QueryFileType {
handle: SharedHandle,
}
impl QueryFileType {
pub fn new(handle: impl Into<SharedHandle>) -> Self {
Self {
handle: handle.into(),
}
}
pub fn handle(&self) -> &SharedHandle {
&self.handle
}
pub fn perform(&self) -> Outcome<FileType> {
let returned = perform(
|| {
unsafe { SetLastError(NO_ERROR) };
unsafe { GetFileType(self.handle.raw()) }
},
|kind| *kind == FILE_TYPE_UNKNOWN,
);
unknown_with_no_error_is_a_result(returned)
}
}
fn unknown_with_no_error_is_a_result(returned: Outcome<FILE_TYPE>) -> Outcome<FileType> {
match returned {
Ok(kind) => Ok(FileType(kind)),
Err(error) if error.code() == NO_ERROR => Ok(FileType::UNKNOWN),
Err(error) => Err(error),
}
}
impl crate::request::Request for QueryFileType {
type Error = crate::Win32Error;
type Output = FileType;
fn perform(&self) -> Outcome<FileType> {
Self::perform(self)
}
}
#[cfg(test)]
mod tests;