clap/
osstringext.rs

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}