cap_primitives/fs/file_type.rs
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 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
//! The `FileType` struct.
use crate::fs::ImplFileTypeExt;
/// `FileType`'s inner state.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
enum Inner {
/// A directory.
Dir,
/// A file.
File,
/// An unknown entity.
Unknown,
/// A `FileTypeExt` type.
Ext(ImplFileTypeExt),
}
/// A structure representing a type of file with accessors for each file type.
///
/// This corresponds to [`std::fs::FileType`].
///
/// <details>
/// We need to define our own version because the libstd `FileType` doesn't
/// have a public constructor that we can use.
/// </details>
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[repr(transparent)]
pub struct FileType(Inner);
impl FileType {
/// Creates a `FileType` for which `is_dir()` returns `true`.
#[inline]
pub const fn dir() -> Self {
Self(Inner::Dir)
}
/// Creates a `FileType` for which `is_file()` returns `true`.
#[inline]
pub const fn file() -> Self {
Self(Inner::File)
}
/// Creates a `FileType` for which `is_unknown()` returns `true`.
#[inline]
pub const fn unknown() -> Self {
Self(Inner::Unknown)
}
/// Creates a `FileType` from extension type.
#[inline]
pub(crate) const fn ext(ext: ImplFileTypeExt) -> Self {
Self(Inner::Ext(ext))
}
/// Tests whether this file type represents a directory.
///
/// This corresponds to [`std::fs::FileType::is_dir`].
#[inline]
pub fn is_dir(&self) -> bool {
self.0 == Inner::Dir
}
/// Tests whether this file type represents a regular file.
///
/// This corresponds to [`std::fs::FileType::is_file`].
#[inline]
pub fn is_file(&self) -> bool {
self.0 == Inner::File
}
/// Tests whether this file type represents a symbolic link.
///
/// This corresponds to [`std::fs::FileType::is_symlink`].
#[inline]
pub fn is_symlink(&self) -> bool {
if let Inner::Ext(ext) = self.0 {
ext.is_symlink()
} else {
false
}
}
}
/// Unix-specific extensions for [`FileType`].
///
/// This corresponds to [`std::os::unix::fs::FileTypeExt`].
#[cfg(any(unix, target_os = "vxworks"))]
pub trait FileTypeExt {
/// Returns `true` if this file type is a block device.
fn is_block_device(&self) -> bool;
/// Returns `true` if this file type is a character device.
fn is_char_device(&self) -> bool;
/// Returns `true` if this file type is a fifo.
fn is_fifo(&self) -> bool;
/// Returns `true` if this file type is a socket.
fn is_socket(&self) -> bool;
}
#[cfg(any(unix, target_os = "vxworks"))]
impl FileTypeExt for FileType {
#[inline]
fn is_block_device(&self) -> bool {
self.0 == Inner::Ext(ImplFileTypeExt::block_device())
}
#[inline]
fn is_char_device(&self) -> bool {
self.0 == Inner::Ext(ImplFileTypeExt::char_device())
}
#[inline]
fn is_fifo(&self) -> bool {
self.0 == Inner::Ext(ImplFileTypeExt::fifo())
}
#[inline]
fn is_socket(&self) -> bool {
self.0 == Inner::Ext(ImplFileTypeExt::socket())
}
}
/// Windows-specific extensions for [`FileType`].
///
/// This corresponds to [`std::os::windows::fs::FileTypeExt`].
#[cfg(all(windows, windows_file_type_ext))]
pub trait FileTypeExt {
/// Returns `true` if this file type is a symbolic link that is also a
/// directory.
fn is_symlink_dir(&self) -> bool;
/// Returns `true` if this file type is a symbolic link that is also a
/// file.
fn is_symlink_file(&self) -> bool;
}
#[cfg(all(windows, windows_file_type_ext))]
impl FileTypeExt for FileType {
#[inline]
fn is_symlink_dir(&self) -> bool {
self.0 == Inner::Ext(ImplFileTypeExt::symlink_dir())
}
#[inline]
fn is_symlink_file(&self) -> bool {
self.0 == Inner::Ext(ImplFileTypeExt::symlink_file())
}
}
/// Extension trait to allow `is_block_device` etc. to be exposed by
/// the `cap-fs-ext` crate.
///
/// This is hidden from the main API since this functionality isn't present in
/// `std`. Use `cap_fs_ext::FileTypeExt` instead of calling this directly.
#[cfg(windows)]
#[doc(hidden)]
pub trait _WindowsFileTypeExt {
fn is_block_device(&self) -> bool;
fn is_char_device(&self) -> bool;
fn is_fifo(&self) -> bool;
fn is_socket(&self) -> bool;
}