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}