1 #[cfg(target_os = "windows")]
2 use INVALID_UTF8;
3 use std::ffi::OsStr;
4 #[cfg(not(target_os = "windows"))]
5 use std::os::unix::ffi::OsStrExt;
6 
7 #[cfg(target_os = "windows")]
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;
len_(&self) -> usize19     fn len_(&self) -> usize;
contains_byte(&self, b: u8) -> bool20     fn contains_byte(&self, b: u8) -> bool;
is_empty_(&self) -> bool21     fn is_empty_(&self) -> bool;
split(&self, b: u8) -> OsSplit22     fn split(&self, b: u8) -> OsSplit;
23 }
24 
25 #[cfg(target_os = "windows")]
26 impl OsStrExt3 for OsStr {
from_bytes(b: &[u8]) -> &Self27     fn from_bytes(b: &[u8]) -> &Self {
28         use std::mem;
29         unsafe { mem::transmute(b) }
30     }
as_bytes(&self) -> &[u8]31     fn as_bytes(&self) -> &[u8] { self.to_str().map(|s| s.as_bytes()).expect(INVALID_UTF8) }
32 }
33 
34 impl OsStrExt2 for OsStr {
starts_with(&self, s: &[u8]) -> bool35     fn starts_with(&self, s: &[u8]) -> bool { self.as_bytes().starts_with(s) }
36 
is_empty_(&self) -> bool37     fn is_empty_(&self) -> bool { self.as_bytes().is_empty() }
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 
len_(&self) -> usize85     fn len_(&self) -> usize { self.as_bytes().len() }
86 
split(&self, b: u8) -> OsSplit87     fn split(&self, b: u8) -> OsSplit {
88         OsSplit {
89             sep: b,
90             val: self.as_bytes(),
91             pos: 0,
92         }
93     }
94 }
95 
96 #[doc(hidden)]
97 #[derive(Clone, Debug)]
98 pub struct OsSplit<'a> {
99     sep: u8,
100     val: &'a [u8],
101     pos: usize,
102 }
103 
104 impl<'a> Iterator for OsSplit<'a> {
105     type Item = &'a OsStr;
106 
next(&mut self) -> Option<&'a OsStr>107     fn next(&mut self) -> Option<&'a OsStr> {
108         debugln!("OsSplit::next: self={:?}", self);
109         if self.pos == self.val.len() {
110             return None;
111         }
112         let start = self.pos;
113         for b in &self.val[start..] {
114             self.pos += 1;
115             if *b == self.sep {
116                 return Some(OsStr::from_bytes(&self.val[start..self.pos - 1]));
117             }
118         }
119         Some(OsStr::from_bytes(&self.val[start..]))
120     }
size_hint(&self) -> (usize, Option<usize>)121     fn size_hint(&self) -> (usize, Option<usize>) {
122         let mut count = 0;
123         for b in &self.val[self.pos..] {
124             if *b == self.sep {
125                 count += 1;
126             }
127         }
128         if count > 0 {
129             return (count, Some(count));
130         }
131         (0, None)
132     }
133 }
134 
135 impl<'a> DoubleEndedIterator for OsSplit<'a> {
next_back(&mut self) -> Option<&'a OsStr>136     fn next_back(&mut self) -> Option<&'a OsStr> {
137         if self.pos == 0 {
138             return None;
139         }
140         let start = self.pos;
141         for b in self.val[..self.pos].iter().rev() {
142             self.pos -= 1;
143             if *b == self.sep {
144                 return Some(OsStr::from_bytes(&self.val[self.pos + 1..start]));
145             }
146         }
147         Some(OsStr::from_bytes(&self.val[..start]))
148     }
149 }
150