app_path/app_path/traits.rs
1//! Trait implementations for `AppPath`.
2//!
3//! This module contains all the standard trait implementations that make `AppPath`
4//! work seamlessly with Rust's standard library and idiomatic code patterns.
5
6use crate::AppPath;
7use std::borrow::Borrow;
8use std::cmp::Ordering;
9use std::hash::{Hash, Hasher};
10use std::ops::Deref;
11use std::path::{Path, PathBuf};
12
13// === Core Display and Conversion Traits ===
14
15/// Default implementation returns the executable's directory.
16///
17/// This provides a natural default for AppPath - the directory where
18/// the executable is located.
19///
20/// # Examples
21///
22/// ```rust
23/// use app_path::AppPath;
24/// use std::path::Path;
25///
26/// let exe_dir = AppPath::default();
27/// let explicit = AppPath::new();
28/// assert_eq!(exe_dir.as_ref() as &Path, explicit.as_ref() as &Path);
29/// ```
30impl Default for AppPath {
31 #[inline]
32 fn default() -> Self {
33 Self::new()
34 }
35}
36
37// === Core Display and Conversion Traits ===
38
39impl std::fmt::Display for AppPath {
40 #[inline]
41 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42 write!(f, "{}", self.full_path.display())
43 }
44}
45
46impl AsRef<Path> for AppPath {
47 #[inline]
48 fn as_ref(&self) -> &Path {
49 &self.full_path
50 }
51}
52
53// === Infallible From Implementations ===
54
55impl From<&str> for AppPath {
56 #[inline]
57 fn from(path: &str) -> Self {
58 Self::with(path)
59 }
60}
61
62impl From<String> for AppPath {
63 #[inline]
64 fn from(path: String) -> Self {
65 Self::with(path)
66 }
67}
68
69impl From<&String> for AppPath {
70 #[inline]
71 fn from(path: &String) -> Self {
72 Self::with(path)
73 }
74}
75
76impl From<&Path> for AppPath {
77 #[inline]
78 fn from(path: &Path) -> Self {
79 Self::with(path)
80 }
81}
82
83impl From<PathBuf> for AppPath {
84 #[inline]
85 fn from(path: PathBuf) -> Self {
86 Self::with(path)
87 }
88}
89
90impl From<&PathBuf> for AppPath {
91 #[inline]
92 fn from(path: &PathBuf) -> Self {
93 Self::with(path)
94 }
95}
96
97// === Additional Trait Implementations ===
98
99impl PartialEq for AppPath {
100 /// Compares two `AppPath` instances for equality based on their resolved paths.
101 ///
102 /// Two `AppPath` instances are considered equal if their full resolved paths
103 /// are identical, regardless of how they were constructed.
104 ///
105 /// # Examples
106 ///
107 /// ```rust
108 /// use app_path::AppPath;
109 ///
110 /// let path1 = AppPath::with("config.toml");
111 /// let path2 = AppPath::with("config.toml");
112 /// let path3 = AppPath::with("other.toml");
113 ///
114 /// assert_eq!(path1, path2);
115 /// assert_ne!(path1, path3);
116 /// ```
117 #[inline]
118 fn eq(&self, other: &Self) -> bool {
119 self.full_path == other.full_path
120 }
121}
122
123impl Eq for AppPath {}
124
125impl PartialOrd for AppPath {
126 /// Compares two `AppPath` instances lexicographically based on their resolved paths.
127 ///
128 /// The comparison is performed on the full resolved paths, providing consistent
129 /// ordering for sorting and collection operations.
130 ///
131 /// # Examples
132 ///
133 /// ```rust
134 /// use app_path::AppPath;
135 ///
136 /// let path1 = AppPath::with("a.txt");
137 /// let path2 = AppPath::with("b.txt");
138 ///
139 /// assert!(path1 < path2);
140 /// ```
141 #[inline]
142 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
143 Some(self.cmp(other))
144 }
145}
146
147impl Ord for AppPath {
148 /// Compares two `AppPath` instances lexicographically based on their resolved paths.
149 ///
150 /// This provides a total ordering that enables `AppPath` to be used in sorted
151 /// collections like `BTreeMap` and `BTreeSet`.
152 ///
153 /// # Examples
154 ///
155 /// ```rust
156 /// use app_path::AppPath;
157 /// use std::collections::BTreeSet;
158 ///
159 /// let mut paths = BTreeSet::new();
160 /// paths.insert(AppPath::with("config.toml"));
161 /// paths.insert(AppPath::with("data.db"));
162 /// paths.insert(AppPath::with("app.log"));
163 ///
164 /// // Paths are automatically sorted lexicographically
165 /// let sorted: Vec<_> = paths.into_iter().collect();
166 /// ```
167 #[inline]
168 fn cmp(&self, other: &Self) -> Ordering {
169 self.full_path.cmp(&other.full_path)
170 }
171}
172
173impl Hash for AppPath {
174 /// Computes a hash for the `AppPath` based on its resolved path.
175 ///
176 /// This enables `AppPath` to be used as keys in hash-based collections
177 /// like `HashMap` and `HashSet`. The hash is computed from the full
178 /// resolved path, ensuring consistent behavior.
179 ///
180 /// # Examples
181 ///
182 /// ```rust
183 /// use app_path::AppPath;
184 /// use std::collections::HashMap;
185 ///
186 /// let mut config_map = HashMap::new();
187 /// let config_path = AppPath::with("config.toml");
188 /// config_map.insert(config_path, "Configuration file");
189 /// ```
190 #[inline]
191 fn hash<H: Hasher>(&self, state: &mut H) {
192 self.full_path.hash(state);
193 }
194}
195
196impl Deref for AppPath {
197 type Target = Path;
198
199 /// Provides direct access to the underlying `Path` through deref coercion.
200 ///
201 /// This allows `AppPath` to be used directly with any API that expects a `&Path`,
202 /// making it a zero-cost abstraction in many contexts. All `Path` methods become
203 /// directly available on `AppPath` instances.
204 ///
205 /// # Examples
206 ///
207 /// ```rust
208 /// use app_path::AppPath;
209 ///
210 /// let app_path = AppPath::with("config.toml");
211 ///
212 /// // Direct access to Path methods through deref
213 /// assert_eq!(app_path.extension(), Some("toml".as_ref()));
214 /// assert_eq!(app_path.file_name(), Some("config.toml".as_ref()));
215 /// assert!(app_path.is_absolute());
216 ///
217 /// // Works with functions expecting &Path
218 /// fn process_path(path: &std::path::Path) {
219 /// println!("Processing: {}", path.display());
220 /// }
221 /// process_path(&app_path); // Automatic deref coercion
222 ///
223 /// // For explicit &Path reference when needed
224 /// let path_ref: &std::path::Path = &app_path; // Via deref
225 /// let path_ref2: &std::path::Path = app_path.as_ref(); // Via AsRef
226 /// ```
227 #[inline]
228 fn deref(&self) -> &Self::Target {
229 &self.full_path
230 }
231}
232
233impl Borrow<Path> for AppPath {
234 /// Allows `AppPath` to be borrowed as a `Path`.
235 ///
236 /// This enables `AppPath` to be used seamlessly in collections that are
237 /// keyed by `Path`, and allows for efficient lookups using `&Path` values.
238 ///
239 /// # Examples
240 ///
241 /// ```rust
242 /// use app_path::AppPath;
243 /// use std::collections::HashMap;
244 /// use std::path::Path;
245 ///
246 /// let mut path_map = HashMap::new();
247 /// let app_path = AppPath::with("config.toml");
248 /// path_map.insert(app_path, "config data");
249 ///
250 /// // Can look up using a &Path
251 /// let lookup_path = Path::new("relative/to/exe/config.toml");
252 /// // Note: This would only work if the paths actually match
253 /// ```
254 #[inline]
255 fn borrow(&self) -> &Path {
256 &self.full_path
257 }
258}
259
260// === Additional Conversion Traits ===
261
262impl AsRef<std::ffi::OsStr> for AppPath {
263 /// Converts `AppPath` to `&OsStr` for FFI operations.
264 ///
265 /// This is useful when interfacing with operating system APIs that require `OsStr`.
266 ///
267 /// # Examples
268 ///
269 /// ```rust
270 /// use app_path::AppPath;
271 /// use std::ffi::OsStr;
272 ///
273 /// let config = AppPath::with("config.toml");
274 /// let os_str: &OsStr = config.as_ref();
275 /// ```
276 #[inline]
277 fn as_ref(&self) -> &std::ffi::OsStr {
278 self.full_path.as_os_str()
279 }
280}
281
282impl From<AppPath> for PathBuf {
283 /// Converts `AppPath` to `PathBuf` for owned path operations.
284 ///
285 /// This moves the internal `PathBuf` out of the `AppPath`, providing
286 /// efficient conversion without cloning.
287 ///
288 /// # Examples
289 ///
290 /// ```rust
291 /// use app_path::AppPath;
292 /// use std::path::PathBuf;
293 ///
294 /// let config = AppPath::with("config.toml");
295 /// let path_buf: PathBuf = config.into();
296 /// ```
297 #[inline]
298 fn from(app_path: AppPath) -> Self {
299 app_path.full_path
300 }
301}
302
303impl From<AppPath> for std::ffi::OsString {
304 /// Converts `AppPath` to `OsString` for owned FFI operations.
305 ///
306 /// # Examples
307 ///
308 /// ```rust
309 /// use app_path::AppPath;
310 /// use std::ffi::OsString;
311 ///
312 /// let config = AppPath::with("config.toml");
313 /// let os_string: OsString = config.into();
314 /// ```
315 #[inline]
316 fn from(app_path: AppPath) -> Self {
317 app_path.full_path.into_os_string()
318 }
319}