which/
lib.rs

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//! # #[cfg(feature = "real-sys")]
10//! # {
11//! use which::which;
12//! use std::path::PathBuf;
13//!
14//! let result = which("rustc").unwrap();
15//! assert_eq!(result, PathBuf::from("/usr/bin/rustc"));
16//! # }
17//! ```
18
19mod checker;
20mod error;
21mod finder;
22mod helper;
23pub mod sys;
24
25use std::fmt;
26use std::path;
27
28use std::ffi::{OsStr, OsString};
29
30pub use crate::error::*;
31use crate::finder::Finder;
32use crate::sys::Sys;
33
34/// Find an executable binary's path by name.
35///
36/// If given an absolute path, returns it if the file exists and is executable.
37///
38/// If given a relative path, returns an absolute path to the file if
39/// it exists and is executable.
40///
41/// If given a string without path separators, looks for a file named
42/// `binary_name` at each directory in `$PATH` and if it finds an executable
43/// file there, returns it.
44///
45/// # Example
46///
47/// ```no_run
48/// use which::which;
49/// use std::path::PathBuf;
50///
51/// let result = which::which("rustc").unwrap();
52/// assert_eq!(result, PathBuf::from("/usr/bin/rustc"));
53///
54/// ```
55#[cfg(feature = "real-sys")]
56pub 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/// ```
80#[cfg(feature = "real-sys")]
81pub fn which_global<T: AsRef<OsStr>>(binary_name: T) -> Result<path::PathBuf> {
82    which_all_global(binary_name).and_then(|mut i| i.next().ok_or(Error::CannotFindBinaryPath))
83}
84
85/// Find all binaries with `binary_name` using `cwd` to resolve relative paths.
86#[cfg(feature = "real-sys")]
87pub fn which_all<T: AsRef<OsStr>>(binary_name: T) -> Result<impl Iterator<Item = path::PathBuf>> {
88    let cwd = sys::RealSys.current_dir().ok();
89
90    Finder::new(&sys::RealSys).find(binary_name, sys::RealSys.env_path(), cwd, Noop)
91}
92
93/// Find all binaries with `binary_name` ignoring `cwd`.
94#[cfg(feature = "real-sys")]
95pub fn which_all_global<T: AsRef<OsStr>>(
96    binary_name: T,
97) -> Result<impl Iterator<Item = path::PathBuf>> {
98    Finder::new(&sys::RealSys).find(
99        binary_name,
100        sys::RealSys.env_path(),
101        Option::<&Path>::None,
102        Noop,
103    )
104}
105
106/// Find all binaries matching a regular expression in a the system PATH.
107///
108/// Only available when feature `regex` is enabled.
109///
110/// # Arguments
111///
112/// * `regex` - A regular expression to match binaries with
113///
114/// # Examples
115///
116/// Find Python executables:
117///
118/// ```no_run
119/// use regex::Regex;
120/// use which::which;
121/// use std::path::PathBuf;
122///
123/// let re = Regex::new(r"python\d$").unwrap();
124/// let binaries: Vec<PathBuf> = which::which_re(re).unwrap().collect();
125/// let python_paths = vec![PathBuf::from("/usr/bin/python2"), PathBuf::from("/usr/bin/python3")];
126/// assert_eq!(binaries, python_paths);
127/// ```
128///
129/// Find all cargo subcommand executables on the path:
130///
131/// ```
132/// use which::which_re;
133/// use regex::Regex;
134///
135/// which_re(Regex::new("^cargo-.*").unwrap()).unwrap()
136///     .for_each(|pth| println!("{}", pth.to_string_lossy()));
137/// ```
138#[cfg(all(feature = "regex", feature = "real-sys"))]
139pub fn which_re(
140    regex: impl std::borrow::Borrow<Regex>,
141) -> Result<impl Iterator<Item = path::PathBuf>> {
142    which_re_in(regex, sys::RealSys.env_path())
143}
144
145/// Find `binary_name` in the path list `paths`, using `cwd` to resolve relative paths.
146#[cfg(feature = "real-sys")]
147pub fn which_in<T, U, V>(binary_name: T, paths: Option<U>, cwd: V) -> Result<path::PathBuf>
148where
149    T: AsRef<OsStr>,
150    U: AsRef<OsStr>,
151    V: AsRef<path::Path>,
152{
153    which_in_all(binary_name, paths, cwd)
154        .and_then(|mut i| i.next().ok_or(Error::CannotFindBinaryPath))
155}
156
157/// Find all binaries matching a regular expression in a list of paths.
158///
159/// Only available when feature `regex` is enabled.
160///
161/// # Arguments
162///
163/// * `regex` - A regular expression to match binaries with
164/// * `paths` - A string containing the paths to search
165///   (separated in the same way as the PATH environment variable)
166///
167/// # Examples
168///
169/// ```no_run
170/// use regex::Regex;
171/// use which::which;
172/// use std::path::PathBuf;
173///
174/// let re = Regex::new(r"python\d$").unwrap();
175/// let paths = Some("/usr/bin:/usr/local/bin");
176/// let binaries: Vec<PathBuf> = which::which_re_in(re, paths).unwrap().collect();
177/// let python_paths = vec![PathBuf::from("/usr/bin/python2"), PathBuf::from("/usr/bin/python3")];
178/// assert_eq!(binaries, python_paths);
179/// ```
180#[cfg(all(feature = "regex", feature = "real-sys"))]
181pub fn which_re_in<T>(
182    regex: impl std::borrow::Borrow<Regex>,
183    paths: Option<T>,
184) -> Result<impl Iterator<Item = path::PathBuf>>
185where
186    T: AsRef<OsStr>,
187{
188    Finder::new(&sys::RealSys).find_re(regex, paths, Noop)
189}
190
191/// Find all binaries with `binary_name` in the path list `paths`, using `cwd` to resolve relative paths.
192#[cfg(feature = "real-sys")]
193pub fn which_in_all<'a, T, U, V>(
194    binary_name: T,
195    paths: Option<U>,
196    cwd: V,
197) -> Result<impl Iterator<Item = path::PathBuf> + 'a>
198where
199    T: AsRef<OsStr>,
200    U: AsRef<OsStr>,
201    V: AsRef<path::Path> + 'a,
202{
203    Finder::new(&sys::RealSys).find(binary_name, paths, Some(cwd), Noop)
204}
205
206/// Find all binaries with `binary_name` in the path list `paths`, ignoring `cwd`.
207#[cfg(feature = "real-sys")]
208pub fn which_in_global<T, U>(
209    binary_name: T,
210    paths: Option<U>,
211) -> Result<impl Iterator<Item = path::PathBuf>>
212where
213    T: AsRef<OsStr>,
214    U: AsRef<OsStr>,
215{
216    Finder::new(&sys::RealSys).find(binary_name, paths, Option::<&Path>::None, Noop)
217}
218
219/// A wrapper containing all functionality in this crate.
220pub struct WhichConfig<TSys: sys::Sys, F = Noop> {
221    cwd: CwdOption,
222    custom_path_list: Option<OsString>,
223    binary_name: Option<OsString>,
224    nonfatal_error_handler: F,
225    #[cfg(feature = "regex")]
226    regex: Option<Regex>,
227    sys: TSys,
228}
229
230enum CwdOption {
231    Unspecified,
232    UseSysCwd,
233    RefuseCwd,
234    UseCustomCwd(path::PathBuf),
235}
236
237/// A handler for non-fatal errors which does nothing with them.
238#[derive(Default, Debug, Clone)]
239pub struct Noop;
240
241/// Defines what should happen when a nonfatal error is encountered. A nonfatal error may represent a problem,
242/// but it doesn't necessarily require `which` to stop its search.
243///
244/// This trait is implemented for any closure or function that takes a single argument which is a [`NonFatalError`].
245/// You may also implement it for your own types.
246pub trait NonFatalErrorHandler {
247    fn handle(&mut self, e: NonFatalError);
248}
249
250impl NonFatalErrorHandler for Noop {
251    fn handle(&mut self, _: NonFatalError) {
252        // Do nothing
253    }
254}
255
256impl<T> NonFatalErrorHandler for T
257where
258    T: FnMut(NonFatalError),
259{
260    fn handle(&mut self, e: NonFatalError) {
261        (self)(e);
262    }
263}
264
265#[cfg(feature = "real-sys")]
266impl<F: Default> Default for WhichConfig<&sys::RealSys, F> {
267    fn default() -> Self {
268        Self {
269            cwd: CwdOption::Unspecified,
270            custom_path_list: None,
271            binary_name: None,
272            nonfatal_error_handler: F::default(),
273            #[cfg(feature = "regex")]
274            regex: None,
275            sys: &sys::RealSys,
276        }
277    }
278}
279
280#[cfg(feature = "regex")]
281type Regex = regex::Regex;
282
283#[cfg(not(feature = "regex"))]
284type Regex = ();
285
286#[cfg(feature = "real-sys")]
287impl WhichConfig<&sys::RealSys, Noop> {
288    pub fn new() -> Self {
289        Self::new_with_sys(&sys::RealSys)
290    }
291}
292
293impl<TSys: Sys> WhichConfig<TSys, Noop> {
294    /// Creates a new `WhichConfig` with the given `sys::Sys`.
295    ///
296    /// This is useful for providing all the system related
297    /// functionality to this crate.
298    pub fn new_with_sys(sys: TSys) -> Self {
299        Self {
300            cwd: CwdOption::Unspecified,
301            custom_path_list: None,
302            binary_name: None,
303            nonfatal_error_handler: Noop,
304            #[cfg(feature = "regex")]
305            regex: None,
306            sys,
307        }
308    }
309}
310
311impl<'a, TSys: Sys + 'a, F: NonFatalErrorHandler + 'a> WhichConfig<TSys, F> {
312    /// Whether or not to use the current working directory. `true` by default.
313    ///
314    /// # Panics
315    ///
316    /// If regex was set previously, and you've just passed in `use_cwd: true`, this will panic.
317    pub fn system_cwd(mut self, use_cwd: bool) -> Self {
318        #[cfg(feature = "regex")]
319        if self.regex.is_some() && use_cwd {
320            panic!("which can't use regex and cwd at the same time!")
321        }
322        // Otherwise, keep custom cwd if specified.
323        self.cwd = if use_cwd {
324            CwdOption::UseSysCwd
325        } else {
326            CwdOption::RefuseCwd
327        };
328        self
329    }
330
331    /// Sets a custom path for resolving relative paths.
332    ///
333    /// # Panics
334    ///
335    /// If regex was set previously, this will panic.
336    pub fn custom_cwd(mut self, cwd: path::PathBuf) -> Self {
337        #[cfg(feature = "regex")]
338        if self.regex.is_some() {
339            panic!("which can't use regex and cwd at the same time!")
340        }
341        self.cwd = CwdOption::UseCustomCwd(cwd);
342        self
343    }
344
345    /// Sets the path name regex to search for. You ***MUST*** call this, or [`Self::binary_name`] prior to searching.
346    ///
347    /// When `Regex` is disabled this function takes the unit type as a stand in. The parameter will change when
348    /// `Regex` is enabled.
349    ///
350    /// # Panics
351    ///
352    /// If the `regex` feature wasn't turned on for this crate this will always panic. Additionally if a
353    /// `cwd` (aka current working directory) or `binary_name` was set previously, this will panic, as those options
354    /// are incompatible with `regex`.
355    #[allow(unused_variables)]
356    #[allow(unused_mut)]
357    pub fn regex(mut self, regex: Regex) -> Self {
358        #[cfg(not(feature = "regex"))]
359        {
360            panic!("which's regex feature was not enabled in your Cargo.toml!")
361        }
362        #[cfg(feature = "regex")]
363        {
364            if matches!(self.cwd, CwdOption::UseSysCwd)
365                || matches!(self.cwd, CwdOption::UseCustomCwd(_))
366            {
367                panic!("which can't use regex and cwd at the same time!")
368            }
369            if self.binary_name.is_some() {
370                panic!("which can't use `binary_name` and `regex` at the same time!");
371            }
372            self.regex = Some(regex);
373            self
374        }
375    }
376
377    /// Sets the path name to search for. You ***MUST*** call this, or [`Self::regex`] prior to searching.
378    ///
379    /// # Panics
380    ///
381    /// If a `regex` was set previously this will panic as this is not compatible with `regex`.
382    pub fn binary_name(mut self, name: OsString) -> Self {
383        #[cfg(feature = "regex")]
384        if self.regex.is_some() {
385            panic!("which can't use `binary_name` and `regex` at the same time!");
386        }
387        self.binary_name = Some(name);
388        self
389    }
390
391    /// Uses the given string instead of the `PATH` env variable.
392    pub fn custom_path_list(mut self, custom_path_list: OsString) -> Self {
393        self.custom_path_list = Some(custom_path_list);
394        self
395    }
396
397    /// Uses the `PATH` env variable. Enabled by default.
398    pub fn system_path_list(mut self) -> Self {
399        self.custom_path_list = None;
400        self
401    }
402
403    /// Sets a closure that will receive non-fatal errors. You can also pass in other types
404    /// that implement [`NonFatalErrorHandler`].
405    ///
406    /// # Example
407    /// ```
408    /// # #[cfg(feature = "real-sys")]
409    /// # {
410    /// # use which::WhichConfig;
411    /// let mut nonfatal_errors = Vec::new();
412    ///
413    /// WhichConfig::new()
414    ///     .binary_name("tar".into())
415    ///     .nonfatal_error_handler(|e| nonfatal_errors.push(e))
416    ///     .all_results()
417    ///     .unwrap()
418    ///     .collect::<Vec<_>>();
419    ///
420    /// if !nonfatal_errors.is_empty() {
421    ///     println!("nonfatal errors encountered: {nonfatal_errors:?}");
422    /// }
423    /// # }
424    /// ```
425    ///
426    /// You could also log it if you choose
427    ///
428    /// ```
429    /// # #[cfg(feature = "real-sys")]
430    /// # {
431    /// # use which::WhichConfig;
432    /// WhichConfig::new()
433    ///     .binary_name("tar".into())
434    ///     .nonfatal_error_handler(|e| eprintln!("{e}"))
435    ///     .all_results()
436    ///     .unwrap()
437    ///     .collect::<Vec<_>>();
438    /// # }
439    /// ```
440    pub fn nonfatal_error_handler<NewF>(self, handler: NewF) -> WhichConfig<TSys, NewF> {
441        WhichConfig {
442            custom_path_list: self.custom_path_list,
443            cwd: self.cwd,
444            binary_name: self.binary_name,
445            nonfatal_error_handler: handler,
446            #[cfg(feature = "regex")]
447            regex: self.regex,
448            sys: self.sys,
449        }
450    }
451
452    /// Finishes configuring, runs the query and returns the first result.
453    pub fn first_result(self) -> Result<path::PathBuf> {
454        self.all_results()
455            .and_then(|mut i| i.next().ok_or(Error::CannotFindBinaryPath))
456    }
457
458    /// Finishes configuring, runs the query and returns all results.
459    pub fn all_results(self) -> Result<impl Iterator<Item = path::PathBuf> + 'a> {
460        let paths = self.custom_path_list.or_else(|| self.sys.env_path());
461
462        #[cfg(feature = "regex")]
463        if let Some(regex) = self.regex {
464            return Finder::new(self.sys)
465                .find_re(regex, paths, self.nonfatal_error_handler)
466                .map(|i| Box::new(i) as Box<dyn Iterator<Item = path::PathBuf> + 'a>);
467        }
468
469        let cwd = match self.cwd {
470            CwdOption::RefuseCwd => None,
471            CwdOption::UseCustomCwd(custom) => Some(custom),
472            CwdOption::UseSysCwd | CwdOption::Unspecified => self.sys.current_dir().ok(),
473        };
474
475        Finder::new(self.sys)
476            .find(
477                self.binary_name.expect(
478                    "binary_name not set! You must set binary_name or regex before searching!",
479                ),
480                paths,
481                cwd,
482                self.nonfatal_error_handler,
483            )
484            .map(|i| Box::new(i) as Box<dyn Iterator<Item = path::PathBuf> + 'a>)
485    }
486}
487
488/// An owned, immutable wrapper around a `PathBuf` containing the path of an executable.
489///
490/// The constructed `PathBuf` is the output of `which` or `which_in`, but `which::Path` has the
491/// advantage of being a type distinct from `std::path::Path` and `std::path::PathBuf`.
492///
493/// It can be beneficial to use `which::Path` instead of `std::path::Path` when you want the type
494/// system to enforce the need for a path that exists and points to a binary that is executable.
495///
496/// Since `which::Path` implements `Deref` for `std::path::Path`, all methods on `&std::path::Path`
497/// are also available to `&which::Path` values.
498#[derive(Clone, PartialEq, Eq)]
499pub struct Path {
500    inner: path::PathBuf,
501}
502
503impl Path {
504    /// Returns the path of an executable binary by name.
505    ///
506    /// This calls `which` and maps the result into a `Path`.
507    #[cfg(feature = "real-sys")]
508    pub fn new<T: AsRef<OsStr>>(binary_name: T) -> Result<Path> {
509        which(binary_name).map(|inner| Path { inner })
510    }
511
512    /// Returns the paths of all executable binaries by a name.
513    ///
514    /// this calls `which_all` and maps the results into `Path`s.
515    #[cfg(feature = "real-sys")]
516    pub fn all<T: AsRef<OsStr>>(binary_name: T) -> Result<impl Iterator<Item = Path>> {
517        which_all(binary_name).map(|inner| inner.map(|inner| Path { inner }))
518    }
519
520    /// Returns the path of an executable binary by name in the path list `paths` and using the
521    /// current working directory `cwd` to resolve relative paths.
522    ///
523    /// This calls `which_in` and maps the result into a `Path`.
524    #[cfg(feature = "real-sys")]
525    pub fn new_in<T, U, V>(binary_name: T, paths: Option<U>, cwd: V) -> Result<Path>
526    where
527        T: AsRef<OsStr>,
528        U: AsRef<OsStr>,
529        V: AsRef<path::Path>,
530    {
531        which_in(binary_name, paths, cwd).map(|inner| Path { inner })
532    }
533
534    /// Returns all paths of an executable binary by name in the path list `paths` and using the
535    /// current working directory `cwd` to resolve relative paths.
536    ///
537    /// This calls `which_in_all` and maps the results into a `Path`.
538    #[cfg(feature = "real-sys")]
539    pub fn all_in<'a, T, U, V>(
540        binary_name: T,
541        paths: Option<U>,
542        cwd: V,
543    ) -> Result<impl Iterator<Item = Path> + 'a>
544    where
545        T: AsRef<OsStr>,
546        U: AsRef<OsStr>,
547        V: AsRef<path::Path> + 'a,
548    {
549        which_in_all(binary_name, paths, cwd).map(|inner| inner.map(|inner| Path { inner }))
550    }
551
552    /// Returns a reference to a `std::path::Path`.
553    pub fn as_path(&self) -> &path::Path {
554        self.inner.as_path()
555    }
556
557    /// Consumes the `which::Path`, yielding its underlying `std::path::PathBuf`.
558    pub fn into_path_buf(self) -> path::PathBuf {
559        self.inner
560    }
561}
562
563impl fmt::Debug for Path {
564    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
565        fmt::Debug::fmt(&self.inner, f)
566    }
567}
568
569impl std::ops::Deref for Path {
570    type Target = path::Path;
571
572    fn deref(&self) -> &path::Path {
573        self.inner.deref()
574    }
575}
576
577impl AsRef<path::Path> for Path {
578    fn as_ref(&self) -> &path::Path {
579        self.as_path()
580    }
581}
582
583impl AsRef<OsStr> for Path {
584    fn as_ref(&self) -> &OsStr {
585        self.as_os_str()
586    }
587}
588
589impl PartialEq<path::PathBuf> for Path {
590    fn eq(&self, other: &path::PathBuf) -> bool {
591        self.inner == *other
592    }
593}
594
595impl PartialEq<Path> for path::PathBuf {
596    fn eq(&self, other: &Path) -> bool {
597        *self == other.inner
598    }
599}
600
601/// An owned, immutable wrapper around a `PathBuf` containing the _canonical_ path of an
602/// executable.
603///
604/// The constructed `PathBuf` is the result of `which` or `which_in` followed by
605/// `Path::canonicalize`, but `CanonicalPath` has the advantage of being a type distinct from
606/// `std::path::Path` and `std::path::PathBuf`.
607///
608/// It can be beneficial to use `CanonicalPath` instead of `std::path::Path` when you want the type
609/// system to enforce the need for a path that exists, points to a binary that is executable, is
610/// absolute, has all components normalized, and has all symbolic links resolved
611///
612/// Since `CanonicalPath` implements `Deref` for `std::path::Path`, all methods on
613/// `&std::path::Path` are also available to `&CanonicalPath` values.
614#[derive(Clone, PartialEq, Eq)]
615pub struct CanonicalPath {
616    inner: path::PathBuf,
617}
618
619impl CanonicalPath {
620    /// Returns the canonical path of an executable binary by name.
621    ///
622    /// This calls `which` and `Path::canonicalize` and maps the result into a `CanonicalPath`.
623    #[cfg(feature = "real-sys")]
624    pub fn new<T: AsRef<OsStr>>(binary_name: T) -> Result<CanonicalPath> {
625        which(binary_name)
626            .and_then(|p| {
627                sys::RealSys
628                    .canonicalize(&p)
629                    .map_err(|_| Error::CannotCanonicalize)
630            })
631            .map(|inner| CanonicalPath { inner })
632    }
633
634    /// Returns the canonical paths of an executable binary by name.
635    ///
636    /// This calls `which_all` and `Path::canonicalize` and maps the results into `CanonicalPath`s.
637    #[cfg(feature = "real-sys")]
638    pub fn all<T: AsRef<OsStr>>(
639        binary_name: T,
640    ) -> Result<impl Iterator<Item = Result<CanonicalPath>>> {
641        which_all(binary_name).map(|inner| {
642            inner.map(|inner| {
643                sys::RealSys
644                    .canonicalize(&inner)
645                    .map_err(|_| Error::CannotCanonicalize)
646                    .map(|inner| CanonicalPath { inner })
647            })
648        })
649    }
650
651    /// Returns the canonical path of an executable binary by name in the path list `paths` and
652    /// using the current working directory `cwd` to resolve relative paths.
653    ///
654    /// This calls `which_in` and `Path::canonicalize` and maps the result into a `CanonicalPath`.
655    #[cfg(feature = "real-sys")]
656    pub fn new_in<T, U, V>(binary_name: T, paths: Option<U>, cwd: V) -> Result<CanonicalPath>
657    where
658        T: AsRef<OsStr>,
659        U: AsRef<OsStr>,
660        V: AsRef<path::Path>,
661    {
662        which_in(binary_name, paths, cwd)
663            .and_then(|p| {
664                sys::RealSys
665                    .canonicalize(&p)
666                    .map_err(|_| Error::CannotCanonicalize)
667            })
668            .map(|inner| CanonicalPath { inner })
669    }
670
671    /// Returns all of the canonical paths of an executable binary by name in the path list `paths` and
672    /// using the current working directory `cwd` to resolve relative paths.
673    ///
674    /// This calls `which_in_all` and `Path::canonicalize` and maps the result into a `CanonicalPath`.
675    #[cfg(feature = "real-sys")]
676    pub fn all_in<'a, T, U, V>(
677        binary_name: T,
678        paths: Option<U>,
679        cwd: V,
680    ) -> Result<impl Iterator<Item = Result<CanonicalPath>> + 'a>
681    where
682        T: AsRef<OsStr>,
683        U: AsRef<OsStr>,
684        V: AsRef<path::Path> + 'a,
685    {
686        which_in_all(binary_name, paths, cwd).map(|inner| {
687            inner.map(|inner| {
688                sys::RealSys
689                    .canonicalize(&inner)
690                    .map_err(|_| Error::CannotCanonicalize)
691                    .map(|inner| CanonicalPath { inner })
692            })
693        })
694    }
695
696    /// Returns a reference to a `std::path::Path`.
697    pub fn as_path(&self) -> &path::Path {
698        self.inner.as_path()
699    }
700
701    /// Consumes the `which::CanonicalPath`, yielding its underlying `std::path::PathBuf`.
702    pub fn into_path_buf(self) -> path::PathBuf {
703        self.inner
704    }
705}
706
707impl fmt::Debug for CanonicalPath {
708    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
709        fmt::Debug::fmt(&self.inner, f)
710    }
711}
712
713impl std::ops::Deref for CanonicalPath {
714    type Target = path::Path;
715
716    fn deref(&self) -> &path::Path {
717        self.inner.deref()
718    }
719}
720
721impl AsRef<path::Path> for CanonicalPath {
722    fn as_ref(&self) -> &path::Path {
723        self.as_path()
724    }
725}
726
727impl AsRef<OsStr> for CanonicalPath {
728    fn as_ref(&self) -> &OsStr {
729        self.as_os_str()
730    }
731}
732
733impl PartialEq<path::PathBuf> for CanonicalPath {
734    fn eq(&self, other: &path::PathBuf) -> bool {
735        self.inner == *other
736    }
737}
738
739impl PartialEq<CanonicalPath> for path::PathBuf {
740    fn eq(&self, other: &CanonicalPath) -> bool {
741        *self == other.inner
742    }
743}