| // Copyright (C) 2017-2018 Baidu, Inc. All Rights Reserved. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions |
| // are met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above copyright |
| // notice, this list of conditions and the following disclaimer in |
| // the documentation and/or other materials provided with the |
| // distribution. |
| // * Neither the name of Baidu, Inc., nor the names of its |
| // contributors may be used to endorse or promote products derived |
| // from this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| use sys::os_str::{Buf, Slice}; |
| use sys_common::{AsInner, IntoInner, FromInner}; |
| use core::ops; |
| use core::cmp; |
| use core::hash::{Hash, Hasher}; |
| use core::fmt; |
| use alloc::borrow::{Borrow, Cow, ToOwned}; |
| use alloc::string::String; |
| use alloc::boxed::Box; |
| use alloc::rc::Rc; |
| use alloc::sync::Arc; |
| |
| |
| /// A type that can represent owned, mutable platform-native strings, but is |
| /// cheaply inter-convertible with Rust strings. |
| /// |
| #[derive(Clone)] |
| pub struct OsString { |
| inner: Buf |
| } |
| |
| /// Slices into OS strings (see [`OsString`]). |
| /// |
| pub struct OsStr { |
| inner: Slice |
| } |
| |
| impl OsString { |
| /// Constructs a new empty `OsString`. |
| /// |
| pub fn new() -> OsString { |
| OsString { inner: Buf::from_string(String::new()) } |
| } |
| |
| /// Converts to an [`OsStr`] slice. |
| /// |
| pub fn as_os_str(&self) -> &OsStr { |
| self |
| } |
| |
| /// Converts the `OsString` into a [`String`] if it contains valid Unicode data. |
| /// |
| /// On failure, ownership of the original `OsString` is returned. |
| /// |
| pub fn into_string(self) -> Result<String, OsString> { |
| self.inner.into_string().map_err(|buf| OsString { inner: buf} ) |
| } |
| |
| /// Extends the string with the given [`&OsStr`] slice. |
| /// |
| pub fn push<T: AsRef<OsStr>>(&mut self, s: T) { |
| self.inner.push_slice(&s.as_ref().inner) |
| } |
| |
| /// Creates a new `OsString` with the given capacity. |
| /// |
| /// The string will be able to hold exactly `capacity` lenth units of other |
| /// OS strings without reallocating. If `capacity` is 0, the string will not |
| /// allocate. |
| /// |
| pub fn with_capacity(capacity: usize) -> OsString { |
| OsString { |
| inner: Buf::with_capacity(capacity) |
| } |
| } |
| |
| /// Truncates the `OsString` to zero length. |
| /// |
| pub fn clear(&mut self) { |
| self.inner.clear() |
| } |
| |
| /// Returns the capacity this `OsString` can hold without reallocating. |
| /// |
| pub fn capacity(&self) -> usize { |
| self.inner.capacity() |
| } |
| |
| /// Reserves capacity for at least `additional` more capacity to be inserted |
| /// in the given `OsString`. |
| /// |
| pub fn reserve(&mut self, additional: usize) { |
| self.inner.reserve(additional) |
| } |
| |
| /// Reserves the minimum capacity for exactly `additional` more capacity to |
| /// be inserted in the given `OsString`. Does nothing if the capacity is |
| /// already sufficient. |
| /// |
| /// Note that the allocator may give the collection more space than it |
| /// requests. Therefore capacity can not be relied upon to be precisely |
| /// minimal. Prefer reserve if future insertions are expected. |
| /// |
| pub fn reserve_exact(&mut self, additional: usize) { |
| self.inner.reserve_exact(additional) |
| } |
| |
| /// Shrinks the capacity of the `OsString` to match its length. |
| /// |
| pub fn shrink_to_fit(&mut self) { |
| self.inner.shrink_to_fit() |
| } |
| |
| /// Shrinks the capacity of the `OsString` with a lower bound. |
| /// |
| /// The capacity will remain at least as large as both the length |
| /// and the supplied value. |
| /// |
| /// Panics if the current capacity is smaller than the supplied |
| /// minimum capacity. |
| /// |
| #[inline] |
| pub fn shrink_to(&mut self, min_capacity: usize) { |
| self.inner.shrink_to(min_capacity) |
| } |
| |
| /// Converts this `OsString` into a boxed `OsStr`. |
| /// |
| pub fn into_boxed_os_str(self) -> Box<OsStr> { |
| let rw = Box::into_raw(self.inner.into_box()) as *mut OsStr; |
| unsafe { Box::from_raw(rw) } |
| } |
| } |
| |
| impl From<String> for OsString { |
| fn from(s: String) -> OsString { |
| OsString { inner: Buf::from_string(s) } |
| } |
| } |
| |
| impl<'a, T: ?Sized + AsRef<OsStr>> From<&'a T> for OsString { |
| fn from(s: &'a T) -> OsString { |
| s.as_ref().to_os_string() |
| } |
| } |
| |
| impl ops::Index<ops::RangeFull> for OsString { |
| type Output = OsStr; |
| |
| #[inline] |
| fn index(&self, _index: ops::RangeFull) -> &OsStr { |
| OsStr::from_inner(self.inner.as_slice()) |
| } |
| } |
| |
| impl ops::Deref for OsString { |
| type Target = OsStr; |
| |
| #[inline] |
| fn deref(&self) -> &OsStr { |
| &self[..] |
| } |
| } |
| |
| impl Default for OsString { |
| /// Constructs an empty `OsString`. |
| #[inline] |
| fn default() -> OsString { |
| OsString::new() |
| } |
| } |
| |
| impl fmt::Debug for OsString { |
| fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
| fmt::Debug::fmt(&**self, formatter) |
| } |
| } |
| |
| impl PartialEq for OsString { |
| fn eq(&self, other: &OsString) -> bool { |
| &**self == &**other |
| } |
| } |
| |
| impl PartialEq<str> for OsString { |
| fn eq(&self, other: &str) -> bool { |
| &**self == other |
| } |
| } |
| |
| impl PartialEq<OsString> for str { |
| fn eq(&self, other: &OsString) -> bool { |
| &**other == self |
| } |
| } |
| |
| impl Eq for OsString {} |
| |
| impl PartialOrd for OsString { |
| #[inline] |
| fn partial_cmp(&self, other: &OsString) -> Option<cmp::Ordering> { |
| (&**self).partial_cmp(&**other) |
| } |
| #[inline] |
| fn lt(&self, other: &OsString) -> bool { &**self < &**other } |
| #[inline] |
| fn le(&self, other: &OsString) -> bool { &**self <= &**other } |
| #[inline] |
| fn gt(&self, other: &OsString) -> bool { &**self > &**other } |
| #[inline] |
| fn ge(&self, other: &OsString) -> bool { &**self >= &**other } |
| } |
| |
| impl PartialOrd<str> for OsString { |
| #[inline] |
| fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> { |
| (&**self).partial_cmp(other) |
| } |
| } |
| |
| impl Ord for OsString { |
| #[inline] |
| fn cmp(&self, other: &OsString) -> cmp::Ordering { |
| (&**self).cmp(&**other) |
| } |
| } |
| |
| impl Hash for OsString { |
| #[inline] |
| fn hash<H: Hasher>(&self, state: &mut H) { |
| (&**self).hash(state) |
| } |
| } |
| |
| impl OsStr { |
| /// Coerces into an `OsStr` slice. |
| /// |
| pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &OsStr { |
| s.as_ref() |
| } |
| |
| fn from_inner(inner: &Slice) -> &OsStr { |
| unsafe { &*(inner as *const Slice as *const OsStr) } |
| } |
| |
| /// Yields a [`&str`] slice if the `OsStr` is valid Unicode. |
| /// |
| /// This conversion may entail doing a check for UTF-8 validity. |
| /// |
| pub fn to_str(&self) -> Option<&str> { |
| self.inner.to_str() |
| } |
| |
| /// Converts an `OsStr` to a [`Cow`]`<`[`str`]`>`. |
| /// |
| /// Any non-Unicode sequences are replaced with U+FFFD REPLACEMENT CHARACTER. |
| /// |
| pub fn to_string_lossy(&self) -> Cow<str> { |
| self.inner.to_string_lossy() |
| } |
| |
| /// Copies the slice into an owned [`OsString`]. |
| /// |
| pub fn to_os_string(&self) -> OsString { |
| OsString { inner: self.inner.to_owned() } |
| } |
| |
| /// Checks whether the `OsStr` is empty. |
| /// |
| pub fn is_empty(&self) -> bool { |
| self.inner.inner.is_empty() |
| } |
| |
| /// Returns the length of this `OsStr`. |
| /// |
| /// Note that this does **not** return the number of bytes in this string |
| /// as, for example, OS strings on Windows are encoded as a list of `u16` |
| /// rather than a list of bytes. This number is simply useful for passing to |
| /// other methods like [`OsString::with_capacity`] to avoid reallocations. |
| /// |
| /// See `OsStr` introduction for more information about encoding. |
| /// |
| pub fn len(&self) -> usize { |
| self.inner.inner.len() |
| } |
| |
| /// Converts a `Box<OsStr>` into an `OsString` without copying or allocating. |
| pub fn into_os_string(self: Box<OsStr>) -> OsString { |
| let boxed = unsafe { Box::from_raw(Box::into_raw(self) as *mut Slice) }; |
| OsString { inner: Buf::from_box(boxed) } |
| } |
| |
| /// Gets the underlying byte representation. |
| /// |
| fn bytes(&self) -> &[u8] { |
| unsafe { &*(&self.inner as *const _ as *const [u8]) } |
| } |
| } |
| |
| impl<'a> From<&'a OsStr> for Box<OsStr> { |
| fn from(s: &'a OsStr) -> Box<OsStr> { |
| let rw = Box::into_raw(s.inner.into_box()) as *mut OsStr; |
| unsafe { Box::from_raw(rw) } |
| } |
| } |
| |
| impl From<Box<OsStr>> for OsString { |
| fn from(boxed: Box<OsStr>) -> OsString { |
| boxed.into_os_string() |
| } |
| } |
| |
| impl From<OsString> for Box<OsStr> { |
| fn from(s: OsString) -> Box<OsStr> { |
| s.into_boxed_os_str() |
| } |
| } |
| |
| impl From<OsString> for Arc<OsStr> { |
| #[inline] |
| fn from(s: OsString) -> Arc<OsStr> { |
| let arc = s.inner.into_arc(); |
| unsafe { Arc::from_raw(Arc::into_raw(arc) as *const OsStr) } |
| } |
| } |
| |
| impl<'a> From<&'a OsStr> for Arc<OsStr> { |
| #[inline] |
| fn from(s: &OsStr) -> Arc<OsStr> { |
| let arc = s.inner.into_arc(); |
| unsafe { Arc::from_raw(Arc::into_raw(arc) as *const OsStr) } |
| } |
| } |
| |
| impl From<OsString> for Rc<OsStr> { |
| #[inline] |
| fn from(s: OsString) -> Rc<OsStr> { |
| let rc = s.inner.into_rc(); |
| unsafe { Rc::from_raw(Rc::into_raw(rc) as *const OsStr) } |
| } |
| } |
| |
| impl<'a> From<&'a OsStr> for Rc<OsStr> { |
| #[inline] |
| fn from(s: &OsStr) -> Rc<OsStr> { |
| let rc = s.inner.into_rc(); |
| unsafe { Rc::from_raw(Rc::into_raw(rc) as *const OsStr) } |
| } |
| } |
| |
| impl Default for Box<OsStr> { |
| fn default() -> Box<OsStr> { |
| let rw = Box::into_raw(Slice::empty_box()) as *mut OsStr; |
| unsafe { Box::from_raw(rw) } |
| } |
| } |
| |
| impl<'a> Default for &'a OsStr { |
| /// Creates an empty `OsStr`. |
| #[inline] |
| fn default() -> &'a OsStr { |
| OsStr::new("") |
| } |
| } |
| |
| impl PartialEq for OsStr { |
| fn eq(&self, other: &OsStr) -> bool { |
| self.bytes().eq(other.bytes()) |
| } |
| } |
| |
| impl PartialEq<str> for OsStr { |
| fn eq(&self, other: &str) -> bool { |
| *self == *OsStr::new(other) |
| } |
| } |
| |
| impl PartialEq<OsStr> for str { |
| fn eq(&self, other: &OsStr) -> bool { |
| *other == *OsStr::new(self) |
| } |
| } |
| |
| impl Eq for OsStr {} |
| |
| impl PartialOrd for OsStr { |
| #[inline] |
| fn partial_cmp(&self, other: &OsStr) -> Option<cmp::Ordering> { |
| self.bytes().partial_cmp(other.bytes()) |
| } |
| #[inline] |
| fn lt(&self, other: &OsStr) -> bool { self.bytes().lt(other.bytes()) } |
| #[inline] |
| fn le(&self, other: &OsStr) -> bool { self.bytes().le(other.bytes()) } |
| #[inline] |
| fn gt(&self, other: &OsStr) -> bool { self.bytes().gt(other.bytes()) } |
| #[inline] |
| fn ge(&self, other: &OsStr) -> bool { self.bytes().ge(other.bytes()) } |
| } |
| |
| impl PartialOrd<str> for OsStr { |
| #[inline] |
| fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> { |
| self.partial_cmp(OsStr::new(other)) |
| } |
| } |
| |
| // FIXME (#19470): cannot provide PartialOrd<OsStr> for str until we |
| // have more flexible coherence rules. |
| |
| impl Ord for OsStr { |
| #[inline] |
| fn cmp(&self, other: &OsStr) -> cmp::Ordering { self.bytes().cmp(other.bytes()) } |
| } |
| |
| macro_rules! impl_cmp { |
| ($lhs:ty, $rhs: ty) => { |
| impl<'a, 'b> PartialEq<$rhs> for $lhs { |
| #[inline] |
| fn eq(&self, other: &$rhs) -> bool { <OsStr as PartialEq>::eq(self, other) } |
| } |
| |
| impl<'a, 'b> PartialEq<$lhs> for $rhs { |
| #[inline] |
| fn eq(&self, other: &$lhs) -> bool { <OsStr as PartialEq>::eq(self, other) } |
| } |
| |
| impl<'a, 'b> PartialOrd<$rhs> for $lhs { |
| #[inline] |
| fn partial_cmp(&self, other: &$rhs) -> Option<cmp::Ordering> { |
| <OsStr as PartialOrd>::partial_cmp(self, other) |
| } |
| } |
| |
| impl<'a, 'b> PartialOrd<$lhs> for $rhs { |
| #[inline] |
| fn partial_cmp(&self, other: &$lhs) -> Option<cmp::Ordering> { |
| <OsStr as PartialOrd>::partial_cmp(self, other) |
| } |
| } |
| } |
| } |
| |
| impl_cmp!(OsString, OsStr); |
| impl_cmp!(OsString, &'a OsStr); |
| impl_cmp!(Cow<'a, OsStr>, OsStr); |
| impl_cmp!(Cow<'a, OsStr>, &'b OsStr); |
| impl_cmp!(Cow<'a, OsStr>, OsString); |
| |
| impl Hash for OsStr { |
| #[inline] |
| fn hash<H: Hasher>(&self, state: &mut H) { |
| self.bytes().hash(state) |
| } |
| } |
| |
| impl fmt::Debug for OsStr { |
| fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
| fmt::Debug::fmt(&self.inner, formatter) |
| } |
| } |
| |
| impl OsStr { |
| pub(crate) fn display(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
| fmt::Display::fmt(&self.inner, formatter) |
| } |
| } |
| impl Borrow<OsStr> for OsString { |
| fn borrow(&self) -> &OsStr { &self[..] } |
| } |
| |
| impl ToOwned for OsStr { |
| type Owned = OsString; |
| fn to_owned(&self) -> OsString { |
| self.to_os_string() |
| } |
| fn clone_into(&self, target: &mut OsString) { |
| target.clear(); |
| target.push(self); |
| } |
| } |
| |
| impl AsRef<OsStr> for OsStr { |
| fn as_ref(&self) -> &OsStr { |
| self |
| } |
| } |
| |
| impl AsRef<OsStr> for OsString { |
| fn as_ref(&self) -> &OsStr { |
| self |
| } |
| } |
| |
| impl AsRef<OsStr> for str { |
| fn as_ref(&self) -> &OsStr { |
| OsStr::from_inner(Slice::from_str(self)) |
| } |
| } |
| |
| impl AsRef<OsStr> for String { |
| fn as_ref(&self) -> &OsStr { |
| (&**self).as_ref() |
| } |
| } |
| |
| impl FromInner<Buf> for OsString { |
| fn from_inner(buf: Buf) -> OsString { |
| OsString { inner: buf } |
| } |
| } |
| |
| impl IntoInner<Buf> for OsString { |
| fn into_inner(self) -> Buf { |
| self.inner |
| } |
| } |
| |
| impl AsInner<Slice> for OsStr { |
| fn as_inner(&self) -> &Slice { |
| &self.inner |
| } |
| } |