1use std::io;
2use std::path::Path;
3use std::path::PathBuf;
4
5#[derive(Debug, Clone, Default)]
6pub struct SearchPath {
7 paths: Vec<PathBuf>,
9}
10
11impl SearchPath {
12 pub fn new(paths: Vec<PathBuf>) -> SearchPath {
13 SearchPath { paths }
14 }
15
16 pub fn from_string(s: &str) -> io::Result<SearchPath> {
26 #[cfg(windows)]
27 let separator = ';';
28
29 #[cfg(not(windows))]
30 let separator = ':';
31
32 let paths: Vec<PathBuf> = s
33 .split(separator)
34 .into_iter()
35 .filter(|s| !s.is_empty())
36 .map(|s| Path::new(s).to_path_buf())
37 .collect();
38
39 let error_paths: Vec<PathBuf> = paths
40 .iter()
41 .filter(|path| !path.exists())
42 .map(|path| path.clone())
43 .collect();
44
45 if !error_paths.is_empty() {
46 Err(io::Error::new(
47 io::ErrorKind::NotFound,
48 format!(
49 "Paths not found:\n{}",
50 error_paths
51 .iter()
52 .map(|path| format!(" {:?}", path))
53 .collect::<Vec<String>>()
54 .join("\n")
55 ),
56 ))
57 } else {
58 Ok(SearchPath::new(paths))
59 }
60 }
61
62 pub fn find(&self, path: &Path) -> io::Result<PathBuf> {
63 if path.is_absolute() {
64 if path.exists() {
65 Ok(path.to_path_buf())
66 } else {
67 Err(io::Error::new(
68 io::ErrorKind::NotFound,
69 format!("Path '{:?}' does not exist", path),
70 ))
71 }
72 } else {
73 let result = self.paths.iter().map(|p| p.join(path)).find(|p| p.exists());
74
75 match result {
76 Some(path) => Ok(path),
77 None => Err(io::Error::new(
78 io::ErrorKind::NotFound,
79 format!("Path '{:?}' not found in: {:?}", path, self.paths),
80 )),
81 }
82 }
83 }
84}