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