1 #[cfg(any(target_os = "windows", target_arch = "wasm32"))]
2 use INVALID_UTF8;
3 use std::ffi::OsStr;
4 #[cfg(not(any(target_os = "windows", target_arch = "wasm32")))]
5 use std::os::unix::ffi::OsStrExt;
6 
7 #[cfg(any(target_os = "windows", target_arch = "wasm32"))]
8 pub trait OsStrExt3 {
from_bytes(b: &[u8]) -> &Self9     fn from_bytes(b: &[u8]) -> &Self;
as_bytes(&self) -> &[u8]10     fn as_bytes(&self) -> &[u8];
11 }
12 
13 #[doc(hidden)]
14 pub trait OsStrExt2 {
starts_with(&self, s: &[u8]) -> bool15     fn starts_with(&self, s: &[u8]) -> bool;
split_at_byte(&self, b: u8) -> (&OsStr, &OsStr)16     fn split_at_byte(&self, b: u8) -> (&OsStr, &OsStr);
split_at(&self, i: usize) -> (&OsStr, &OsStr)17     fn split_at(&self, i: usize) -> (&OsStr, &OsStr);
trim_left_matches(&self, b: u8) -> &OsStr18     fn trim_left_matches(&self, b: u8) -> &OsStr;
contains_byte(&self, b: u8) -> bool19     fn contains_byte(&self, b: u8) -> bool;
split(&self, b: u8) -> OsSplit20     fn split(&self, b: u8) -> OsSplit;
21 }
22 
23 #[cfg(any(target_os = "windows", target_arch = "wasm32"))]
24 impl OsStrExt3 for OsStr {
from_bytes(b: &[u8]) -> &Self25     fn from_bytes(b: &[u8]) -> &Self {
26         use std::mem;
27         unsafe { mem::transmute(b) }
28     }
as_bytes(&self) -> &[u8]29     fn as_bytes(&self) -> &[u8] {
30         self.to_str().map(|s| s.as_bytes()).expect(INVALID_UTF8)
31     }
32 }
33 
34 impl OsStrExt2 for OsStr {
starts_with(&self, s: &[u8]) -> bool35     fn starts_with(&self, s: &[u8]) -> bool {
36         self.as_bytes().starts_with(s)
37     }
38 
contains_byte(&self, byte: u8) -> bool39     fn contains_byte(&self, byte: u8) -> bool {
40         for b in self.as_bytes() {
41             if b == &byte {
42                 return true;
43             }
44         }
45         false
46     }
47 
split_at_byte(&self, byte: u8) -> (&OsStr, &OsStr)48     fn split_at_byte(&self, byte: u8) -> (&OsStr, &OsStr) {
49         for (i, b) in self.as_bytes().iter().enumerate() {
50             if b == &byte {
51                 return (
52                     OsStr::from_bytes(&self.as_bytes()[..i]),
53                     OsStr::from_bytes(&self.as_bytes()[i + 1..]),
54                 );
55             }
56         }
57         (
58             &*self,
59             OsStr::from_bytes(&self.as_bytes()[self.len()..self.len()]),
60         )
61     }
62 
trim_left_matches(&self, byte: u8) -> &OsStr63     fn trim_left_matches(&self, byte: u8) -> &OsStr {
64         let mut found = false;
65         for (i, b) in self.as_bytes().iter().enumerate() {
66             if b != &byte {
67                 return OsStr::from_bytes(&self.as_bytes()[i..]);
68             } else {
69                 found = true;
70             }
71         }
72         if found {
73             return OsStr::from_bytes(&self.as_bytes()[self.len()..]);
74         }
75         &*self
76     }
77 
split_at(&self, i: usize) -> (&OsStr, &OsStr)78     fn split_at(&self, i: usize) -> (&OsStr, &OsStr) {
79         (
80             OsStr::from_bytes(&self.as_bytes()[..i]),
81             OsStr::from_bytes(&self.as_bytes()[i..]),
82         )
83     }
84 
split(&self, b: u8) -> OsSplit85     fn split(&self, b: u8) -> OsSplit {
86         OsSplit {
87             sep: b,
88             val: self.as_bytes(),
89             pos: 0,
90         }
91     }
92 }
93 
94 #[doc(hidden)]
95 #[derive(Clone, Debug)]
96 pub struct OsSplit<'a> {
97     sep: u8,
98     val: &'a [u8],
99     pos: usize,
100 }
101 
102 impl<'a> Iterator for OsSplit<'a> {
103     type Item = &'a OsStr;
104 
next(&mut self) -> Option<&'a OsStr>105     fn next(&mut self) -> Option<&'a OsStr> {
106         debugln!("OsSplit::next: self={:?}", self);
107         if self.pos == self.val.len() {
108             return None;
109         }
110         let start = self.pos;
111         for b in &self.val[start..] {
112             self.pos += 1;
113             if *b == self.sep {
114                 return Some(OsStr::from_bytes(&self.val[start..self.pos - 1]));
115             }
116         }
117         Some(OsStr::from_bytes(&self.val[start..]))
118     }
119 }
120