os_str_generic/
lib.rs

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/// A single "element" of an OsStr. On windows, this corresponds to a `u16`. On unix-like systems, it
12/// corresponds to a `u8`
13///
14/// Can be compared to another `OsStrElement` or a `&OsStr`.
15#[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/*
76impl<'a> ::std::cmp::PartialEq<&'a str> for OsStrElement {
77    fn eq(&self, rhs: & &'a str) -> bool {
78        rhs.len() == 1 && rhs
79    }
80}
81*/
82
83#[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/// Iterator over the elements of a `&OsStr`
113#[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
126/// Extentions to OsStr that allow working with them without filling code with `#[cfg(...)]`
127pub trait OsStrGenericExt {
128    // type Element;
129
130    /// Iterate over the smallest elements of an OsStr. Element meaning is dependent on specific
131    /// OS.
132    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    /*
173    /* consider this pattern, perhaps in another trait */
174    #[cfg(windows)]
175    type Element = u16;
176    #[cfg(not(windows))]
177    type Element = u8;
178    */
179
180    fn elements(&self) -> OsStrElements {
181        OsStrElements {
182            inner: OsStrElementsInner::from_osstr(self),
183        }
184    }
185}
186
187/*
188#[derive(Debug)]
189struct OsStrSplit {
190}
191
192impl Iterator for OsStrSplit {
193    type Item = &OsStr
194}
195
196fn split_flags(flags: &OsStr) -> OsStrSplit
197{
198
199    for i in flags.elements() {
200        if i == ' ' {
201            
202        }
203    }
204}
205*/