]> git.proxmox.com Git - rustc.git/blob - src/libstd/ffi/os_str.rs
eb5ddecbd054d090700585fc3c9ef971efeaf893
[rustc.git] / src / libstd / ffi / os_str.rs
1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use borrow::{Borrow, Cow, ToOwned};
12 use ffi::CString;
13 use fmt::{self, Debug};
14 use mem;
15 use string::String;
16 use ops;
17 use cmp;
18 use hash::{Hash, Hasher};
19 use vec::Vec;
20
21 use sys::os_str::{Buf, Slice};
22 use sys_common::{AsInner, IntoInner, FromInner};
23
24 /// A type that can represent owned, mutable platform-native strings, but is
25 /// cheaply interconvertable with Rust strings.
26 ///
27 /// The need for this type arises from the fact that:
28 ///
29 /// * On Unix systems, strings are often arbitrary sequences of non-zero
30 /// bytes, in many cases interpreted as UTF-8.
31 ///
32 /// * On Windows, strings are often arbitrary sequences of non-zero 16-bit
33 /// values, interpreted as UTF-16 when it is valid to do so.
34 ///
35 /// * In Rust, strings are always valid UTF-8, but may contain zeros.
36 ///
37 /// `OsString` and `OsStr` bridge this gap by simultaneously representing Rust
38 /// and platform-native string values, and in particular allowing a Rust string
39 /// to be converted into an "OS" string with no cost.
40 #[derive(Clone)]
41 #[stable(feature = "rust1", since = "1.0.0")]
42 pub struct OsString {
43 inner: Buf
44 }
45
46 /// Slices into OS strings (see `OsString`).
47 #[stable(feature = "rust1", since = "1.0.0")]
48 pub struct OsStr {
49 inner: Slice
50 }
51
52 impl OsString {
53 /// Constructs a new empty `OsString`.
54 #[stable(feature = "rust1", since = "1.0.0")]
55 pub fn new() -> OsString {
56 OsString { inner: Buf::from_string(String::new()) }
57 }
58
59 /// Constructs an `OsString` from a byte sequence.
60 ///
61 /// # Platform behavior
62 ///
63 /// On Unix systems, any byte sequence can be successfully
64 /// converted into an `OsString`.
65 ///
66 /// On Windows system, only UTF-8 byte sequences will successfully
67 /// convert; non UTF-8 data will produce `None`.
68 #[unstable(feature = "convert", reason = "recently added", issue = "27704")]
69 #[rustc_deprecated(reason = "RFC was closed, hides subtle Windows semantics",
70 since = "1.6.0")]
71 pub fn from_bytes<B>(bytes: B) -> Option<OsString> where B: Into<Vec<u8>> {
72 Self::_from_bytes(bytes.into())
73 }
74
75 #[cfg(unix)]
76 fn _from_bytes(vec: Vec<u8>) -> Option<OsString> {
77 use os::unix::ffi::OsStringExt;
78 Some(OsString::from_vec(vec))
79 }
80
81 #[cfg(windows)]
82 fn _from_bytes(vec: Vec<u8>) -> Option<OsString> {
83 String::from_utf8(vec).ok().map(OsString::from)
84 }
85
86 /// Converts to an `OsStr` slice.
87 #[stable(feature = "rust1", since = "1.0.0")]
88 pub fn as_os_str(&self) -> &OsStr {
89 self
90 }
91
92 /// Converts the `OsString` into a `String` if it contains valid Unicode data.
93 ///
94 /// On failure, ownership of the original `OsString` is returned.
95 #[stable(feature = "rust1", since = "1.0.0")]
96 pub fn into_string(self) -> Result<String, OsString> {
97 self.inner.into_string().map_err(|buf| OsString { inner: buf} )
98 }
99
100 /// Extends the string with the given `&OsStr` slice.
101 #[stable(feature = "rust1", since = "1.0.0")]
102 pub fn push<T: AsRef<OsStr>>(&mut self, s: T) {
103 self.inner.push_slice(&s.as_ref().inner)
104 }
105 }
106
107 #[stable(feature = "rust1", since = "1.0.0")]
108 impl From<String> for OsString {
109 fn from(s: String) -> OsString {
110 OsString { inner: Buf::from_string(s) }
111 }
112 }
113
114 #[stable(feature = "rust1", since = "1.0.0")]
115 impl<'a, T: ?Sized + AsRef<OsStr>> From<&'a T> for OsString {
116 fn from(s: &'a T) -> OsString {
117 s.as_ref().to_os_string()
118 }
119 }
120
121 #[stable(feature = "rust1", since = "1.0.0")]
122 impl ops::Index<ops::RangeFull> for OsString {
123 type Output = OsStr;
124
125 #[inline]
126 fn index(&self, _index: ops::RangeFull) -> &OsStr {
127 OsStr::from_inner(self.inner.as_slice())
128 }
129 }
130
131 #[stable(feature = "rust1", since = "1.0.0")]
132 impl ops::Deref for OsString {
133 type Target = OsStr;
134
135 #[inline]
136 fn deref(&self) -> &OsStr {
137 &self[..]
138 }
139 }
140
141 #[stable(feature = "rust1", since = "1.0.0")]
142 impl Debug for OsString {
143 fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
144 fmt::Debug::fmt(&**self, formatter)
145 }
146 }
147
148 #[stable(feature = "rust1", since = "1.0.0")]
149 impl PartialEq for OsString {
150 fn eq(&self, other: &OsString) -> bool {
151 &**self == &**other
152 }
153 }
154
155 #[stable(feature = "rust1", since = "1.0.0")]
156 impl PartialEq<str> for OsString {
157 fn eq(&self, other: &str) -> bool {
158 &**self == other
159 }
160 }
161
162 #[stable(feature = "rust1", since = "1.0.0")]
163 impl PartialEq<OsString> for str {
164 fn eq(&self, other: &OsString) -> bool {
165 &**other == self
166 }
167 }
168
169 #[stable(feature = "rust1", since = "1.0.0")]
170 impl Eq for OsString {}
171
172 #[stable(feature = "rust1", since = "1.0.0")]
173 impl PartialOrd for OsString {
174 #[inline]
175 fn partial_cmp(&self, other: &OsString) -> Option<cmp::Ordering> {
176 (&**self).partial_cmp(&**other)
177 }
178 #[inline]
179 fn lt(&self, other: &OsString) -> bool { &**self < &**other }
180 #[inline]
181 fn le(&self, other: &OsString) -> bool { &**self <= &**other }
182 #[inline]
183 fn gt(&self, other: &OsString) -> bool { &**self > &**other }
184 #[inline]
185 fn ge(&self, other: &OsString) -> bool { &**self >= &**other }
186 }
187
188 #[stable(feature = "rust1", since = "1.0.0")]
189 impl PartialOrd<str> for OsString {
190 #[inline]
191 fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
192 (&**self).partial_cmp(other)
193 }
194 }
195
196 #[stable(feature = "rust1", since = "1.0.0")]
197 impl Ord for OsString {
198 #[inline]
199 fn cmp(&self, other: &OsString) -> cmp::Ordering {
200 (&**self).cmp(&**other)
201 }
202 }
203
204 #[stable(feature = "rust1", since = "1.0.0")]
205 impl Hash for OsString {
206 #[inline]
207 fn hash<H: Hasher>(&self, state: &mut H) {
208 (&**self).hash(state)
209 }
210 }
211
212 impl OsStr {
213 /// Coerces into an `OsStr` slice.
214 #[stable(feature = "rust1", since = "1.0.0")]
215 pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &OsStr {
216 s.as_ref()
217 }
218
219 fn from_inner(inner: &Slice) -> &OsStr {
220 unsafe { mem::transmute(inner) }
221 }
222
223 /// Yields a `&str` slice if the `OsStr` is valid unicode.
224 ///
225 /// This conversion may entail doing a check for UTF-8 validity.
226 #[stable(feature = "rust1", since = "1.0.0")]
227 pub fn to_str(&self) -> Option<&str> {
228 self.inner.to_str()
229 }
230
231 /// Converts an `OsStr` to a `Cow<str>`.
232 ///
233 /// Any non-Unicode sequences are replaced with U+FFFD REPLACEMENT CHARACTER.
234 #[stable(feature = "rust1", since = "1.0.0")]
235 pub fn to_string_lossy(&self) -> Cow<str> {
236 self.inner.to_string_lossy()
237 }
238
239 /// Copies the slice into an owned `OsString`.
240 #[stable(feature = "rust1", since = "1.0.0")]
241 pub fn to_os_string(&self) -> OsString {
242 OsString { inner: self.inner.to_owned() }
243 }
244
245 /// Yields this `OsStr` as a byte slice.
246 ///
247 /// # Platform behavior
248 ///
249 /// On Unix systems, this is a no-op.
250 ///
251 /// On Windows systems, this returns `None` unless the `OsStr` is
252 /// valid unicode, in which case it produces UTF-8-encoded
253 /// data. This may entail checking validity.
254 #[unstable(feature = "convert", reason = "recently added", issue = "27704")]
255 #[rustc_deprecated(reason = "RFC was closed, hides subtle Windows semantics",
256 since = "1.6.0")]
257 pub fn to_bytes(&self) -> Option<&[u8]> {
258 if cfg!(windows) {
259 self.to_str().map(|s| s.as_bytes())
260 } else {
261 Some(self.bytes())
262 }
263 }
264
265 /// Creates a `CString` containing this `OsStr` data.
266 ///
267 /// Fails if the `OsStr` contains interior nulls.
268 ///
269 /// This is a convenience for creating a `CString` from
270 /// `self.to_bytes()`, and inherits the platform behavior of the
271 /// `to_bytes` method.
272 #[unstable(feature = "convert", reason = "recently added", issue = "27704")]
273 #[rustc_deprecated(reason = "RFC was closed, hides subtle Windows semantics",
274 since = "1.6.0")]
275 #[allow(deprecated)]
276 pub fn to_cstring(&self) -> Option<CString> {
277 self.to_bytes().and_then(|b| CString::new(b).ok())
278 }
279
280 /// Gets the underlying byte representation.
281 ///
282 /// Note: it is *crucial* that this API is private, to avoid
283 /// revealing the internal, platform-specific encodings.
284 fn bytes(&self) -> &[u8] {
285 unsafe { mem::transmute(&self.inner) }
286 }
287 }
288
289 #[stable(feature = "rust1", since = "1.0.0")]
290 impl PartialEq for OsStr {
291 fn eq(&self, other: &OsStr) -> bool {
292 self.bytes().eq(other.bytes())
293 }
294 }
295
296 #[stable(feature = "rust1", since = "1.0.0")]
297 impl PartialEq<str> for OsStr {
298 fn eq(&self, other: &str) -> bool {
299 *self == *OsStr::new(other)
300 }
301 }
302
303 #[stable(feature = "rust1", since = "1.0.0")]
304 impl PartialEq<OsStr> for str {
305 fn eq(&self, other: &OsStr) -> bool {
306 *other == *OsStr::new(self)
307 }
308 }
309
310 #[stable(feature = "rust1", since = "1.0.0")]
311 impl Eq for OsStr {}
312
313 #[stable(feature = "rust1", since = "1.0.0")]
314 impl PartialOrd for OsStr {
315 #[inline]
316 fn partial_cmp(&self, other: &OsStr) -> Option<cmp::Ordering> {
317 self.bytes().partial_cmp(other.bytes())
318 }
319 #[inline]
320 fn lt(&self, other: &OsStr) -> bool { self.bytes().lt(other.bytes()) }
321 #[inline]
322 fn le(&self, other: &OsStr) -> bool { self.bytes().le(other.bytes()) }
323 #[inline]
324 fn gt(&self, other: &OsStr) -> bool { self.bytes().gt(other.bytes()) }
325 #[inline]
326 fn ge(&self, other: &OsStr) -> bool { self.bytes().ge(other.bytes()) }
327 }
328
329 #[stable(feature = "rust1", since = "1.0.0")]
330 impl PartialOrd<str> for OsStr {
331 #[inline]
332 fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
333 self.partial_cmp(OsStr::new(other))
334 }
335 }
336
337 // FIXME (#19470): cannot provide PartialOrd<OsStr> for str until we
338 // have more flexible coherence rules.
339
340 #[stable(feature = "rust1", since = "1.0.0")]
341 impl Ord for OsStr {
342 #[inline]
343 fn cmp(&self, other: &OsStr) -> cmp::Ordering { self.bytes().cmp(other.bytes()) }
344 }
345
346 #[stable(feature = "rust1", since = "1.0.0")]
347 impl Hash for OsStr {
348 #[inline]
349 fn hash<H: Hasher>(&self, state: &mut H) {
350 self.bytes().hash(state)
351 }
352 }
353
354 #[stable(feature = "rust1", since = "1.0.0")]
355 impl Debug for OsStr {
356 fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
357 self.inner.fmt(formatter)
358 }
359 }
360
361 #[stable(feature = "rust1", since = "1.0.0")]
362 impl Borrow<OsStr> for OsString {
363 fn borrow(&self) -> &OsStr { &self[..] }
364 }
365
366 #[stable(feature = "rust1", since = "1.0.0")]
367 impl ToOwned for OsStr {
368 type Owned = OsString;
369 fn to_owned(&self) -> OsString { self.to_os_string() }
370 }
371
372 #[stable(feature = "rust1", since = "1.0.0")]
373 impl AsRef<OsStr> for OsStr {
374 fn as_ref(&self) -> &OsStr {
375 self
376 }
377 }
378
379 #[stable(feature = "rust1", since = "1.0.0")]
380 impl AsRef<OsStr> for OsString {
381 fn as_ref(&self) -> &OsStr {
382 self
383 }
384 }
385
386 #[stable(feature = "rust1", since = "1.0.0")]
387 impl AsRef<OsStr> for str {
388 fn as_ref(&self) -> &OsStr {
389 OsStr::from_inner(Slice::from_str(self))
390 }
391 }
392
393 #[stable(feature = "rust1", since = "1.0.0")]
394 impl AsRef<OsStr> for String {
395 fn as_ref(&self) -> &OsStr {
396 (&**self).as_ref()
397 }
398 }
399
400 impl FromInner<Buf> for OsString {
401 fn from_inner(buf: Buf) -> OsString {
402 OsString { inner: buf }
403 }
404 }
405
406 impl IntoInner<Buf> for OsString {
407 fn into_inner(self) -> Buf {
408 self.inner
409 }
410 }
411
412 impl AsInner<Slice> for OsStr {
413 fn as_inner(&self) -> &Slice {
414 &self.inner
415 }
416 }