fancy_tree/tree/entry/attributes/
mod.rs1pub use directory::DirectoryAttributes;
3pub use file::FileAttributes;
4use std::fs::{self, File, Metadata};
5use std::io;
6use std::path::Path;
7pub use symlink::SymlinkAttributes;
8
9mod directory;
10mod file;
11mod interop;
12mod symlink;
13
14pub enum Attributes {
16 Directory(DirectoryAttributes),
18 File(FileAttributes),
20 Symlink(SymlinkAttributes),
22}
23
24impl Attributes {
25 pub fn new<P>(path: P) -> io::Result<Self>
27 where
28 P: AsRef<Path>,
29 {
30 let path = path.as_ref();
31 let metadata = fs::metadata(path)?;
32 let file_type = metadata.file_type();
33
34 if file_type.is_symlink() {
35 Ok(Self::new_symlink())
36 } else if file_type.is_dir() {
37 Ok(Self::new_directory(metadata))
38 } else if file_type.is_file() {
39 let file = File::open(path)?;
40 Self::new_file(path, file, metadata)
41 } else {
42 unreachable!("Must be a symlink, directory, or file")
44 }
45 }
46
47 #[inline]
49 fn new_file<P>(path: P, file: File, metadata: Metadata) -> io::Result<Self>
50 where
51 P: AsRef<Path>,
52 {
53 FileAttributes::new(path, file, metadata).map(Self::File)
54 }
55
56 #[inline]
58 fn new_directory(metadata: Metadata) -> Self {
59 Self::Directory(DirectoryAttributes::new(metadata))
60 }
61
62 #[inline]
64 fn new_symlink() -> Self {
65 Self::Symlink(SymlinkAttributes)
66 }
67
68 #[inline]
70 pub fn file(&self) -> Option<&FileAttributes> {
71 if let Self::File(attributes) = self {
72 Some(attributes)
73 } else {
74 None
75 }
76 }
77
78 #[inline]
80 pub fn directory(&self) -> Option<&DirectoryAttributes> {
81 if let Self::Directory(attributes) = self {
82 Some(attributes)
83 } else {
84 None
85 }
86 }
87
88 #[inline]
90 pub fn symlink(&self) -> Option<&SymlinkAttributes> {
91 if let Self::Symlink(attributes) = self {
92 Some(attributes)
93 } else {
94 None
95 }
96 }
97
98 pub fn is_executable(&self) -> bool {
100 self.is_file_and(|attributes| attributes.is_executable())
101 }
102
103 pub fn is_hidden(&self) -> bool {
105 self.is_file_and(|attributes| attributes.is_hidden())
106 || self.is_directory_and(|attributes| attributes.is_hidden())
107 }
108
109 #[inline]
111 pub const fn is_file(&self) -> bool {
112 matches!(self, Self::File(_))
113 }
114
115 pub fn is_file_and<F>(&self, f: F) -> bool
117 where
118 F: FnOnce(&FileAttributes) -> bool,
119 {
120 if let Self::File(attributes) = self {
121 f(attributes)
122 } else {
123 false
124 }
125 }
126
127 #[inline]
129 pub const fn is_directory(&self) -> bool {
130 matches!(self, Self::Directory(_))
131 }
132
133 pub fn is_directory_and<F>(&self, f: F) -> bool
135 where
136 F: FnOnce(&DirectoryAttributes) -> bool,
137 {
138 if let Self::Directory(attributes) = self {
139 f(attributes)
140 } else {
141 false
142 }
143 }
144
145 #[inline]
147 pub const fn is_symlink(&self) -> bool {
148 matches!(self, Self::Symlink(_))
149 }
150}