1use std::ffi::{OsStr, OsString};
2use std::iter::FromIterator;
3use std::ascii::AsciiExt;
4
5#[cfg(windows)]
6type Elem = u16;
7
8#[cfg(not(windows))]
9type Elem = u8;
10
11#[derive(Debug, Clone, PartialEq, Eq, Copy)]
16pub struct OsStrElement {
17 inner: Elem
18}
19
20impl OsStrElement {
21 pub fn raw(&self) -> Elem {
22 self.inner
23 }
24
25 #[cfg(windows)]
26 fn as_os_string_inner(&self) -> OsString {
27 use std::os::windows::ffi::OsStringExt;
28 let v = [self.inner];
29 OsString::from_wide(&v[..])
30 }
31
32 #[cfg(not(windows))]
33 fn as_os_string_inner(&self) -> OsString {
34 use std::os::unix::ffi::OsStringExt;
35 let v = vec![self.inner];
36 OsString::from_vec(v)
37 }
38
39 pub fn as_os_string(&self) -> OsString {
40 self.as_os_string_inner()
41 }
42}
43
44impl<'a> ::std::cmp::PartialEq<&'a OsStr> for OsStrElement {
45 fn eq(&self, rhs: & &'a OsStr) -> bool {
46 rhs.len() == 1 && rhs.elements().next().unwrap().inner == self.inner
47 }
48}
49
50impl ::std::cmp::PartialEq<char> for OsStrElement {
51 fn eq(&self, rhs: &char) -> bool {
52 rhs.is_ascii() && self.inner as u8 == *rhs as u8
53 }
54}
55
56impl ::std::cmp::PartialEq<u8> for OsStrElement {
57 fn eq(&self, rhs: &u8) -> bool {
58 self.inner == self.inner as u8 as Elem && self.inner as u8 == *rhs
59 }
60}
61
62impl FromIterator<OsStrElement> for OsString {
63 fn from_iter<T>(iter: T) -> OsString
64 where T: IntoIterator<Item=OsStrElement>
65 {
66 let mut s = OsString::new();
67 for i in iter.into_iter() {
68 s.push(i.as_os_string())
69 }
70
71 s
72 }
73}
74
75#[cfg(windows)]
84#[derive(Clone)]
85struct OsStrElementsInner<'a>(::std::os::windows::ffi::EncodeWide<'a>);
86
87#[cfg(windows)]
88impl<'a> ::std::fmt::Debug for OsStrElementsInner<'a> {
89 fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
90 f.debug_struct("OsStrElementsInner").finish()
91 }
92}
93
94#[cfg(not(windows))]
95#[derive(Debug, Clone)]
96struct OsStrElementsInner<'a>(std::iter::Cloned<std::slice::Iter<'a, u8>>);
97
98impl<'a> OsStrElementsInner<'a> {
99 #[cfg(windows)]
100 fn from_osstr(i: &'a OsStr) -> OsStrElementsInner<'a> {
101 use std::os::windows::ffi::OsStrExt;
102 OsStrElementsInner(i.encode_wide())
103 }
104
105 #[cfg(not(windows))]
106 fn from_osstr(i: &'a OsStr) -> OsStrElementsInner<'a> {
107 use std::os::unix::ffi::OsStrExt;
108 OsStrElementsInner(i.as_bytes().iter().cloned())
109 }
110}
111
112#[derive(Debug, Clone)]
114pub struct OsStrElements<'a> {
115 inner: OsStrElementsInner<'a>,
116}
117
118impl<'a> Iterator for OsStrElements<'a> {
119 type Item = OsStrElement;
120
121 fn next(&mut self) -> Option<OsStrElement> {
122 self.inner.0.next().map(|x| OsStrElement { inner: x })
123 }
124}
125
126pub trait OsStrGenericExt {
128 fn elements(&self) -> OsStrElements;
133
134 fn starts_with<T: AsRef<OsStr>>(&self, prefix: T) -> bool {
135 let mut ei = self.elements();
136 let mut pi = prefix.as_ref().elements();
137 loop {
138 let e = ei.next();
139 let p = pi.next();
140 match (e, p) {
141 (Some(_), None) => return true,
142 (None, None) => return true,
143 (None, Some(_)) => return false,
144 (Some(c1), Some(c2)) => if c1 != c2 { return false }
145 }
146 }
147 }
148
149 fn without_prefix<T: AsRef<OsStr>>(&self, prefix: T) -> Option<OsString> {
150 let mut ei = self.elements().peekable();
151 let mut pi = prefix.as_ref().elements();
152 loop {
153 {
154 let e = ei.peek();
155 let p = pi.next();
156 match (e, p) {
157 (Some(_), None) => break,
158 (None, None) => break,
159 (None, Some(_)) => return None,
160 (Some(c1), Some(c2)) => if c1.clone() != c2 { return None }
161 }
162 }
163
164 ei.next();
165 }
166
167 Some(ei.collect())
168 }
169}
170
171impl OsStrGenericExt for OsStr {
172 fn elements(&self) -> OsStrElements {
181 OsStrElements {
182 inner: OsStrElementsInner::from_osstr(self),
183 }
184 }
185}
186
187