aboutsummaryrefslogtreecommitdiff
path: root/ctr-std/src/ffi/os_str.rs
diff options
context:
space:
mode:
Diffstat (limited to 'ctr-std/src/ffi/os_str.rs')
-rw-r--r--ctr-std/src/ffi/os_str.rs416
1 files changed, 393 insertions, 23 deletions
diff --git a/ctr-std/src/ffi/os_str.rs b/ctr-std/src/ffi/os_str.rs
index 84b50f0..3959e85 100644
--- a/ctr-std/src/ffi/os_str.rs
+++ b/ctr-std/src/ffi/os_str.rs
@@ -9,11 +9,12 @@
// except according to those terms.
use borrow::{Borrow, Cow};
-use fmt::{self, Debug};
-use mem;
+use fmt;
use ops;
use cmp;
use hash::{Hash, Hasher};
+use rc::Rc;
+use sync::Arc;
use sys::os_str::{Buf, Slice};
use sys_common::{AsInner, IntoInner, FromInner};
@@ -29,18 +30,71 @@ use sys_common::{AsInner, IntoInner, FromInner};
/// * On Windows, strings are often arbitrary sequences of non-zero 16-bit
/// values, interpreted as UTF-16 when it is valid to do so.
///
-/// * In Rust, strings are always valid UTF-8, but may contain zeros.
+/// * In Rust, strings are always valid UTF-8, which may contain zeros.
///
-/// `OsString` and `OsStr` bridge this gap by simultaneously representing Rust
+/// `OsString` and [`OsStr`] bridge this gap by simultaneously representing Rust
/// and platform-native string values, and in particular allowing a Rust string
-/// to be converted into an "OS" string with no cost.
+/// to be converted into an "OS" string with no cost if possible.
+///
+/// `OsString` is to [`&OsStr`] as [`String`] is to [`&str`]: the former
+/// in each pair are owned strings; the latter are borrowed
+/// references.
+///
+/// # Creating an `OsString`
+///
+/// **From a Rust string**: `OsString` implements
+/// [`From`]`<`[`String`]`>`, so you can use `my_string.from` to
+/// create an `OsString` from a normal Rust string.
+///
+/// **From slices:** Just like you can start with an empty Rust
+/// [`String`] and then [`push_str`][String.push_str] `&str`
+/// sub-string slices into it, you can create an empty `OsString` with
+/// the [`new`] method and then push string slices into it with the
+/// [`push`] method.
+///
+/// # Extracting a borrowed reference to the whole OS string
+///
+/// You can use the [`as_os_str`] method to get an `&`[`OsStr`] from
+/// an `OsString`; this is effectively a borrowed reference to the
+/// whole string.
+///
+/// # Conversions
+///
+/// See the [module's toplevel documentation about conversions][conversions] for a discussion on
+/// the traits which `OsString` implements for conversions from/to native representations.
+///
+/// [`OsStr`]: struct.OsStr.html
+/// [`&OsStr`]: struct.OsStr.html
+/// [`From`]: ../convert/trait.From.html
+/// [`String`]: ../string/struct.String.html
+/// [`&str`]: ../primitive.str.html
+/// [`u8`]: ../primitive.u8.html
+/// [`u16`]: ../primitive.u16.html
+/// [String.push_str]: ../string/struct.String.html#method.push_str
+/// [`new`]: #method.new
+/// [`push`]: #method.push
+/// [`as_os_str`]: #method.as_os_str
#[derive(Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct OsString {
inner: Buf
}
-/// Slices into OS strings (see `OsString`).
+/// Borrowed reference to an OS string (see [`OsString`]).
+///
+/// This type represents a borrowed reference to a string in the operating system's preferred
+/// representation.
+///
+/// `&OsStr` is to [`OsString`] as [`&str`] is to [`String`]: the former in each pair are borrowed
+/// references; the latter are owned strings.
+///
+/// See the [module's toplevel documentation about conversions][conversions] for a discussion on
+/// the traits which `OsStr` implements for conversions from/to native representations.
+///
+/// [`OsString`]: struct.OsString.html
+/// [`&str`]: ../primitive.str.html
+/// [`String`]: ../string/struct.String.html
+/// [conversions]: index.html#conversions
#[stable(feature = "rust1", since = "1.0.0")]
pub struct OsStr {
inner: Slice
@@ -48,26 +102,70 @@ pub struct OsStr {
impl OsString {
/// Constructs a new empty `OsString`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ ///
+ /// let os_string = OsString::new();
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new() -> OsString {
OsString { inner: Buf::from_string(String::new()) }
}
- /// Converts to an `OsStr` slice.
+ /// Converts to an [`OsStr`] slice.
+ ///
+ /// [`OsStr`]: struct.OsStr.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::{OsString, OsStr};
+ ///
+ /// let os_string = OsString::from("foo");
+ /// let os_str = OsStr::new("foo");
+ /// assert_eq!(os_string.as_os_str(), os_str);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn as_os_str(&self) -> &OsStr {
self
}
- /// Converts the `OsString` into a `String` if it contains valid Unicode data.
+ /// Converts the `OsString` into a [`String`] if it contains valid Unicode data.
///
/// On failure, ownership of the original `OsString` is returned.
+ ///
+ /// [`String`]: ../../std/string/struct.String.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ ///
+ /// let os_string = OsString::from("foo");
+ /// let string = os_string.into_string();
+ /// assert_eq!(string, Ok(String::from("foo")));
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
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.
+ /// Extends the string with the given [`&OsStr`] slice.
+ ///
+ /// [`&OsStr`]: struct.OsStr.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ ///
+ /// let mut os_string = OsString::from("foo");
+ /// os_string.push("bar");
+ /// assert_eq!(&os_string, "foobar");
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn push<T: AsRef<OsStr>>(&mut self, s: T) {
self.inner.push_slice(&s.as_ref().inner)
@@ -75,11 +173,25 @@ impl OsString {
/// Creates a new `OsString` with the given capacity.
///
- /// The string will be able to hold exactly `capacity` lenth units of other
+ /// The string will be able to hold exactly `capacity` length units of other
/// OS strings without reallocating. If `capacity` is 0, the string will not
/// allocate.
///
/// See main `OsString` documentation information about encoding.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ ///
+ /// let mut os_string = OsString::with_capacity(10);
+ /// let capacity = os_string.capacity();
+ ///
+ /// // This push is done without reallocating
+ /// os_string.push("foo");
+ ///
+ /// assert_eq!(capacity, os_string.capacity());
+ /// ```
#[stable(feature = "osstring_simple_functions", since = "1.9.0")]
pub fn with_capacity(capacity: usize) -> OsString {
OsString {
@@ -88,6 +200,18 @@ impl OsString {
}
/// Truncates the `OsString` to zero length.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ ///
+ /// let mut os_string = OsString::from("foo");
+ /// assert_eq!(&os_string, "foo");
+ ///
+ /// os_string.clear();
+ /// assert_eq!(&os_string, "");
+ /// ```
#[stable(feature = "osstring_simple_functions", since = "1.9.0")]
pub fn clear(&mut self) {
self.inner.clear()
@@ -96,6 +220,15 @@ impl OsString {
/// Returns the capacity this `OsString` can hold without reallocating.
///
/// See `OsString` introduction for information about encoding.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ ///
+ /// let mut os_string = OsString::with_capacity(10);
+ /// assert!(os_string.capacity() >= 10);
+ /// ```
#[stable(feature = "osstring_simple_functions", since = "1.9.0")]
pub fn capacity(&self) -> usize {
self.inner.capacity()
@@ -105,6 +238,16 @@ impl OsString {
/// in the given `OsString`.
///
/// The collection may reserve more space to avoid frequent reallocations.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ ///
+ /// let mut s = OsString::new();
+ /// s.reserve(10);
+ /// assert!(s.capacity() >= 10);
+ /// ```
#[stable(feature = "osstring_simple_functions", since = "1.9.0")]
pub fn reserve(&mut self, additional: usize) {
self.inner.reserve(additional)
@@ -117,10 +260,59 @@ impl OsString {
/// 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.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ ///
+ /// let mut s = OsString::new();
+ /// s.reserve_exact(10);
+ /// assert!(s.capacity() >= 10);
+ /// ```
#[stable(feature = "osstring_simple_functions", since = "1.9.0")]
pub fn reserve_exact(&mut self, additional: usize) {
self.inner.reserve_exact(additional)
}
+
+ /// Shrinks the capacity of the `OsString` to match its length.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ ///
+ /// let mut s = OsString::from("foo");
+ ///
+ /// s.reserve(100);
+ /// assert!(s.capacity() >= 100);
+ ///
+ /// s.shrink_to_fit();
+ /// assert_eq!(3, s.capacity());
+ /// ```
+ #[stable(feature = "osstring_shrink_to_fit", since = "1.19.0")]
+ pub fn shrink_to_fit(&mut self) {
+ self.inner.shrink_to_fit()
+ }
+
+ /// Converts this `OsString` into a boxed [`OsStr`].
+ ///
+ /// [`OsStr`]: struct.OsStr.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::{OsString, OsStr};
+ ///
+ /// let s = OsString::from("hello");
+ ///
+ /// let b: Box<OsStr> = s.into_boxed_os_str();
+ /// ```
+ #[stable(feature = "into_boxed_os_str", since = "1.20.0")]
+ 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) }
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -167,8 +359,8 @@ impl Default for OsString {
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl Debug for OsString {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+impl fmt::Debug for OsString {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&**self, formatter)
}
}
@@ -253,26 +445,66 @@ impl OsStr {
}
fn from_inner(inner: &Slice) -> &OsStr {
- unsafe { mem::transmute(inner) }
+ unsafe { &*(inner as *const Slice as *const OsStr) }
}
- /// Yields a `&str` slice if the `OsStr` is valid Unicode.
+ /// Yields a [`&str`] slice if the `OsStr` is valid Unicode.
///
/// This conversion may entail doing a check for UTF-8 validity.
+ ///
+ /// [`&str`]: ../../std/primitive.str.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsStr;
+ ///
+ /// let os_str = OsStr::new("foo");
+ /// assert_eq!(os_str.to_str(), Some("foo"));
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn to_str(&self) -> Option<&str> {
self.inner.to_str()
}
- /// Converts an `OsStr` to a `Cow<str>`.
+ /// Converts an `OsStr` to a [`Cow`]`<`[`str`]`>`.
///
/// Any non-Unicode sequences are replaced with U+FFFD REPLACEMENT CHARACTER.
+ ///
+ /// [`Cow`]: ../../std/borrow/enum.Cow.html
+ /// [`str`]: ../../std/primitive.str.html
+ ///
+ /// # Examples
+ ///
+ /// Calling `to_string_lossy` on an `OsStr` with valid unicode:
+ ///
+ /// ```
+ /// use std::ffi::OsStr;
+ ///
+ /// let os_str = OsStr::new("foo");
+ /// assert_eq!(os_str.to_string_lossy(), "foo");
+ /// ```
+ ///
+ /// Had `os_str` contained invalid unicode, the `to_string_lossy` call might
+ /// have returned `"fo�"`.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn to_string_lossy(&self) -> Cow<str> {
self.inner.to_string_lossy()
}
- /// Copies the slice into an owned `OsString`.
+ /// Copies the slice into an owned [`OsString`].
+ ///
+ /// [`OsString`]: struct.OsString.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::{OsStr, OsString};
+ ///
+ /// let os_str = OsStr::new("foo");
+ /// let os_string = os_str.to_os_string();
+ /// assert_eq!(os_string, OsString::from("foo"));
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn to_os_string(&self) -> OsString {
OsString { inner: self.inner.to_owned() }
@@ -299,12 +531,15 @@ impl OsStr {
/// 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`
+ /// 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.
+ /// other methods like [`OsString::with_capacity`] to avoid reallocations.
///
/// See `OsStr` introduction for more information about encoding.
///
+ /// [`u16`]: ../primitive.u16.html
+ /// [`OsString::with_capacity`]: struct.OsString.html#method.with_capacity
+ ///
/// # Examples
///
/// ```
@@ -321,12 +556,88 @@ impl OsStr {
self.inner.inner.len()
}
+ /// Converts a [`Box`]`<OsStr>` into an [`OsString`] without copying or allocating.
+ ///
+ /// [`Box`]: ../boxed/struct.Box.html
+ /// [`OsString`]: struct.OsString.html
+ #[stable(feature = "into_boxed_os_str", since = "1.20.0")]
+ 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.
///
/// Note: it is *crucial* that this API is private, to avoid
/// revealing the internal, platform-specific encodings.
fn bytes(&self) -> &[u8] {
- unsafe { mem::transmute(&self.inner) }
+ unsafe { &*(&self.inner as *const _ as *const [u8]) }
+ }
+}
+
+#[stable(feature = "box_from_os_str", since = "1.17.0")]
+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) }
+ }
+}
+
+#[stable(feature = "os_string_from_box", since = "1.18.0")]
+impl From<Box<OsStr>> for OsString {
+ fn from(boxed: Box<OsStr>) -> OsString {
+ boxed.into_os_string()
+ }
+}
+
+#[stable(feature = "box_from_os_string", since = "1.20.0")]
+impl From<OsString> for Box<OsStr> {
+ fn from(s: OsString) -> Box<OsStr> {
+ s.into_boxed_os_str()
+ }
+}
+
+#[stable(feature = "shared_from_slice2", since = "1.24.0")]
+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) }
+ }
+}
+
+#[stable(feature = "shared_from_slice2", since = "1.24.0")]
+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) }
+ }
+}
+
+#[stable(feature = "shared_from_slice2", since = "1.24.0")]
+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) }
+ }
+}
+
+#[stable(feature = "shared_from_slice2", since = "1.24.0")]
+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) }
+ }
+}
+
+#[stable(feature = "box_default_extra", since = "1.17.0")]
+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) }
}
}
@@ -443,9 +754,15 @@ impl Hash for OsStr {
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl Debug for OsStr {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- self.inner.fmt(formatter)
+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)
}
}
@@ -457,7 +774,13 @@ impl Borrow<OsStr> for OsString {
#[stable(feature = "rust1", since = "1.0.0")]
impl ToOwned for OsStr {
type Owned = OsString;
- fn to_owned(&self) -> OsString { self.to_os_string() }
+ fn to_owned(&self) -> OsString {
+ self.to_os_string()
+ }
+ fn clone_into(&self, target: &mut OsString) {
+ target.clear();
+ target.push(self);
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -511,6 +834,9 @@ mod tests {
use super::*;
use sys_common::{AsInner, IntoInner};
+ use rc::Rc;
+ use sync::Arc;
+
#[test]
fn test_os_string_with_capacity() {
let os_string = OsString::with_capacity(0);
@@ -626,4 +952,48 @@ mod tests {
let os_str: &OsStr = Default::default();
assert_eq!("", os_str);
}
+
+ #[test]
+ fn into_boxed() {
+ let orig = "Hello, world!";
+ let os_str = OsStr::new(orig);
+ let boxed: Box<OsStr> = Box::from(os_str);
+ let os_string = os_str.to_owned().into_boxed_os_str().into_os_string();
+ assert_eq!(os_str, &*boxed);
+ assert_eq!(&*boxed, &*os_string);
+ assert_eq!(&*os_string, os_str);
+ }
+
+ #[test]
+ fn boxed_default() {
+ let boxed = <Box<OsStr>>::default();
+ assert!(boxed.is_empty());
+ }
+
+ #[test]
+ fn test_os_str_clone_into() {
+ let mut os_string = OsString::with_capacity(123);
+ os_string.push("hello");
+ let os_str = OsStr::new("bonjour");
+ os_str.clone_into(&mut os_string);
+ assert_eq!(os_str, os_string);
+ assert!(os_string.capacity() >= 123);
+ }
+
+ #[test]
+ fn into_rc() {
+ let orig = "Hello, world!";
+ let os_str = OsStr::new(orig);
+ let rc: Rc<OsStr> = Rc::from(os_str);
+ let arc: Arc<OsStr> = Arc::from(os_str);
+
+ assert_eq!(&*rc, os_str);
+ assert_eq!(&*arc, os_str);
+
+ let rc2: Rc<OsStr> = Rc::from(os_str.to_owned());
+ let arc2: Arc<OsStr> = Arc::from(os_str.to_owned());
+
+ assert_eq!(&*rc2, os_str);
+ assert_eq!(&*arc2, os_str);
+ }
}