• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! which
2 //!
3 //! A Rust equivalent of Unix command `which(1)`.
4 //! # Example:
5 //!
6 //! To find which rustc executable binary is using:
7 //!
8 //! ```no_run
9 //! use which::which;
10 //! use std::path::PathBuf;
11 //!
12 //! let result = which("rustc").unwrap();
13 //! assert_eq!(result, PathBuf::from("/usr/bin/rustc"));
14 //!
15 //! ```
16 
17 mod checker;
18 mod error;
19 mod finder;
20 #[cfg(windows)]
21 mod helper;
22 
23 #[cfg(feature = "regex")]
24 use std::borrow::Borrow;
25 use std::env;
26 use std::fmt;
27 use std::path;
28 
29 use std::ffi::{OsStr, OsString};
30 
31 use crate::checker::{CompositeChecker, ExecutableChecker, ExistedChecker};
32 pub use crate::error::*;
33 use crate::finder::Finder;
34 
35 /// Find an executable binary's path by name.
36 ///
37 /// If given an absolute path, returns it if the file exists and is executable.
38 ///
39 /// If given a relative path, returns an absolute path to the file if
40 /// it exists and is executable.
41 ///
42 /// If given a string without path separators, looks for a file named
43 /// `binary_name` at each directory in `$PATH` and if it finds an executable
44 /// file there, returns it.
45 ///
46 /// # Example
47 ///
48 /// ```no_run
49 /// use which::which;
50 /// use std::path::PathBuf;
51 ///
52 /// let result = which::which("rustc").unwrap();
53 /// assert_eq!(result, PathBuf::from("/usr/bin/rustc"));
54 ///
55 /// ```
which<T: AsRef<OsStr>>(binary_name: T) -> Result<path::PathBuf>56 pub fn which<T: AsRef<OsStr>>(binary_name: T) -> Result<path::PathBuf> {
57     which_all(binary_name).and_then(|mut i| i.next().ok_or(Error::CannotFindBinaryPath))
58 }
59 
60 /// Find an executable binary's path by name, ignoring `cwd`.
61 ///
62 /// If given an absolute path, returns it if the file exists and is executable.
63 ///
64 /// Does not resolve relative paths.
65 ///
66 /// If given a string without path separators, looks for a file named
67 /// `binary_name` at each directory in `$PATH` and if it finds an executable
68 /// file there, returns it.
69 ///
70 /// # Example
71 ///
72 /// ```no_run
73 /// use which::which;
74 /// use std::path::PathBuf;
75 ///
76 /// let result = which::which_global("rustc").unwrap();
77 /// assert_eq!(result, PathBuf::from("/usr/bin/rustc"));
78 ///
79 /// ```
which_global<T: AsRef<OsStr>>(binary_name: T) -> Result<path::PathBuf>80 pub fn which_global<T: AsRef<OsStr>>(binary_name: T) -> Result<path::PathBuf> {
81     which_all_global(binary_name).and_then(|mut i| i.next().ok_or(Error::CannotFindBinaryPath))
82 }
83 
84 /// Find all binaries with `binary_name` using `cwd` to resolve relative paths.
which_all<T: AsRef<OsStr>>(binary_name: T) -> Result<impl Iterator<Item = path::PathBuf>>85 pub fn which_all<T: AsRef<OsStr>>(binary_name: T) -> Result<impl Iterator<Item = path::PathBuf>> {
86     let cwd = env::current_dir().ok();
87 
88     let binary_checker = build_binary_checker();
89 
90     let finder = Finder::new();
91 
92     finder.find(binary_name, env::var_os("PATH"), cwd, binary_checker)
93 }
94 
95 /// Find all binaries with `binary_name` ignoring `cwd`.
which_all_global<T: AsRef<OsStr>>( binary_name: T, ) -> Result<impl Iterator<Item = path::PathBuf>>96 pub fn which_all_global<T: AsRef<OsStr>>(
97     binary_name: T,
98 ) -> Result<impl Iterator<Item = path::PathBuf>> {
99     let binary_checker = build_binary_checker();
100 
101     let finder = Finder::new();
102 
103     finder.find(
104         binary_name,
105         env::var_os("PATH"),
106         Option::<&Path>::None,
107         binary_checker,
108     )
109 }
110 
111 /// Find all binaries matching a regular expression in a the system PATH.
112 ///
113 /// Only available when feature `regex` is enabled.
114 ///
115 /// # Arguments
116 ///
117 /// * `regex` - A regular expression to match binaries with
118 ///
119 /// # Examples
120 ///
121 /// Find Python executables:
122 ///
123 /// ```no_run
124 /// use regex::Regex;
125 /// use which::which;
126 /// use std::path::PathBuf;
127 ///
128 /// let re = Regex::new(r"python\d$").unwrap();
129 /// let binaries: Vec<PathBuf> = which::which_re(re).unwrap().collect();
130 /// let python_paths = vec![PathBuf::from("/usr/bin/python2"), PathBuf::from("/usr/bin/python3")];
131 /// assert_eq!(binaries, python_paths);
132 /// ```
133 ///
134 /// Find all cargo subcommand executables on the path:
135 ///
136 /// ```
137 /// use which::which_re;
138 /// use regex::Regex;
139 ///
140 /// which_re(Regex::new("^cargo-.*").unwrap()).unwrap()
141 ///     .for_each(|pth| println!("{}", pth.to_string_lossy()));
142 /// ```
143 #[cfg(feature = "regex")]
which_re(regex: impl Borrow<Regex>) -> Result<impl Iterator<Item = path::PathBuf>>144 pub fn which_re(regex: impl Borrow<Regex>) -> Result<impl Iterator<Item = path::PathBuf>> {
145     which_re_in(regex, env::var_os("PATH"))
146 }
147 
148 /// Find `binary_name` in the path list `paths`, using `cwd` to resolve relative paths.
which_in<T, U, V>(binary_name: T, paths: Option<U>, cwd: V) -> Result<path::PathBuf> where T: AsRef<OsStr>, U: AsRef<OsStr>, V: AsRef<path::Path>,149 pub fn which_in<T, U, V>(binary_name: T, paths: Option<U>, cwd: V) -> Result<path::PathBuf>
150 where
151     T: AsRef<OsStr>,
152     U: AsRef<OsStr>,
153     V: AsRef<path::Path>,
154 {
155     which_in_all(binary_name, paths, cwd)
156         .and_then(|mut i| i.next().ok_or(Error::CannotFindBinaryPath))
157 }
158 
159 /// Find all binaries matching a regular expression in a list of paths.
160 ///
161 /// Only available when feature `regex` is enabled.
162 ///
163 /// # Arguments
164 ///
165 /// * `regex` - A regular expression to match binaries with
166 /// * `paths` - A string containing the paths to search
167 ///             (separated in the same way as the PATH environment variable)
168 ///
169 /// # Examples
170 ///
171 /// ```no_run
172 /// use regex::Regex;
173 /// use which::which;
174 /// use std::path::PathBuf;
175 ///
176 /// let re = Regex::new(r"python\d$").unwrap();
177 /// let paths = Some("/usr/bin:/usr/local/bin");
178 /// let binaries: Vec<PathBuf> = which::which_re_in(re, paths).unwrap().collect();
179 /// let python_paths = vec![PathBuf::from("/usr/bin/python2"), PathBuf::from("/usr/bin/python3")];
180 /// assert_eq!(binaries, python_paths);
181 /// ```
182 #[cfg(feature = "regex")]
which_re_in<T>( regex: impl Borrow<Regex>, paths: Option<T>, ) -> Result<impl Iterator<Item = path::PathBuf>> where T: AsRef<OsStr>,183 pub fn which_re_in<T>(
184     regex: impl Borrow<Regex>,
185     paths: Option<T>,
186 ) -> Result<impl Iterator<Item = path::PathBuf>>
187 where
188     T: AsRef<OsStr>,
189 {
190     let binary_checker = build_binary_checker();
191 
192     let finder = Finder::new();
193 
194     finder.find_re(regex, paths, binary_checker)
195 }
196 
197 /// Find all binaries with `binary_name` in the path list `paths`, using `cwd` to resolve relative paths.
which_in_all<T, U, V>( binary_name: T, paths: Option<U>, cwd: V, ) -> Result<impl Iterator<Item = path::PathBuf>> where T: AsRef<OsStr>, U: AsRef<OsStr>, V: AsRef<path::Path>,198 pub fn which_in_all<T, U, V>(
199     binary_name: T,
200     paths: Option<U>,
201     cwd: V,
202 ) -> Result<impl Iterator<Item = path::PathBuf>>
203 where
204     T: AsRef<OsStr>,
205     U: AsRef<OsStr>,
206     V: AsRef<path::Path>,
207 {
208     let binary_checker = build_binary_checker();
209 
210     let finder = Finder::new();
211 
212     finder.find(binary_name, paths, Some(cwd), binary_checker)
213 }
214 
215 /// Find all binaries with `binary_name` in the path list `paths`, ignoring `cwd`.
which_in_global<T, U>( binary_name: T, paths: Option<U>, ) -> Result<impl Iterator<Item = path::PathBuf>> where T: AsRef<OsStr>, U: AsRef<OsStr>,216 pub fn which_in_global<T, U>(
217     binary_name: T,
218     paths: Option<U>,
219 ) -> Result<impl Iterator<Item = path::PathBuf>>
220 where
221     T: AsRef<OsStr>,
222     U: AsRef<OsStr>,
223 {
224     let binary_checker = build_binary_checker();
225 
226     let finder = Finder::new();
227 
228     finder.find(binary_name, paths, Option::<&Path>::None, binary_checker)
229 }
230 
build_binary_checker() -> CompositeChecker231 fn build_binary_checker() -> CompositeChecker {
232     CompositeChecker::new()
233         .add_checker(Box::new(ExistedChecker::new()))
234         .add_checker(Box::new(ExecutableChecker::new()))
235 }
236 
237 /// A wrapper containing all functionality in this crate.
238 pub struct WhichConfig {
239     cwd: Option<either::Either<bool, path::PathBuf>>,
240     custom_path_list: Option<OsString>,
241     binary_name: Option<OsString>,
242     #[cfg(feature = "regex")]
243     regex: Option<Regex>,
244 }
245 
246 impl Default for WhichConfig {
default() -> Self247     fn default() -> Self {
248         Self {
249             cwd: Some(either::Either::Left(true)),
250             custom_path_list: None,
251             binary_name: None,
252             #[cfg(feature = "regex")]
253             regex: None,
254         }
255     }
256 }
257 
258 #[cfg(feature = "regex")]
259 type Regex = regex::Regex;
260 
261 #[cfg(not(feature = "regex"))]
262 type Regex = ();
263 
264 impl WhichConfig {
new() -> Self265     pub fn new() -> Self {
266         Self::default()
267     }
268 
269     /// Whether or not to use the current working directory. `true` by default.
270     ///
271     /// # Panics
272     ///
273     /// If regex was set previously, and you've just passed in `use_cwd: true`, this will panic.
system_cwd(mut self, use_cwd: bool) -> Self274     pub fn system_cwd(mut self, use_cwd: bool) -> Self {
275         #[cfg(feature = "regex")]
276         if self.regex.is_some() && use_cwd {
277             panic!("which can't use regex and cwd at the same time!")
278         }
279         self.cwd = Some(either::Either::Left(use_cwd));
280         self
281     }
282 
283     /// Sets a custom path for resolving relative paths.
284     ///
285     /// # Panics
286     ///
287     /// If regex was set previously, this will panic.
custom_cwd(mut self, cwd: path::PathBuf) -> Self288     pub fn custom_cwd(mut self, cwd: path::PathBuf) -> Self {
289         #[cfg(feature = "regex")]
290         if self.regex.is_some() {
291             panic!("which can't use regex and cwd at the same time!")
292         }
293         self.cwd = Some(either::Either::Right(cwd));
294         self
295     }
296 
297     /// Sets the path name regex to search for. You ***MUST*** call this, or [`Self::binary_name`] prior to searching.
298     ///
299     /// When `Regex` is disabled this function takes the unit type as a stand in. The parameter will change when
300     /// `Regex` is enabled.
301     ///
302     /// # Panics
303     ///
304     /// If the `regex` feature wasn't turned on for this crate this will always panic. Additionally if a
305     /// `cwd` (aka current working directory) or `binary_name` was set previously, this will panic, as those options
306     /// are incompatible with `regex`.
307     #[allow(unused_variables)]
regex(mut self, regex: Regex) -> Self308     pub fn regex(mut self, regex: Regex) -> Self {
309         #[cfg(not(feature = "regex"))]
310         {
311             panic!("which's regex feature was not enabled in your Cargo.toml!")
312         }
313         #[cfg(feature = "regex")]
314         {
315             if self.cwd != Some(either::Either::Left(false)) && self.cwd.is_some() {
316                 panic!("which can't use regex and cwd at the same time!")
317             }
318             if self.binary_name.is_some() {
319                 panic!("which can't use `binary_name` and `regex` at the same time!");
320             }
321             self.regex = Some(regex);
322             self
323         }
324     }
325 
326     /// Sets the path name to search for. You ***MUST*** call this, or [`Self::regex`] prior to searching.
327     ///
328     /// # Panics
329     ///
330     /// If a `regex` was set previously this will panic as this is not compatible with `regex`.
binary_name(mut self, name: OsString) -> Self331     pub fn binary_name(mut self, name: OsString) -> Self {
332         #[cfg(feature = "regex")]
333         if self.regex.is_some() {
334             panic!("which can't use `binary_name` and `regex` at the same time!");
335         }
336         self.binary_name = Some(name);
337         self
338     }
339 
340     /// Uses the given string instead of the `PATH` env variable.
custom_path_list(mut self, custom_path_list: OsString) -> Self341     pub fn custom_path_list(mut self, custom_path_list: OsString) -> Self {
342         self.custom_path_list = Some(custom_path_list);
343         self
344     }
345 
346     /// Uses the `PATH` env variable. Enabled by default.
system_path_list(mut self) -> Self347     pub fn system_path_list(mut self) -> Self {
348         self.custom_path_list = None;
349         self
350     }
351 
352     /// Finishes configuring, runs the query and returns the first result.
first_result(self) -> Result<path::PathBuf>353     pub fn first_result(self) -> Result<path::PathBuf> {
354         self.all_results()
355             .and_then(|mut i| i.next().ok_or(Error::CannotFindBinaryPath))
356     }
357 
358     /// Finishes configuring, runs the query and returns all results.
all_results(self) -> Result<impl Iterator<Item = path::PathBuf>>359     pub fn all_results(self) -> Result<impl Iterator<Item = path::PathBuf>> {
360         let binary_checker = build_binary_checker();
361 
362         let finder = Finder::new();
363 
364         let paths = self.custom_path_list.or_else(|| env::var_os("PATH"));
365 
366         #[cfg(feature = "regex")]
367         if let Some(regex) = self.regex {
368             return finder
369                 .find_re(regex, paths, binary_checker)
370                 .map(|i| Box::new(i) as Box<dyn Iterator<Item = path::PathBuf>>);
371         }
372 
373         let cwd = match self.cwd {
374             Some(either::Either::Left(false)) => None,
375             Some(either::Either::Right(custom)) => Some(custom),
376             None | Some(either::Either::Left(true)) => env::current_dir().ok(),
377         };
378 
379         finder
380             .find(
381                 self.binary_name.expect(
382                     "binary_name not set! You must set binary_name or regex before searching!",
383                 ),
384                 paths,
385                 cwd,
386                 binary_checker,
387             )
388             .map(|i| Box::new(i) as Box<dyn Iterator<Item = path::PathBuf>>)
389     }
390 }
391 
392 /// An owned, immutable wrapper around a `PathBuf` containing the path of an executable.
393 ///
394 /// The constructed `PathBuf` is the output of `which` or `which_in`, but `which::Path` has the
395 /// advantage of being a type distinct from `std::path::Path` and `std::path::PathBuf`.
396 ///
397 /// It can be beneficial to use `which::Path` instead of `std::path::Path` when you want the type
398 /// system to enforce the need for a path that exists and points to a binary that is executable.
399 ///
400 /// Since `which::Path` implements `Deref` for `std::path::Path`, all methods on `&std::path::Path`
401 /// are also available to `&which::Path` values.
402 #[derive(Clone, PartialEq, Eq)]
403 pub struct Path {
404     inner: path::PathBuf,
405 }
406 
407 impl Path {
408     /// Returns the path of an executable binary by name.
409     ///
410     /// This calls `which` and maps the result into a `Path`.
new<T: AsRef<OsStr>>(binary_name: T) -> Result<Path>411     pub fn new<T: AsRef<OsStr>>(binary_name: T) -> Result<Path> {
412         which(binary_name).map(|inner| Path { inner })
413     }
414 
415     /// Returns the paths of all executable binaries by a name.
416     ///
417     /// this calls `which_all` and maps the results into `Path`s.
all<T: AsRef<OsStr>>(binary_name: T) -> Result<impl Iterator<Item = Path>>418     pub fn all<T: AsRef<OsStr>>(binary_name: T) -> Result<impl Iterator<Item = Path>> {
419         which_all(binary_name).map(|inner| inner.map(|inner| Path { inner }))
420     }
421 
422     /// Returns the path of an executable binary by name in the path list `paths` and using the
423     /// current working directory `cwd` to resolve relative paths.
424     ///
425     /// This calls `which_in` and maps the result into a `Path`.
new_in<T, U, V>(binary_name: T, paths: Option<U>, cwd: V) -> Result<Path> where T: AsRef<OsStr>, U: AsRef<OsStr>, V: AsRef<path::Path>,426     pub fn new_in<T, U, V>(binary_name: T, paths: Option<U>, cwd: V) -> Result<Path>
427     where
428         T: AsRef<OsStr>,
429         U: AsRef<OsStr>,
430         V: AsRef<path::Path>,
431     {
432         which_in(binary_name, paths, cwd).map(|inner| Path { inner })
433     }
434 
435     /// Returns all paths of an executable binary by name in the path list `paths` and using the
436     /// current working directory `cwd` to resolve relative paths.
437     ///
438     /// This calls `which_in_all` and maps the results into a `Path`.
all_in<T, U, V>( binary_name: T, paths: Option<U>, cwd: V, ) -> Result<impl Iterator<Item = Path>> where T: AsRef<OsStr>, U: AsRef<OsStr>, V: AsRef<path::Path>,439     pub fn all_in<T, U, V>(
440         binary_name: T,
441         paths: Option<U>,
442         cwd: V,
443     ) -> Result<impl Iterator<Item = Path>>
444     where
445         T: AsRef<OsStr>,
446         U: AsRef<OsStr>,
447         V: AsRef<path::Path>,
448     {
449         which_in_all(binary_name, paths, cwd).map(|inner| inner.map(|inner| Path { inner }))
450     }
451 
452     /// Returns a reference to a `std::path::Path`.
as_path(&self) -> &path::Path453     pub fn as_path(&self) -> &path::Path {
454         self.inner.as_path()
455     }
456 
457     /// Consumes the `which::Path`, yielding its underlying `std::path::PathBuf`.
into_path_buf(self) -> path::PathBuf458     pub fn into_path_buf(self) -> path::PathBuf {
459         self.inner
460     }
461 }
462 
463 impl fmt::Debug for Path {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result464     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
465         fmt::Debug::fmt(&self.inner, f)
466     }
467 }
468 
469 impl std::ops::Deref for Path {
470     type Target = path::Path;
471 
deref(&self) -> &path::Path472     fn deref(&self) -> &path::Path {
473         self.inner.deref()
474     }
475 }
476 
477 impl AsRef<path::Path> for Path {
as_ref(&self) -> &path::Path478     fn as_ref(&self) -> &path::Path {
479         self.as_path()
480     }
481 }
482 
483 impl AsRef<OsStr> for Path {
as_ref(&self) -> &OsStr484     fn as_ref(&self) -> &OsStr {
485         self.as_os_str()
486     }
487 }
488 
489 impl PartialEq<path::PathBuf> for Path {
eq(&self, other: &path::PathBuf) -> bool490     fn eq(&self, other: &path::PathBuf) -> bool {
491         self.inner == *other
492     }
493 }
494 
495 impl PartialEq<Path> for path::PathBuf {
eq(&self, other: &Path) -> bool496     fn eq(&self, other: &Path) -> bool {
497         *self == other.inner
498     }
499 }
500 
501 /// An owned, immutable wrapper around a `PathBuf` containing the _canonical_ path of an
502 /// executable.
503 ///
504 /// The constructed `PathBuf` is the result of `which` or `which_in` followed by
505 /// `Path::canonicalize`, but `CanonicalPath` has the advantage of being a type distinct from
506 /// `std::path::Path` and `std::path::PathBuf`.
507 ///
508 /// It can be beneficial to use `CanonicalPath` instead of `std::path::Path` when you want the type
509 /// system to enforce the need for a path that exists, points to a binary that is executable, is
510 /// absolute, has all components normalized, and has all symbolic links resolved
511 ///
512 /// Since `CanonicalPath` implements `Deref` for `std::path::Path`, all methods on
513 /// `&std::path::Path` are also available to `&CanonicalPath` values.
514 #[derive(Clone, PartialEq, Eq)]
515 pub struct CanonicalPath {
516     inner: path::PathBuf,
517 }
518 
519 impl CanonicalPath {
520     /// Returns the canonical path of an executable binary by name.
521     ///
522     /// This calls `which` and `Path::canonicalize` and maps the result into a `CanonicalPath`.
new<T: AsRef<OsStr>>(binary_name: T) -> Result<CanonicalPath>523     pub fn new<T: AsRef<OsStr>>(binary_name: T) -> Result<CanonicalPath> {
524         which(binary_name)
525             .and_then(|p| p.canonicalize().map_err(|_| Error::CannotCanonicalize))
526             .map(|inner| CanonicalPath { inner })
527     }
528 
529     /// Returns the canonical paths of an executable binary by name.
530     ///
531     /// This calls `which_all` and `Path::canonicalize` and maps the results into `CanonicalPath`s.
all<T: AsRef<OsStr>>( binary_name: T, ) -> Result<impl Iterator<Item = Result<CanonicalPath>>>532     pub fn all<T: AsRef<OsStr>>(
533         binary_name: T,
534     ) -> Result<impl Iterator<Item = Result<CanonicalPath>>> {
535         which_all(binary_name).map(|inner| {
536             inner.map(|inner| {
537                 inner
538                     .canonicalize()
539                     .map_err(|_| Error::CannotCanonicalize)
540                     .map(|inner| CanonicalPath { inner })
541             })
542         })
543     }
544 
545     /// Returns the canonical path of an executable binary by name in the path list `paths` and
546     /// using the current working directory `cwd` to resolve relative paths.
547     ///
548     /// This calls `which_in` and `Path::canonicalize` and maps the result into a `CanonicalPath`.
new_in<T, U, V>(binary_name: T, paths: Option<U>, cwd: V) -> Result<CanonicalPath> where T: AsRef<OsStr>, U: AsRef<OsStr>, V: AsRef<path::Path>,549     pub fn new_in<T, U, V>(binary_name: T, paths: Option<U>, cwd: V) -> Result<CanonicalPath>
550     where
551         T: AsRef<OsStr>,
552         U: AsRef<OsStr>,
553         V: AsRef<path::Path>,
554     {
555         which_in(binary_name, paths, cwd)
556             .and_then(|p| p.canonicalize().map_err(|_| Error::CannotCanonicalize))
557             .map(|inner| CanonicalPath { inner })
558     }
559 
560     /// Returns all of the canonical paths of an executable binary by name in the path list `paths` and
561     /// using the current working directory `cwd` to resolve relative paths.
562     ///
563     /// This calls `which_in_all` and `Path::canonicalize` and maps the result into a `CanonicalPath`.
all_in<T, U, V>( binary_name: T, paths: Option<U>, cwd: V, ) -> Result<impl Iterator<Item = Result<CanonicalPath>>> where T: AsRef<OsStr>, U: AsRef<OsStr>, V: AsRef<path::Path>,564     pub fn all_in<T, U, V>(
565         binary_name: T,
566         paths: Option<U>,
567         cwd: V,
568     ) -> Result<impl Iterator<Item = Result<CanonicalPath>>>
569     where
570         T: AsRef<OsStr>,
571         U: AsRef<OsStr>,
572         V: AsRef<path::Path>,
573     {
574         which_in_all(binary_name, paths, cwd).map(|inner| {
575             inner.map(|inner| {
576                 inner
577                     .canonicalize()
578                     .map_err(|_| Error::CannotCanonicalize)
579                     .map(|inner| CanonicalPath { inner })
580             })
581         })
582     }
583 
584     /// Returns a reference to a `std::path::Path`.
as_path(&self) -> &path::Path585     pub fn as_path(&self) -> &path::Path {
586         self.inner.as_path()
587     }
588 
589     /// Consumes the `which::CanonicalPath`, yielding its underlying `std::path::PathBuf`.
into_path_buf(self) -> path::PathBuf590     pub fn into_path_buf(self) -> path::PathBuf {
591         self.inner
592     }
593 }
594 
595 impl fmt::Debug for CanonicalPath {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result596     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
597         fmt::Debug::fmt(&self.inner, f)
598     }
599 }
600 
601 impl std::ops::Deref for CanonicalPath {
602     type Target = path::Path;
603 
deref(&self) -> &path::Path604     fn deref(&self) -> &path::Path {
605         self.inner.deref()
606     }
607 }
608 
609 impl AsRef<path::Path> for CanonicalPath {
as_ref(&self) -> &path::Path610     fn as_ref(&self) -> &path::Path {
611         self.as_path()
612     }
613 }
614 
615 impl AsRef<OsStr> for CanonicalPath {
as_ref(&self) -> &OsStr616     fn as_ref(&self) -> &OsStr {
617         self.as_os_str()
618     }
619 }
620 
621 impl PartialEq<path::PathBuf> for CanonicalPath {
eq(&self, other: &path::PathBuf) -> bool622     fn eq(&self, other: &path::PathBuf) -> bool {
623         self.inner == *other
624     }
625 }
626 
627 impl PartialEq<CanonicalPath> for path::PathBuf {
eq(&self, other: &CanonicalPath) -> bool628     fn eq(&self, other: &CanonicalPath) -> bool {
629         *self == other.inner
630     }
631 }
632