]>
Commit | Line | Data |
---|---|---|
85aaf69f SL |
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 | ||
9e0c209e | 11 | use borrow::{Borrow, Cow}; |
041b39d2 | 12 | use fmt; |
85aaf69f SL |
13 | use ops; |
14 | use cmp; | |
15 | use hash::{Hash, Hasher}; | |
ff7c6d11 XL |
16 | use rc::Rc; |
17 | use sync::Arc; | |
85aaf69f SL |
18 | |
19 | use sys::os_str::{Buf, Slice}; | |
20 | use sys_common::{AsInner, IntoInner, FromInner}; | |
85aaf69f | 21 | |
9cc50fc6 | 22 | /// A type that can represent owned, mutable platform-native strings, but is |
54a0048b | 23 | /// cheaply inter-convertible with Rust strings. |
9cc50fc6 SL |
24 | /// |
25 | /// The need for this type arises from the fact that: | |
26 | /// | |
27 | /// * On Unix systems, strings are often arbitrary sequences of non-zero | |
28 | /// bytes, in many cases interpreted as UTF-8. | |
29 | /// | |
30 | /// * On Windows, strings are often arbitrary sequences of non-zero 16-bit | |
31 | /// values, interpreted as UTF-16 when it is valid to do so. | |
32 | /// | |
041b39d2 | 33 | /// * In Rust, strings are always valid UTF-8, which may contain zeros. |
9cc50fc6 | 34 | /// |
32a655c1 | 35 | /// `OsString` and [`OsStr`] bridge this gap by simultaneously representing Rust |
9cc50fc6 | 36 | /// and platform-native string values, and in particular allowing a Rust string |
abe05a73 XL |
37 | /// to be converted into an "OS" string with no cost if possible. |
38 | /// | |
2c00a5a8 | 39 | /// `OsString` is to [`&OsStr`] as [`String`] is to [`&str`]: the former |
abe05a73 XL |
40 | /// in each pair are owned strings; the latter are borrowed |
41 | /// references. | |
42 | /// | |
43 | /// # Creating an `OsString` | |
44 | /// | |
45 | /// **From a Rust string**: `OsString` implements | |
46 | /// [`From`]`<`[`String`]`>`, so you can use `my_string.from` to | |
47 | /// create an `OsString` from a normal Rust string. | |
48 | /// | |
49 | /// **From slices:** Just like you can start with an empty Rust | |
50 | /// [`String`] and then [`push_str`][String.push_str] `&str` | |
51 | /// sub-string slices into it, you can create an empty `OsString` with | |
52 | /// the [`new`] method and then push string slices into it with the | |
53 | /// [`push`] method. | |
54 | /// | |
55 | /// # Extracting a borrowed reference to the whole OS string | |
56 | /// | |
57 | /// You can use the [`as_os_str`] method to get an `&`[`OsStr`] from | |
58 | /// an `OsString`; this is effectively a borrowed reference to the | |
59 | /// whole string. | |
60 | /// | |
61 | /// # Conversions | |
62 | /// | |
63 | /// See the [module's toplevel documentation about conversions][conversions] for a discussion on | |
64 | /// the traits which `OsString` implements for conversions from/to native representations. | |
32a655c1 SL |
65 | /// |
66 | /// [`OsStr`]: struct.OsStr.html | |
2c00a5a8 | 67 | /// [`&OsStr`]: struct.OsStr.html |
abe05a73 XL |
68 | /// [`From`]: ../convert/trait.From.html |
69 | /// [`String`]: ../string/struct.String.html | |
70 | /// [`&str`]: ../primitive.str.html | |
71 | /// [`u8`]: ../primitive.u8.html | |
72 | /// [`u16`]: ../primitive.u16.html | |
73 | /// [String.push_str]: ../string/struct.String.html#method.push_str | |
74 | /// [`new`]: #method.new | |
75 | /// [`push`]: #method.push | |
76 | /// [`as_os_str`]: #method.as_os_str | |
85aaf69f | 77 | #[derive(Clone)] |
c34b1796 | 78 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
79 | pub struct OsString { |
80 | inner: Buf | |
81 | } | |
82 | ||
abe05a73 XL |
83 | /// Borrowed reference to an OS string (see [`OsString`]). |
84 | /// | |
85 | /// This type represents a borrowed reference to a string in the operating system's preferred | |
86 | /// representation. | |
87 | /// | |
2c00a5a8 | 88 | /// `&OsStr` is to [`OsString`] as [`&str`] is to [`String`]: the former in each pair are borrowed |
abe05a73 XL |
89 | /// references; the latter are owned strings. |
90 | /// | |
91 | /// See the [module's toplevel documentation about conversions][conversions] for a discussion on | |
92 | /// the traits which `OsStr` implements for conversions from/to native representations. | |
32a655c1 SL |
93 | /// |
94 | /// [`OsString`]: struct.OsString.html | |
2c00a5a8 XL |
95 | /// [`&str`]: ../primitive.str.html |
96 | /// [`String`]: ../string/struct.String.html | |
abe05a73 | 97 | /// [conversions]: index.html#conversions |
c34b1796 | 98 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
99 | pub struct OsStr { |
100 | inner: Slice | |
101 | } | |
102 | ||
103 | impl OsString { | |
85aaf69f | 104 | /// Constructs a new empty `OsString`. |
32a655c1 SL |
105 | /// |
106 | /// # Examples | |
107 | /// | |
108 | /// ``` | |
109 | /// use std::ffi::OsString; | |
110 | /// | |
111 | /// let os_string = OsString::new(); | |
112 | /// ``` | |
c34b1796 | 113 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
114 | pub fn new() -> OsString { |
115 | OsString { inner: Buf::from_string(String::new()) } | |
116 | } | |
117 | ||
32a655c1 SL |
118 | /// Converts to an [`OsStr`] slice. |
119 | /// | |
120 | /// [`OsStr`]: struct.OsStr.html | |
121 | /// | |
122 | /// # Examples | |
123 | /// | |
124 | /// ``` | |
125 | /// use std::ffi::{OsString, OsStr}; | |
126 | /// | |
127 | /// let os_string = OsString::from("foo"); | |
128 | /// let os_str = OsStr::new("foo"); | |
129 | /// assert_eq!(os_string.as_os_str(), os_str); | |
130 | /// ``` | |
c34b1796 AL |
131 | #[stable(feature = "rust1", since = "1.0.0")] |
132 | pub fn as_os_str(&self) -> &OsStr { | |
133 | self | |
134 | } | |
135 | ||
32a655c1 | 136 | /// Converts the `OsString` into a [`String`] if it contains valid Unicode data. |
85aaf69f SL |
137 | /// |
138 | /// On failure, ownership of the original `OsString` is returned. | |
32a655c1 SL |
139 | /// |
140 | /// [`String`]: ../../std/string/struct.String.html | |
141 | /// | |
142 | /// # Examples | |
143 | /// | |
144 | /// ``` | |
145 | /// use std::ffi::OsString; | |
146 | /// | |
147 | /// let os_string = OsString::from("foo"); | |
148 | /// let string = os_string.into_string(); | |
149 | /// assert_eq!(string, Ok(String::from("foo"))); | |
150 | /// ``` | |
c34b1796 | 151 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
152 | pub fn into_string(self) -> Result<String, OsString> { |
153 | self.inner.into_string().map_err(|buf| OsString { inner: buf} ) | |
154 | } | |
155 | ||
32a655c1 SL |
156 | /// Extends the string with the given [`&OsStr`] slice. |
157 | /// | |
158 | /// [`&OsStr`]: struct.OsStr.html | |
159 | /// | |
160 | /// # Examples | |
161 | /// | |
162 | /// ``` | |
163 | /// use std::ffi::OsString; | |
164 | /// | |
165 | /// let mut os_string = OsString::from("foo"); | |
166 | /// os_string.push("bar"); | |
167 | /// assert_eq!(&os_string, "foobar"); | |
168 | /// ``` | |
c34b1796 AL |
169 | #[stable(feature = "rust1", since = "1.0.0")] |
170 | pub fn push<T: AsRef<OsStr>>(&mut self, s: T) { | |
171 | self.inner.push_slice(&s.as_ref().inner) | |
172 | } | |
7453a54e | 173 | |
54a0048b SL |
174 | /// Creates a new `OsString` with the given capacity. |
175 | /// | |
3b2f2976 | 176 | /// The string will be able to hold exactly `capacity` length units of other |
54a0048b SL |
177 | /// OS strings without reallocating. If `capacity` is 0, the string will not |
178 | /// allocate. | |
7453a54e SL |
179 | /// |
180 | /// See main `OsString` documentation information about encoding. | |
32a655c1 SL |
181 | /// |
182 | /// # Examples | |
183 | /// | |
184 | /// ``` | |
185 | /// use std::ffi::OsString; | |
186 | /// | |
187 | /// let mut os_string = OsString::with_capacity(10); | |
188 | /// let capacity = os_string.capacity(); | |
189 | /// | |
190 | /// // This push is done without reallocating | |
191 | /// os_string.push("foo"); | |
192 | /// | |
193 | /// assert_eq!(capacity, os_string.capacity()); | |
194 | /// ``` | |
54a0048b | 195 | #[stable(feature = "osstring_simple_functions", since = "1.9.0")] |
7453a54e SL |
196 | pub fn with_capacity(capacity: usize) -> OsString { |
197 | OsString { | |
198 | inner: Buf::with_capacity(capacity) | |
199 | } | |
200 | } | |
201 | ||
202 | /// Truncates the `OsString` to zero length. | |
32a655c1 SL |
203 | /// |
204 | /// # Examples | |
205 | /// | |
206 | /// ``` | |
207 | /// use std::ffi::OsString; | |
208 | /// | |
209 | /// let mut os_string = OsString::from("foo"); | |
210 | /// assert_eq!(&os_string, "foo"); | |
211 | /// | |
212 | /// os_string.clear(); | |
213 | /// assert_eq!(&os_string, ""); | |
214 | /// ``` | |
54a0048b | 215 | #[stable(feature = "osstring_simple_functions", since = "1.9.0")] |
7453a54e SL |
216 | pub fn clear(&mut self) { |
217 | self.inner.clear() | |
218 | } | |
219 | ||
54a0048b | 220 | /// Returns the capacity this `OsString` can hold without reallocating. |
7453a54e SL |
221 | /// |
222 | /// See `OsString` introduction for information about encoding. | |
32a655c1 SL |
223 | /// |
224 | /// # Examples | |
225 | /// | |
226 | /// ``` | |
227 | /// use std::ffi::OsString; | |
228 | /// | |
229 | /// let mut os_string = OsString::with_capacity(10); | |
230 | /// assert!(os_string.capacity() >= 10); | |
231 | /// ``` | |
54a0048b | 232 | #[stable(feature = "osstring_simple_functions", since = "1.9.0")] |
7453a54e SL |
233 | pub fn capacity(&self) -> usize { |
234 | self.inner.capacity() | |
235 | } | |
236 | ||
54a0048b SL |
237 | /// Reserves capacity for at least `additional` more capacity to be inserted |
238 | /// in the given `OsString`. | |
239 | /// | |
240 | /// The collection may reserve more space to avoid frequent reallocations. | |
cc61c64b XL |
241 | /// |
242 | /// # Examples | |
243 | /// | |
244 | /// ``` | |
245 | /// use std::ffi::OsString; | |
246 | /// | |
247 | /// let mut s = OsString::new(); | |
248 | /// s.reserve(10); | |
249 | /// assert!(s.capacity() >= 10); | |
250 | /// ``` | |
54a0048b | 251 | #[stable(feature = "osstring_simple_functions", since = "1.9.0")] |
7453a54e SL |
252 | pub fn reserve(&mut self, additional: usize) { |
253 | self.inner.reserve(additional) | |
254 | } | |
255 | ||
54a0048b SL |
256 | /// Reserves the minimum capacity for exactly `additional` more capacity to |
257 | /// be inserted in the given `OsString`. Does nothing if the capacity is | |
7453a54e SL |
258 | /// already sufficient. |
259 | /// | |
260 | /// Note that the allocator may give the collection more space than it | |
261 | /// requests. Therefore capacity can not be relied upon to be precisely | |
262 | /// minimal. Prefer reserve if future insertions are expected. | |
cc61c64b XL |
263 | /// |
264 | /// # Examples | |
265 | /// | |
266 | /// ``` | |
267 | /// use std::ffi::OsString; | |
268 | /// | |
269 | /// let mut s = OsString::new(); | |
270 | /// s.reserve_exact(10); | |
271 | /// assert!(s.capacity() >= 10); | |
272 | /// ``` | |
54a0048b | 273 | #[stable(feature = "osstring_simple_functions", since = "1.9.0")] |
7453a54e SL |
274 | pub fn reserve_exact(&mut self, additional: usize) { |
275 | self.inner.reserve_exact(additional) | |
276 | } | |
8bb4bdeb XL |
277 | |
278 | /// Shrinks the capacity of the `OsString` to match its length. | |
cc61c64b XL |
279 | /// |
280 | /// # Examples | |
281 | /// | |
282 | /// ``` | |
cc61c64b XL |
283 | /// use std::ffi::OsString; |
284 | /// | |
285 | /// let mut s = OsString::from("foo"); | |
286 | /// | |
287 | /// s.reserve(100); | |
288 | /// assert!(s.capacity() >= 100); | |
289 | /// | |
290 | /// s.shrink_to_fit(); | |
291 | /// assert_eq!(3, s.capacity()); | |
292 | /// ``` | |
7cac9316 | 293 | #[stable(feature = "osstring_shrink_to_fit", since = "1.19.0")] |
8bb4bdeb XL |
294 | pub fn shrink_to_fit(&mut self) { |
295 | self.inner.shrink_to_fit() | |
296 | } | |
297 | ||
0531ce1d XL |
298 | /// Shrinks the capacity of the `OsString` with a lower bound. |
299 | /// | |
300 | /// The capacity will remain at least as large as both the length | |
301 | /// and the supplied value. | |
302 | /// | |
303 | /// Panics if the current capacity is smaller than the supplied | |
304 | /// minimum capacity. | |
305 | /// | |
306 | /// # Examples | |
307 | /// | |
308 | /// ``` | |
309 | /// #![feature(shrink_to)] | |
310 | /// use std::ffi::OsString; | |
311 | /// | |
312 | /// let mut s = OsString::from("foo"); | |
313 | /// | |
314 | /// s.reserve(100); | |
315 | /// assert!(s.capacity() >= 100); | |
316 | /// | |
317 | /// s.shrink_to(10); | |
318 | /// assert!(s.capacity() >= 10); | |
319 | /// s.shrink_to(0); | |
320 | /// assert!(s.capacity() >= 3); | |
321 | /// ``` | |
322 | #[inline] | |
323 | #[unstable(feature = "shrink_to", reason = "new API", issue="0")] | |
324 | pub fn shrink_to(&mut self, min_capacity: usize) { | |
325 | self.inner.shrink_to(min_capacity) | |
326 | } | |
327 | ||
7cac9316 XL |
328 | /// Converts this `OsString` into a boxed [`OsStr`]. |
329 | /// | |
330 | /// [`OsStr`]: struct.OsStr.html | |
cc61c64b XL |
331 | /// |
332 | /// # Examples | |
333 | /// | |
334 | /// ``` | |
cc61c64b XL |
335 | /// use std::ffi::{OsString, OsStr}; |
336 | /// | |
337 | /// let s = OsString::from("hello"); | |
338 | /// | |
339 | /// let b: Box<OsStr> = s.into_boxed_os_str(); | |
340 | /// ``` | |
041b39d2 | 341 | #[stable(feature = "into_boxed_os_str", since = "1.20.0")] |
8bb4bdeb | 342 | pub fn into_boxed_os_str(self) -> Box<OsStr> { |
ea8adc8c XL |
343 | let rw = Box::into_raw(self.inner.into_box()) as *mut OsStr; |
344 | unsafe { Box::from_raw(rw) } | |
8bb4bdeb | 345 | } |
c34b1796 AL |
346 | } |
347 | ||
348 | #[stable(feature = "rust1", since = "1.0.0")] | |
349 | impl From<String> for OsString { | |
350 | fn from(s: String) -> OsString { | |
351 | OsString { inner: Buf::from_string(s) } | |
352 | } | |
353 | } | |
354 | ||
355 | #[stable(feature = "rust1", since = "1.0.0")] | |
356 | impl<'a, T: ?Sized + AsRef<OsStr>> From<&'a T> for OsString { | |
357 | fn from(s: &'a T) -> OsString { | |
358 | s.as_ref().to_os_string() | |
85aaf69f SL |
359 | } |
360 | } | |
361 | ||
c34b1796 | 362 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
363 | impl ops::Index<ops::RangeFull> for OsString { |
364 | type Output = OsStr; | |
365 | ||
366 | #[inline] | |
c34b1796 | 367 | fn index(&self, _index: ops::RangeFull) -> &OsStr { |
e9174d1e | 368 | OsStr::from_inner(self.inner.as_slice()) |
85aaf69f SL |
369 | } |
370 | } | |
371 | ||
c34b1796 | 372 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
373 | impl ops::Deref for OsString { |
374 | type Target = OsStr; | |
375 | ||
376 | #[inline] | |
377 | fn deref(&self) -> &OsStr { | |
378 | &self[..] | |
379 | } | |
380 | } | |
381 | ||
54a0048b SL |
382 | #[stable(feature = "osstring_default", since = "1.9.0")] |
383 | impl Default for OsString { | |
9e0c209e | 384 | /// Constructs an empty `OsString`. |
54a0048b SL |
385 | #[inline] |
386 | fn default() -> OsString { | |
387 | OsString::new() | |
388 | } | |
389 | } | |
390 | ||
c34b1796 | 391 | #[stable(feature = "rust1", since = "1.0.0")] |
041b39d2 XL |
392 | impl fmt::Debug for OsString { |
393 | fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { | |
85aaf69f SL |
394 | fmt::Debug::fmt(&**self, formatter) |
395 | } | |
396 | } | |
397 | ||
c34b1796 | 398 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
399 | impl PartialEq for OsString { |
400 | fn eq(&self, other: &OsString) -> bool { | |
401 | &**self == &**other | |
402 | } | |
403 | } | |
404 | ||
c34b1796 | 405 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
406 | impl PartialEq<str> for OsString { |
407 | fn eq(&self, other: &str) -> bool { | |
408 | &**self == other | |
409 | } | |
410 | } | |
411 | ||
c34b1796 | 412 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
413 | impl PartialEq<OsString> for str { |
414 | fn eq(&self, other: &OsString) -> bool { | |
415 | &**other == self | |
416 | } | |
417 | } | |
418 | ||
c34b1796 | 419 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
420 | impl Eq for OsString {} |
421 | ||
c34b1796 | 422 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
423 | impl PartialOrd for OsString { |
424 | #[inline] | |
425 | fn partial_cmp(&self, other: &OsString) -> Option<cmp::Ordering> { | |
426 | (&**self).partial_cmp(&**other) | |
427 | } | |
428 | #[inline] | |
429 | fn lt(&self, other: &OsString) -> bool { &**self < &**other } | |
430 | #[inline] | |
431 | fn le(&self, other: &OsString) -> bool { &**self <= &**other } | |
432 | #[inline] | |
433 | fn gt(&self, other: &OsString) -> bool { &**self > &**other } | |
434 | #[inline] | |
435 | fn ge(&self, other: &OsString) -> bool { &**self >= &**other } | |
436 | } | |
437 | ||
c34b1796 | 438 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
439 | impl PartialOrd<str> for OsString { |
440 | #[inline] | |
441 | fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> { | |
442 | (&**self).partial_cmp(other) | |
443 | } | |
444 | } | |
445 | ||
c34b1796 | 446 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
447 | impl Ord for OsString { |
448 | #[inline] | |
449 | fn cmp(&self, other: &OsString) -> cmp::Ordering { | |
450 | (&**self).cmp(&**other) | |
451 | } | |
452 | } | |
453 | ||
85aaf69f SL |
454 | #[stable(feature = "rust1", since = "1.0.0")] |
455 | impl Hash for OsString { | |
456 | #[inline] | |
457 | fn hash<H: Hasher>(&self, state: &mut H) { | |
458 | (&**self).hash(state) | |
459 | } | |
460 | } | |
461 | ||
462 | impl OsStr { | |
9346a6ac | 463 | /// Coerces into an `OsStr` slice. |
9e0c209e SL |
464 | /// |
465 | /// # Examples | |
466 | /// | |
467 | /// ``` | |
468 | /// use std::ffi::OsStr; | |
469 | /// | |
470 | /// let os_str = OsStr::new("foo"); | |
471 | /// ``` | |
c34b1796 AL |
472 | #[stable(feature = "rust1", since = "1.0.0")] |
473 | pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &OsStr { | |
474 | s.as_ref() | |
475 | } | |
476 | ||
e9174d1e | 477 | fn from_inner(inner: &Slice) -> &OsStr { |
ea8adc8c | 478 | unsafe { &*(inner as *const Slice as *const OsStr) } |
e9174d1e SL |
479 | } |
480 | ||
32a655c1 | 481 | /// Yields a [`&str`] slice if the `OsStr` is valid Unicode. |
85aaf69f SL |
482 | /// |
483 | /// This conversion may entail doing a check for UTF-8 validity. | |
32a655c1 SL |
484 | /// |
485 | /// [`&str`]: ../../std/primitive.str.html | |
486 | /// | |
487 | /// # Examples | |
488 | /// | |
489 | /// ``` | |
490 | /// use std::ffi::OsStr; | |
491 | /// | |
492 | /// let os_str = OsStr::new("foo"); | |
493 | /// assert_eq!(os_str.to_str(), Some("foo")); | |
494 | /// ``` | |
c34b1796 | 495 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
496 | pub fn to_str(&self) -> Option<&str> { |
497 | self.inner.to_str() | |
498 | } | |
499 | ||
32a655c1 | 500 | /// Converts an `OsStr` to a [`Cow`]`<`[`str`]`>`. |
85aaf69f SL |
501 | /// |
502 | /// Any non-Unicode sequences are replaced with U+FFFD REPLACEMENT CHARACTER. | |
32a655c1 SL |
503 | /// |
504 | /// [`Cow`]: ../../std/borrow/enum.Cow.html | |
505 | /// [`str`]: ../../std/primitive.str.html | |
506 | /// | |
507 | /// # Examples | |
508 | /// | |
509 | /// Calling `to_string_lossy` on an `OsStr` with valid unicode: | |
510 | /// | |
511 | /// ``` | |
512 | /// use std::ffi::OsStr; | |
513 | /// | |
514 | /// let os_str = OsStr::new("foo"); | |
515 | /// assert_eq!(os_str.to_string_lossy(), "foo"); | |
516 | /// ``` | |
517 | /// | |
518 | /// Had `os_str` contained invalid unicode, the `to_string_lossy` call might | |
519 | /// have returned `"fo�"`. | |
c34b1796 AL |
520 | #[stable(feature = "rust1", since = "1.0.0")] |
521 | pub fn to_string_lossy(&self) -> Cow<str> { | |
85aaf69f SL |
522 | self.inner.to_string_lossy() |
523 | } | |
524 | ||
32a655c1 SL |
525 | /// Copies the slice into an owned [`OsString`]. |
526 | /// | |
527 | /// [`OsString`]: struct.OsString.html | |
cc61c64b XL |
528 | /// |
529 | /// # Examples | |
530 | /// | |
531 | /// ``` | |
532 | /// use std::ffi::{OsStr, OsString}; | |
533 | /// | |
534 | /// let os_str = OsStr::new("foo"); | |
535 | /// let os_string = os_str.to_os_string(); | |
536 | /// assert_eq!(os_string, OsString::from("foo")); | |
537 | /// ``` | |
c34b1796 | 538 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
539 | pub fn to_os_string(&self) -> OsString { |
540 | OsString { inner: self.inner.to_owned() } | |
541 | } | |
542 | ||
7453a54e | 543 | /// Checks whether the `OsStr` is empty. |
9e0c209e SL |
544 | /// |
545 | /// # Examples | |
546 | /// | |
547 | /// ``` | |
548 | /// use std::ffi::OsStr; | |
549 | /// | |
550 | /// let os_str = OsStr::new(""); | |
551 | /// assert!(os_str.is_empty()); | |
552 | /// | |
553 | /// let os_str = OsStr::new("foo"); | |
554 | /// assert!(!os_str.is_empty()); | |
555 | /// ``` | |
54a0048b | 556 | #[stable(feature = "osstring_simple_functions", since = "1.9.0")] |
7453a54e SL |
557 | pub fn is_empty(&self) -> bool { |
558 | self.inner.inner.is_empty() | |
559 | } | |
560 | ||
54a0048b SL |
561 | /// Returns the length of this `OsStr`. |
562 | /// | |
563 | /// Note that this does **not** return the number of bytes in this string | |
7cac9316 | 564 | /// as, for example, OS strings on Windows are encoded as a list of [`u16`] |
54a0048b | 565 | /// rather than a list of bytes. This number is simply useful for passing to |
32a655c1 | 566 | /// other methods like [`OsString::with_capacity`] to avoid reallocations. |
7453a54e | 567 | /// |
54a0048b | 568 | /// See `OsStr` introduction for more information about encoding. |
9e0c209e | 569 | /// |
7cac9316 | 570 | /// [`u16`]: ../primitive.u16.html |
32a655c1 SL |
571 | /// [`OsString::with_capacity`]: struct.OsString.html#method.with_capacity |
572 | /// | |
9e0c209e SL |
573 | /// # Examples |
574 | /// | |
575 | /// ``` | |
576 | /// use std::ffi::OsStr; | |
577 | /// | |
578 | /// let os_str = OsStr::new(""); | |
579 | /// assert_eq!(os_str.len(), 0); | |
580 | /// | |
581 | /// let os_str = OsStr::new("foo"); | |
582 | /// assert_eq!(os_str.len(), 3); | |
583 | /// ``` | |
54a0048b | 584 | #[stable(feature = "osstring_simple_functions", since = "1.9.0")] |
7453a54e SL |
585 | pub fn len(&self) -> usize { |
586 | self.inner.inner.len() | |
587 | } | |
588 | ||
7cac9316 XL |
589 | /// Converts a [`Box`]`<OsStr>` into an [`OsString`] without copying or allocating. |
590 | /// | |
591 | /// [`Box`]: ../boxed/struct.Box.html | |
592 | /// [`OsString`]: struct.OsString.html | |
041b39d2 | 593 | #[stable(feature = "into_boxed_os_str", since = "1.20.0")] |
cc61c64b | 594 | pub fn into_os_string(self: Box<OsStr>) -> OsString { |
ea8adc8c XL |
595 | let boxed = unsafe { Box::from_raw(Box::into_raw(self) as *mut Slice) }; |
596 | OsString { inner: Buf::from_box(boxed) } | |
cc61c64b XL |
597 | } |
598 | ||
9346a6ac | 599 | /// Gets the underlying byte representation. |
85aaf69f SL |
600 | /// |
601 | /// Note: it is *crucial* that this API is private, to avoid | |
602 | /// revealing the internal, platform-specific encodings. | |
603 | fn bytes(&self) -> &[u8] { | |
ea8adc8c | 604 | unsafe { &*(&self.inner as *const _ as *const [u8]) } |
85aaf69f SL |
605 | } |
606 | } | |
607 | ||
8bb4bdeb XL |
608 | #[stable(feature = "box_from_os_str", since = "1.17.0")] |
609 | impl<'a> From<&'a OsStr> for Box<OsStr> { | |
610 | fn from(s: &'a OsStr) -> Box<OsStr> { | |
ea8adc8c XL |
611 | let rw = Box::into_raw(s.inner.into_box()) as *mut OsStr; |
612 | unsafe { Box::from_raw(rw) } | |
8bb4bdeb XL |
613 | } |
614 | } | |
615 | ||
7cac9316 XL |
616 | #[stable(feature = "os_string_from_box", since = "1.18.0")] |
617 | impl From<Box<OsStr>> for OsString { | |
cc61c64b XL |
618 | fn from(boxed: Box<OsStr>) -> OsString { |
619 | boxed.into_os_string() | |
620 | } | |
621 | } | |
622 | ||
041b39d2 XL |
623 | #[stable(feature = "box_from_os_string", since = "1.20.0")] |
624 | impl From<OsString> for Box<OsStr> { | |
625 | fn from(s: OsString) -> Box<OsStr> { | |
626 | s.into_boxed_os_str() | |
cc61c64b XL |
627 | } |
628 | } | |
629 | ||
2c00a5a8 | 630 | #[stable(feature = "shared_from_slice2", since = "1.24.0")] |
ff7c6d11 XL |
631 | impl From<OsString> for Arc<OsStr> { |
632 | #[inline] | |
633 | fn from(s: OsString) -> Arc<OsStr> { | |
634 | let arc = s.inner.into_arc(); | |
635 | unsafe { Arc::from_raw(Arc::into_raw(arc) as *const OsStr) } | |
636 | } | |
637 | } | |
638 | ||
2c00a5a8 | 639 | #[stable(feature = "shared_from_slice2", since = "1.24.0")] |
ff7c6d11 XL |
640 | impl<'a> From<&'a OsStr> for Arc<OsStr> { |
641 | #[inline] | |
642 | fn from(s: &OsStr) -> Arc<OsStr> { | |
643 | let arc = s.inner.into_arc(); | |
644 | unsafe { Arc::from_raw(Arc::into_raw(arc) as *const OsStr) } | |
645 | } | |
646 | } | |
647 | ||
2c00a5a8 | 648 | #[stable(feature = "shared_from_slice2", since = "1.24.0")] |
ff7c6d11 XL |
649 | impl From<OsString> for Rc<OsStr> { |
650 | #[inline] | |
651 | fn from(s: OsString) -> Rc<OsStr> { | |
652 | let rc = s.inner.into_rc(); | |
653 | unsafe { Rc::from_raw(Rc::into_raw(rc) as *const OsStr) } | |
654 | } | |
655 | } | |
656 | ||
2c00a5a8 | 657 | #[stable(feature = "shared_from_slice2", since = "1.24.0")] |
ff7c6d11 XL |
658 | impl<'a> From<&'a OsStr> for Rc<OsStr> { |
659 | #[inline] | |
660 | fn from(s: &OsStr) -> Rc<OsStr> { | |
661 | let rc = s.inner.into_rc(); | |
662 | unsafe { Rc::from_raw(Rc::into_raw(rc) as *const OsStr) } | |
663 | } | |
664 | } | |
665 | ||
8bb4bdeb XL |
666 | #[stable(feature = "box_default_extra", since = "1.17.0")] |
667 | impl Default for Box<OsStr> { | |
668 | fn default() -> Box<OsStr> { | |
ea8adc8c XL |
669 | let rw = Box::into_raw(Slice::empty_box()) as *mut OsStr; |
670 | unsafe { Box::from_raw(rw) } | |
8bb4bdeb XL |
671 | } |
672 | } | |
673 | ||
54a0048b SL |
674 | #[stable(feature = "osstring_default", since = "1.9.0")] |
675 | impl<'a> Default for &'a OsStr { | |
9e0c209e | 676 | /// Creates an empty `OsStr`. |
54a0048b SL |
677 | #[inline] |
678 | fn default() -> &'a OsStr { | |
679 | OsStr::new("") | |
680 | } | |
681 | } | |
682 | ||
c34b1796 | 683 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
684 | impl PartialEq for OsStr { |
685 | fn eq(&self, other: &OsStr) -> bool { | |
686 | self.bytes().eq(other.bytes()) | |
687 | } | |
688 | } | |
689 | ||
c34b1796 | 690 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
691 | impl PartialEq<str> for OsStr { |
692 | fn eq(&self, other: &str) -> bool { | |
c34b1796 | 693 | *self == *OsStr::new(other) |
85aaf69f SL |
694 | } |
695 | } | |
696 | ||
c34b1796 | 697 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
698 | impl PartialEq<OsStr> for str { |
699 | fn eq(&self, other: &OsStr) -> bool { | |
c34b1796 | 700 | *other == *OsStr::new(self) |
85aaf69f SL |
701 | } |
702 | } | |
703 | ||
c34b1796 | 704 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
705 | impl Eq for OsStr {} |
706 | ||
c34b1796 | 707 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
708 | impl PartialOrd for OsStr { |
709 | #[inline] | |
710 | fn partial_cmp(&self, other: &OsStr) -> Option<cmp::Ordering> { | |
711 | self.bytes().partial_cmp(other.bytes()) | |
712 | } | |
713 | #[inline] | |
714 | fn lt(&self, other: &OsStr) -> bool { self.bytes().lt(other.bytes()) } | |
715 | #[inline] | |
716 | fn le(&self, other: &OsStr) -> bool { self.bytes().le(other.bytes()) } | |
717 | #[inline] | |
718 | fn gt(&self, other: &OsStr) -> bool { self.bytes().gt(other.bytes()) } | |
719 | #[inline] | |
720 | fn ge(&self, other: &OsStr) -> bool { self.bytes().ge(other.bytes()) } | |
721 | } | |
722 | ||
c34b1796 | 723 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
724 | impl PartialOrd<str> for OsStr { |
725 | #[inline] | |
726 | fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> { | |
c34b1796 | 727 | self.partial_cmp(OsStr::new(other)) |
85aaf69f SL |
728 | } |
729 | } | |
730 | ||
731 | // FIXME (#19470): cannot provide PartialOrd<OsStr> for str until we | |
732 | // have more flexible coherence rules. | |
733 | ||
c34b1796 | 734 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
735 | impl Ord for OsStr { |
736 | #[inline] | |
737 | fn cmp(&self, other: &OsStr) -> cmp::Ordering { self.bytes().cmp(other.bytes()) } | |
738 | } | |
739 | ||
7453a54e SL |
740 | macro_rules! impl_cmp { |
741 | ($lhs:ty, $rhs: ty) => { | |
742 | #[stable(feature = "cmp_os_str", since = "1.8.0")] | |
743 | impl<'a, 'b> PartialEq<$rhs> for $lhs { | |
744 | #[inline] | |
745 | fn eq(&self, other: &$rhs) -> bool { <OsStr as PartialEq>::eq(self, other) } | |
746 | } | |
747 | ||
748 | #[stable(feature = "cmp_os_str", since = "1.8.0")] | |
749 | impl<'a, 'b> PartialEq<$lhs> for $rhs { | |
750 | #[inline] | |
751 | fn eq(&self, other: &$lhs) -> bool { <OsStr as PartialEq>::eq(self, other) } | |
752 | } | |
753 | ||
754 | #[stable(feature = "cmp_os_str", since = "1.8.0")] | |
755 | impl<'a, 'b> PartialOrd<$rhs> for $lhs { | |
756 | #[inline] | |
757 | fn partial_cmp(&self, other: &$rhs) -> Option<cmp::Ordering> { | |
758 | <OsStr as PartialOrd>::partial_cmp(self, other) | |
759 | } | |
760 | } | |
761 | ||
762 | #[stable(feature = "cmp_os_str", since = "1.8.0")] | |
763 | impl<'a, 'b> PartialOrd<$lhs> for $rhs { | |
764 | #[inline] | |
765 | fn partial_cmp(&self, other: &$lhs) -> Option<cmp::Ordering> { | |
766 | <OsStr as PartialOrd>::partial_cmp(self, other) | |
767 | } | |
768 | } | |
769 | } | |
770 | } | |
771 | ||
772 | impl_cmp!(OsString, OsStr); | |
773 | impl_cmp!(OsString, &'a OsStr); | |
774 | impl_cmp!(Cow<'a, OsStr>, OsStr); | |
775 | impl_cmp!(Cow<'a, OsStr>, &'b OsStr); | |
776 | impl_cmp!(Cow<'a, OsStr>, OsString); | |
777 | ||
85aaf69f SL |
778 | #[stable(feature = "rust1", since = "1.0.0")] |
779 | impl Hash for OsStr { | |
780 | #[inline] | |
781 | fn hash<H: Hasher>(&self, state: &mut H) { | |
782 | self.bytes().hash(state) | |
783 | } | |
784 | } | |
785 | ||
c34b1796 | 786 | #[stable(feature = "rust1", since = "1.0.0")] |
041b39d2 XL |
787 | impl fmt::Debug for OsStr { |
788 | fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { | |
789 | fmt::Debug::fmt(&self.inner, formatter) | |
790 | } | |
791 | } | |
792 | ||
793 | impl OsStr { | |
794 | pub(crate) fn display(&self, formatter: &mut fmt::Formatter) -> fmt::Result { | |
795 | fmt::Display::fmt(&self.inner, formatter) | |
85aaf69f SL |
796 | } |
797 | } | |
798 | ||
c34b1796 | 799 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
800 | impl Borrow<OsStr> for OsString { |
801 | fn borrow(&self) -> &OsStr { &self[..] } | |
802 | } | |
803 | ||
c34b1796 | 804 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
805 | impl ToOwned for OsStr { |
806 | type Owned = OsString; | |
cc61c64b XL |
807 | fn to_owned(&self) -> OsString { |
808 | self.to_os_string() | |
809 | } | |
810 | fn clone_into(&self, target: &mut OsString) { | |
811 | target.clear(); | |
812 | target.push(self); | |
813 | } | |
85aaf69f SL |
814 | } |
815 | ||
c34b1796 AL |
816 | #[stable(feature = "rust1", since = "1.0.0")] |
817 | impl AsRef<OsStr> for OsStr { | |
818 | fn as_ref(&self) -> &OsStr { | |
819 | self | |
85aaf69f SL |
820 | } |
821 | } | |
822 | ||
c34b1796 AL |
823 | #[stable(feature = "rust1", since = "1.0.0")] |
824 | impl AsRef<OsStr> for OsString { | |
825 | fn as_ref(&self) -> &OsStr { | |
826 | self | |
827 | } | |
828 | } | |
829 | ||
830 | #[stable(feature = "rust1", since = "1.0.0")] | |
831 | impl AsRef<OsStr> for str { | |
832 | fn as_ref(&self) -> &OsStr { | |
e9174d1e | 833 | OsStr::from_inner(Slice::from_str(self)) |
c34b1796 AL |
834 | } |
835 | } | |
836 | ||
837 | #[stable(feature = "rust1", since = "1.0.0")] | |
838 | impl AsRef<OsStr> for String { | |
839 | fn as_ref(&self) -> &OsStr { | |
e9174d1e | 840 | (&**self).as_ref() |
c34b1796 AL |
841 | } |
842 | } | |
843 | ||
85aaf69f SL |
844 | impl FromInner<Buf> for OsString { |
845 | fn from_inner(buf: Buf) -> OsString { | |
846 | OsString { inner: buf } | |
847 | } | |
848 | } | |
849 | ||
850 | impl IntoInner<Buf> for OsString { | |
851 | fn into_inner(self) -> Buf { | |
852 | self.inner | |
853 | } | |
854 | } | |
855 | ||
856 | impl AsInner<Slice> for OsStr { | |
857 | fn as_inner(&self) -> &Slice { | |
858 | &self.inner | |
859 | } | |
860 | } | |
7453a54e SL |
861 | |
862 | #[cfg(test)] | |
863 | mod tests { | |
864 | use super::*; | |
865 | use sys_common::{AsInner, IntoInner}; | |
866 | ||
ff7c6d11 XL |
867 | use rc::Rc; |
868 | use sync::Arc; | |
869 | ||
7453a54e SL |
870 | #[test] |
871 | fn test_os_string_with_capacity() { | |
872 | let os_string = OsString::with_capacity(0); | |
873 | assert_eq!(0, os_string.inner.into_inner().capacity()); | |
874 | ||
875 | let os_string = OsString::with_capacity(10); | |
876 | assert_eq!(10, os_string.inner.into_inner().capacity()); | |
877 | ||
878 | let mut os_string = OsString::with_capacity(0); | |
879 | os_string.push("abc"); | |
880 | assert!(os_string.inner.into_inner().capacity() >= 3); | |
881 | } | |
882 | ||
883 | #[test] | |
884 | fn test_os_string_clear() { | |
885 | let mut os_string = OsString::from("abc"); | |
886 | assert_eq!(3, os_string.inner.as_inner().len()); | |
887 | ||
888 | os_string.clear(); | |
889 | assert_eq!(&os_string, ""); | |
890 | assert_eq!(0, os_string.inner.as_inner().len()); | |
891 | } | |
892 | ||
893 | #[test] | |
894 | fn test_os_string_capacity() { | |
895 | let os_string = OsString::with_capacity(0); | |
896 | assert_eq!(0, os_string.capacity()); | |
897 | ||
898 | let os_string = OsString::with_capacity(10); | |
899 | assert_eq!(10, os_string.capacity()); | |
900 | ||
901 | let mut os_string = OsString::with_capacity(0); | |
902 | os_string.push("abc"); | |
903 | assert!(os_string.capacity() >= 3); | |
904 | } | |
905 | ||
906 | #[test] | |
907 | fn test_os_string_reserve() { | |
908 | let mut os_string = OsString::new(); | |
909 | assert_eq!(os_string.capacity(), 0); | |
910 | ||
911 | os_string.reserve(2); | |
912 | assert!(os_string.capacity() >= 2); | |
913 | ||
914 | for _ in 0..16 { | |
915 | os_string.push("a"); | |
916 | } | |
917 | ||
918 | assert!(os_string.capacity() >= 16); | |
919 | os_string.reserve(16); | |
920 | assert!(os_string.capacity() >= 32); | |
921 | ||
922 | os_string.push("a"); | |
923 | ||
924 | os_string.reserve(16); | |
925 | assert!(os_string.capacity() >= 33) | |
926 | } | |
927 | ||
928 | #[test] | |
929 | fn test_os_string_reserve_exact() { | |
930 | let mut os_string = OsString::new(); | |
931 | assert_eq!(os_string.capacity(), 0); | |
932 | ||
933 | os_string.reserve_exact(2); | |
934 | assert!(os_string.capacity() >= 2); | |
935 | ||
936 | for _ in 0..16 { | |
937 | os_string.push("a"); | |
938 | } | |
939 | ||
940 | assert!(os_string.capacity() >= 16); | |
941 | os_string.reserve_exact(16); | |
942 | assert!(os_string.capacity() >= 32); | |
943 | ||
944 | os_string.push("a"); | |
945 | ||
946 | os_string.reserve_exact(16); | |
947 | assert!(os_string.capacity() >= 33) | |
948 | } | |
949 | ||
54a0048b SL |
950 | #[test] |
951 | fn test_os_string_default() { | |
952 | let os_string: OsString = Default::default(); | |
953 | assert_eq!("", &os_string); | |
954 | } | |
955 | ||
7453a54e SL |
956 | #[test] |
957 | fn test_os_str_is_empty() { | |
958 | let mut os_string = OsString::new(); | |
959 | assert!(os_string.is_empty()); | |
960 | ||
961 | os_string.push("abc"); | |
962 | assert!(!os_string.is_empty()); | |
963 | ||
964 | os_string.clear(); | |
965 | assert!(os_string.is_empty()); | |
966 | } | |
967 | ||
968 | #[test] | |
969 | fn test_os_str_len() { | |
970 | let mut os_string = OsString::new(); | |
971 | assert_eq!(0, os_string.len()); | |
972 | ||
973 | os_string.push("abc"); | |
974 | assert_eq!(3, os_string.len()); | |
975 | ||
976 | os_string.clear(); | |
977 | assert_eq!(0, os_string.len()); | |
978 | } | |
54a0048b SL |
979 | |
980 | #[test] | |
981 | fn test_os_str_default() { | |
982 | let os_str: &OsStr = Default::default(); | |
983 | assert_eq!("", os_str); | |
984 | } | |
8bb4bdeb XL |
985 | |
986 | #[test] | |
987 | fn into_boxed() { | |
988 | let orig = "Hello, world!"; | |
989 | let os_str = OsStr::new(orig); | |
cc61c64b XL |
990 | let boxed: Box<OsStr> = Box::from(os_str); |
991 | let os_string = os_str.to_owned().into_boxed_os_str().into_os_string(); | |
992 | assert_eq!(os_str, &*boxed); | |
993 | assert_eq!(&*boxed, &*os_string); | |
994 | assert_eq!(&*os_string, os_str); | |
8bb4bdeb XL |
995 | } |
996 | ||
997 | #[test] | |
998 | fn boxed_default() { | |
999 | let boxed = <Box<OsStr>>::default(); | |
1000 | assert!(boxed.is_empty()); | |
1001 | } | |
cc61c64b XL |
1002 | |
1003 | #[test] | |
1004 | fn test_os_str_clone_into() { | |
1005 | let mut os_string = OsString::with_capacity(123); | |
1006 | os_string.push("hello"); | |
1007 | let os_str = OsStr::new("bonjour"); | |
1008 | os_str.clone_into(&mut os_string); | |
1009 | assert_eq!(os_str, os_string); | |
1010 | assert!(os_string.capacity() >= 123); | |
1011 | } | |
ff7c6d11 XL |
1012 | |
1013 | #[test] | |
1014 | fn into_rc() { | |
1015 | let orig = "Hello, world!"; | |
1016 | let os_str = OsStr::new(orig); | |
1017 | let rc: Rc<OsStr> = Rc::from(os_str); | |
1018 | let arc: Arc<OsStr> = Arc::from(os_str); | |
1019 | ||
1020 | assert_eq!(&*rc, os_str); | |
1021 | assert_eq!(&*arc, os_str); | |
1022 | ||
1023 | let rc2: Rc<OsStr> = Rc::from(os_str.to_owned()); | |
1024 | let arc2: Arc<OsStr> = Arc::from(os_str.to_owned()); | |
1025 | ||
1026 | assert_eq!(&*rc2, os_str); | |
1027 | assert_eq!(&*arc2, os_str); | |
1028 | } | |
7453a54e | 1029 | } |