1use std::ffi::OsStr;
2
3use bstr::{BStr, ByteSlice, ByteVec};
4
5use crate::Spec;
6
7impl std::convert::TryFrom<&OsStr> for Spec {
8 type Error = crate::Utf8Error;
9
10 fn try_from(value: &OsStr) -> Result<Self, Self::Error> {
11 crate::os_str_into_bstr(value).map(|value| {
12 assert_valid_hack(value);
13 Spec(value.into())
14 })
15 }
16}
17
18fn assert_valid_hack(input: &BStr) {
19 assert!(!input.contains_str(b"/../"));
20 assert!(!input.contains_str(b"/./"));
21 assert!(!input.starts_with_str(b"../"));
22 assert!(!input.starts_with_str(b"./"));
23 assert!(!input.starts_with_str(b"/"));
24}
25
26impl Spec {
27 pub fn from_bytes(input: &BStr) -> Option<Self> {
30 assert_valid_hack(input);
31 Spec(input.into()).into()
32 }
33 pub fn items(&self) -> impl Iterator<Item = &BStr> {
35 std::iter::once(self.0.as_bstr())
36 }
37 pub fn apply_prefix(&mut self, prefix: &std::path::Path) -> &Self {
40 let prefix = crate::into_bstr(prefix);
42 if !prefix.is_empty() {
43 let mut prefix = crate::to_unix_separators_on_windows(prefix);
44 {
45 let path = prefix.to_mut();
46 path.push_byte(b'/');
47 path.extend_from_slice(&self.0);
48 }
49 self.0 = prefix.into_owned();
50 }
51 self
52 }
53}