-
Notifications
You must be signed in to change notification settings - Fork 0
/
path_reroot.rs
122 lines (110 loc) · 3.61 KB
/
path_reroot.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
//! Export the `struct` [`PathReRoot`]. Given an iterator over items of type [PathBuf]
//! rewrite the root of those that contains a given prefix, by using another one
//! given as a replacement.
use std::path::{Path, PathBuf, StripPrefixError};
/// function that performs the prefix replacement
/// can fail if `Path::strip_prefix` fails
/// `Path::strip_prefix` may fail if `base` is not a prefix of `path`
fn path_re_root<P>(path: P, base: P, replace_by: P) -> Result<PathBuf, StripPrefixError>
where
P: AsRef<Path>,
{
match path.as_ref().strip_prefix(base) {
Ok(rest) => Ok(replace_by.as_ref().join(rest)),
Err(e) => Err(e),
}
}
/// Given an iterator over items of type [PathBuf] rewrite the root of those that
/// contains a given prefix, by using another one given as a replacement.
///
/// **This iterator will yield tuples** where the first element is the original
/// path ([PathBuf]) and the second is a `Result` with the new [PathBuf].
pub struct PathReRoot<I, P>
where
P: AsRef<Path>,
I: Iterator<Item = PathBuf>,
{
pub inner_iter: I,
pub strip_prefix: P,
pub replace_by: P,
}
impl<I, P> Iterator for PathReRoot<I, P>
where
I: Iterator<Item = PathBuf>,
P: AsRef<Path>,
{
/// Item is a tuple where the first element is the original path
/// and the second one is the result of the re root operation
type Item = (PathBuf, Result<PathBuf, StripPrefixError>);
fn next(&mut self) -> Option<Self::Item> {
match self.inner_iter.next() {
Some(p) => {
let rooted = path_re_root(
p.as_path(),
self.strip_prefix.as_ref(),
self.replace_by.as_ref(),
);
Some((p, rooted))
}
None => None,
}
}
}
#[cfg(test)]
mod test {
use std::path::{Path, PathBuf};
use super::path_re_root;
struct Subject<P: AsRef<Path>> {
path: P,
strip_prefix: P,
replace_prefix: P,
expect: Option<PathBuf>,
}
#[test]
fn re_root_fn() {
let subjects = [
Subject {
path: "/a/b/c/d",
strip_prefix: "/a/b",
replace_prefix: "/x/y",
expect: Some(PathBuf::from("/x/y/c/d")),
},
// prefix can be erased from the target by passing an
// empty string as `replace_by`
Subject {
path: "/a/b/c/d",
strip_prefix: "/a/b",
replace_prefix: "",
expect: Some(PathBuf::from("c/d")),
},
// not a valid prefix
Subject {
path: "/a/b/c/d",
strip_prefix: "/c/d",
replace_prefix: "",
expect: None,
},
// mismatch: target path is relative, given prefix is absolute
Subject {
path: "./c/d",
strip_prefix: "/c/d",
replace_prefix: "",
expect: None,
},
// mismatch: target path is absolute, given prefix is relative
Subject {
path: "/c/d",
strip_prefix: ".c/d",
replace_prefix: "",
expect: None,
},
];
for subject in subjects {
let res = path_re_root(subject.path, subject.strip_prefix, subject.replace_prefix);
match subject.expect.is_some() {
true => assert_eq!(res, Result::Ok(subject.expect.unwrap())),
false => assert!(res.is_err()),
}
}
}
}