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