1use std::borrow::Cow;
2
3use bstr::{ByteSlice, ByteVec};
4
5pub(crate) fn file_name<'a>(path: &Cow<'a, [u8]>) -> Option<Cow<'a, [u8]>> {
10 if path.last_byte().map_or(true, |b| b == b'.') {
11 return None;
12 }
13 let last_slash = path.rfind_byte(b'/').map(|i| i + 1).unwrap_or(0);
14 Some(match *path {
15 Cow::Borrowed(path) => Cow::Borrowed(&path[last_slash..]),
16 Cow::Owned(ref path) => {
17 let mut path = path.clone();
18 path.drain_bytes(..last_slash);
19 Cow::Owned(path)
20 }
21 })
22}
23
24pub(crate) fn file_name_ext<'a>(
41 name: &Cow<'a, [u8]>,
42) -> Option<Cow<'a, [u8]>> {
43 if name.is_empty() {
44 return None;
45 }
46 let last_dot_at = match name.rfind_byte(b'.') {
47 None => return None,
48 Some(i) => i,
49 };
50 Some(match *name {
51 Cow::Borrowed(name) => Cow::Borrowed(&name[last_dot_at..]),
52 Cow::Owned(ref name) => {
53 let mut name = name.clone();
54 name.drain_bytes(..last_dot_at);
55 Cow::Owned(name)
56 }
57 })
58}
59
60#[cfg(unix)]
63pub(crate) fn normalize_path(path: Cow<'_, [u8]>) -> Cow<'_, [u8]> {
64 path
66}
67
68#[cfg(not(unix))]
71pub(crate) fn normalize_path(mut path: Cow<[u8]>) -> Cow<[u8]> {
72 use std::path::is_separator;
73
74 for i in 0..path.len() {
75 if path[i] == b'/' || !is_separator(char::from(path[i])) {
76 continue;
77 }
78 path.to_mut()[i] = b'/';
79 }
80 path
81}
82
83#[cfg(test)]
84mod tests {
85 use std::borrow::Cow;
86
87 use bstr::{ByteVec, B};
88
89 use super::{file_name_ext, normalize_path};
90
91 macro_rules! ext {
92 ($name:ident, $file_name:expr, $ext:expr) => {
93 #[test]
94 fn $name() {
95 let bs = Vec::from($file_name);
96 let got = file_name_ext(&Cow::Owned(bs));
97 assert_eq!($ext.map(|s| Cow::Borrowed(B(s))), got);
98 }
99 };
100 }
101
102 ext!(ext1, "foo.rs", Some(".rs"));
103 ext!(ext2, ".rs", Some(".rs"));
104 ext!(ext3, "..rs", Some(".rs"));
105 ext!(ext4, "", None::<&str>);
106 ext!(ext5, "foo", None::<&str>);
107
108 macro_rules! normalize {
109 ($name:ident, $path:expr, $expected:expr) => {
110 #[test]
111 fn $name() {
112 let bs = Vec::from_slice($path);
113 let got = normalize_path(Cow::Owned(bs));
114 assert_eq!($expected.to_vec(), got.into_owned());
115 }
116 };
117 }
118
119 normalize!(normal1, b"foo", b"foo");
120 normalize!(normal2, b"foo/bar", b"foo/bar");
121 #[cfg(unix)]
122 normalize!(normal3, b"foo\\bar", b"foo\\bar");
123 #[cfg(not(unix))]
124 normalize!(normal3, b"foo\\bar", b"foo/bar");
125 #[cfg(unix)]
126 normalize!(normal4, b"foo\\bar/baz", b"foo\\bar/baz");
127 #[cfg(not(unix))]
128 normalize!(normal4, b"foo\\bar/baz", b"foo/bar/baz");
129}