1#[cfg(any(target_os = "windows", target_arch = "wasm32"))]
2use INVALID_UTF8;
3use std::ffi::OsStr;
4#[cfg(not(any(target_os = "windows", target_arch = "wasm32")))]
5use std::os::unix::ffi::OsStrExt;
6
7#[cfg(any(target_os = "windows", target_arch = "wasm32"))]
8pub trait OsStrExt3 {
9 fn from_bytes(b: &[u8]) -> &Self;
10 fn as_bytes(&self) -> &[u8];
11}
12
13#[doc(hidden)]
14pub trait OsStrExt2 {
15 fn starts_with(&self, s: &[u8]) -> bool;
16 fn split_at_byte(&self, b: u8) -> (&OsStr, &OsStr);
17 fn split_at(&self, i: usize) -> (&OsStr, &OsStr);
18 fn trim_left_matches(&self, b: u8) -> &OsStr;
19 fn contains_byte(&self, b: u8) -> bool;
20 fn split(&self, b: u8) -> OsSplit;
21}
22
23#[cfg(any(target_os = "windows", target_arch = "wasm32"))]
24impl OsStrExt3 for OsStr {
25 fn from_bytes(b: &[u8]) -> &Self {
26 use std::mem;
27 unsafe { mem::transmute(b) }
28 }
29 fn as_bytes(&self) -> &[u8] {
30 self.to_str().map(|s| s.as_bytes()).expect(INVALID_UTF8)
31 }
32}
33
34impl OsStrExt2 for OsStr {
35 fn starts_with(&self, s: &[u8]) -> bool {
36 self.as_bytes().starts_with(s)
37 }
38
39 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
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
63 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
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
85 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)]
96pub struct OsSplit<'a> {
97 sep: u8,
98 val: &'a [u8],
99 pos: usize,
100}
101
102impl<'a> Iterator for OsSplit<'a> {
103 type Item = &'a OsStr;
104
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}