From 2338d7419743f876135f723d1823dde16bdb7fdf Mon Sep 17 00:00:00 2001
From: Corey Farwell <coreyf@rwell.org>
Date: Fri, 12 Feb 2016 12:21:57 -0500
Subject: [PATCH] Add Capacity/length methods for OsString.

https://github.com/rust-lang/rust/issues/29453
---
 src/libstd/ffi/os_str.rs         | 178 +++++++++++++++++++++++++++++++
 src/libstd/sys/common/wtf8.rs    |  14 +++
 src/libstd/sys/unix/os_str.rs    |  41 +++++++
 src/libstd/sys/windows/os_str.rs |  35 ++++++
 4 files changed, 268 insertions(+)

diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs
index eb5ddecbd054d..90ea7396a8ab3 100644
--- a/src/libstd/ffi/os_str.rs
+++ b/src/libstd/ffi/os_str.rs
@@ -102,6 +102,58 @@ impl OsString {
     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` bytes without reallocating. If
+    /// `capacity` is 0, the string will not allocate.
+    ///
+    /// See main `OsString` documentation information about encoding.
+    #[unstable(feature = "osstring_simple_functions",
+               reason = "recently added", issue = "29453")]
+    pub fn with_capacity(capacity: usize) -> OsString {
+        OsString {
+            inner: Buf::with_capacity(capacity)
+        }
+    }
+
+    /// Truncates the `OsString` to zero length.
+    #[unstable(feature = "osstring_simple_functions",
+               reason = "recently added", issue = "29453")]
+    pub fn clear(&mut self) {
+        self.inner.clear()
+    }
+
+    /// Returns the number of bytes this `OsString` can hold without
+    /// reallocating.
+    ///
+    /// See `OsString` introduction for information about encoding.
+    #[unstable(feature = "osstring_simple_functions",
+               reason = "recently added", issue = "29453")]
+    pub fn capacity(&self) -> usize {
+        self.inner.capacity()
+    }
+
+    /// Reserves capacity for at least `additional` more bytes to be inserted
+    /// in the given `OsString`. The collection may reserve more space to avoid
+    /// frequent reallocations.
+    #[unstable(feature = "osstring_simple_functions",
+               reason = "recently added", issue = "29453")]
+    pub fn reserve(&mut self, additional: usize) {
+        self.inner.reserve(additional)
+    }
+
+    /// Reserves the minimum capacity for exactly `additional` more bytes 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.
+    #[unstable(feature = "osstring_simple_functions",
+               reason = "recently added", issue = "29453")]
+    pub fn reserve_exact(&mut self, additional: usize) {
+        self.inner.reserve_exact(additional)
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -277,6 +329,22 @@ impl OsStr {
         self.to_bytes().and_then(|b| CString::new(b).ok())
     }
 
+    /// Checks whether the `OsStr` is empty.
+    #[unstable(feature = "osstring_simple_functions",
+               reason = "recently added", issue = "29453")]
+    pub fn is_empty(&self) -> bool {
+        self.inner.inner.is_empty()
+    }
+
+    /// Returns the number of bytes in this `OsStr`.
+    ///
+    /// See `OsStr` introduction for information about encoding.
+    #[unstable(feature = "osstring_simple_functions",
+               reason = "recently added", issue = "29453")]
+    pub fn len(&self) -> usize {
+        self.inner.inner.len()
+    }
+
     /// Gets the underlying byte representation.
     ///
     /// Note: it is *crucial* that this API is private, to avoid
@@ -414,3 +482,113 @@ impl AsInner<Slice> for OsStr {
         &self.inner
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use sys_common::{AsInner, IntoInner};
+
+    #[test]
+    fn test_os_string_with_capacity() {
+        let os_string = OsString::with_capacity(0);
+        assert_eq!(0, os_string.inner.into_inner().capacity());
+
+        let os_string = OsString::with_capacity(10);
+        assert_eq!(10, os_string.inner.into_inner().capacity());
+
+        let mut os_string = OsString::with_capacity(0);
+        os_string.push("abc");
+        assert!(os_string.inner.into_inner().capacity() >= 3);
+    }
+
+    #[test]
+    fn test_os_string_clear() {
+        let mut os_string = OsString::from("abc");
+        assert_eq!(3, os_string.inner.as_inner().len());
+
+        os_string.clear();
+        assert_eq!(&os_string, "");
+        assert_eq!(0, os_string.inner.as_inner().len());
+    }
+
+    #[test]
+    fn test_os_string_capacity() {
+        let os_string = OsString::with_capacity(0);
+        assert_eq!(0, os_string.capacity());
+
+        let os_string = OsString::with_capacity(10);
+        assert_eq!(10, os_string.capacity());
+
+        let mut os_string = OsString::with_capacity(0);
+        os_string.push("abc");
+        assert!(os_string.capacity() >= 3);
+    }
+
+    #[test]
+    fn test_os_string_reserve() {
+        let mut os_string = OsString::new();
+        assert_eq!(os_string.capacity(), 0);
+
+        os_string.reserve(2);
+        assert!(os_string.capacity() >= 2);
+
+        for _ in 0..16 {
+            os_string.push("a");
+        }
+
+        assert!(os_string.capacity() >= 16);
+        os_string.reserve(16);
+        assert!(os_string.capacity() >= 32);
+
+        os_string.push("a");
+
+        os_string.reserve(16);
+        assert!(os_string.capacity() >= 33)
+    }
+
+    #[test]
+    fn test_os_string_reserve_exact() {
+        let mut os_string = OsString::new();
+        assert_eq!(os_string.capacity(), 0);
+
+        os_string.reserve_exact(2);
+        assert!(os_string.capacity() >= 2);
+
+        for _ in 0..16 {
+            os_string.push("a");
+        }
+
+        assert!(os_string.capacity() >= 16);
+        os_string.reserve_exact(16);
+        assert!(os_string.capacity() >= 32);
+
+        os_string.push("a");
+
+        os_string.reserve_exact(16);
+        assert!(os_string.capacity() >= 33)
+    }
+
+    #[test]
+    fn test_os_str_is_empty() {
+        let mut os_string = OsString::new();
+        assert!(os_string.is_empty());
+
+        os_string.push("abc");
+        assert!(!os_string.is_empty());
+
+        os_string.clear();
+        assert!(os_string.is_empty());
+    }
+
+    #[test]
+    fn test_os_str_len() {
+        let mut os_string = OsString::new();
+        assert_eq!(0, os_string.len());
+
+        os_string.push("abc");
+        assert_eq!(3, os_string.len());
+
+        os_string.clear();
+        assert_eq!(0, os_string.len());
+    }
+}
diff --git a/src/libstd/sys/common/wtf8.rs b/src/libstd/sys/common/wtf8.rs
index bc997af3a27e4..68ba2fe20b4b3 100644
--- a/src/libstd/sys/common/wtf8.rs
+++ b/src/libstd/sys/common/wtf8.rs
@@ -178,6 +178,10 @@ impl Wtf8Buf {
         Wtf8Buf { bytes: <[_]>::to_vec(str.as_bytes()) }
     }
 
+    pub fn clear(&mut self) {
+        self.bytes.clear()
+    }
+
     /// Creates a WTF-8 string from a potentially ill-formed UTF-16 slice of 16-bit code units.
     ///
     /// This is lossless: calling `.encode_wide()` on the resulting string
@@ -234,6 +238,11 @@ impl Wtf8Buf {
         self.bytes.reserve(additional)
     }
 
+    #[inline]
+    pub fn reserve_exact(&mut self, additional: usize) {
+        self.bytes.reserve_exact(additional)
+    }
+
     /// Returns the number of bytes that this string buffer can hold without reallocating.
     #[inline]
     pub fn capacity(&self) -> usize {
@@ -443,6 +452,11 @@ impl Wtf8 {
         self.bytes.len()
     }
 
+    #[inline]
+    pub fn is_empty(&self) -> bool {
+        self.bytes.is_empty()
+    }
+
     /// Returns the code point at `position` if it is in the ASCII range,
     /// or `b'\xFF' otherwise.
     ///
diff --git a/src/libstd/sys/unix/os_str.rs b/src/libstd/sys/unix/os_str.rs
index 0524df218a14c..d5eea5d1f3be5 100644
--- a/src/libstd/sys/unix/os_str.rs
+++ b/src/libstd/sys/unix/os_str.rs
@@ -17,6 +17,7 @@ use vec::Vec;
 use str;
 use string::String;
 use mem;
+use sys_common::{AsInner, IntoInner};
 
 #[derive(Clone, Hash)]
 pub struct Buf {
@@ -39,11 +40,51 @@ impl Debug for Buf {
     }
 }
 
+impl IntoInner<Vec<u8>> for Buf {
+    fn into_inner(self) -> Vec<u8> {
+        self.inner
+    }
+}
+
+impl AsInner<[u8]> for Buf {
+    fn as_inner(&self) -> &[u8] {
+        &self.inner
+    }
+}
+
+
 impl Buf {
     pub fn from_string(s: String) -> Buf {
         Buf { inner: s.into_bytes() }
     }
 
+    #[inline]
+    pub fn with_capacity(capacity: usize) -> Buf {
+        Buf {
+            inner: Vec::with_capacity(capacity)
+        }
+    }
+
+    #[inline]
+    pub fn clear(&mut self) {
+        self.inner.clear()
+    }
+
+    #[inline]
+    pub fn capacity(&self) -> usize {
+        self.inner.capacity()
+    }
+
+    #[inline]
+    pub fn reserve(&mut self, additional: usize) {
+        self.inner.reserve(additional)
+    }
+
+    #[inline]
+    pub fn reserve_exact(&mut self, additional: usize) {
+        self.inner.reserve_exact(additional)
+    }
+
     pub fn as_slice(&self) -> &Slice {
         unsafe { mem::transmute(&*self.inner) }
     }
diff --git a/src/libstd/sys/windows/os_str.rs b/src/libstd/sys/windows/os_str.rs
index 91905ae7489d5..26767a1349e6f 100644
--- a/src/libstd/sys/windows/os_str.rs
+++ b/src/libstd/sys/windows/os_str.rs
@@ -18,12 +18,25 @@ use string::String;
 use result::Result;
 use option::Option;
 use mem;
+use sys_common::{AsInner, IntoInner};
 
 #[derive(Clone, Hash)]
 pub struct Buf {
     pub inner: Wtf8Buf
 }
 
+impl IntoInner<Wtf8Buf> for Buf {
+    fn into_inner(self) -> Wtf8Buf {
+        self.inner
+    }
+}
+
+impl AsInner<Wtf8> for Buf {
+    fn as_inner(&self) -> &Wtf8 {
+        &self.inner
+    }
+}
+
 impl Debug for Buf {
     fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
         self.as_slice().fmt(formatter)
@@ -41,6 +54,20 @@ impl Debug for Slice {
 }
 
 impl Buf {
+    pub fn with_capacity(capacity: usize) -> Buf {
+        Buf {
+            inner: Wtf8Buf::with_capacity(capacity)
+        }
+    }
+
+    pub fn clear(&mut self) {
+        self.inner.clear()
+    }
+
+    pub fn capacity(&self) -> usize {
+        self.inner.capacity()
+    }
+
     pub fn from_string(s: String) -> Buf {
         Buf { inner: Wtf8Buf::from_string(s) }
     }
@@ -56,6 +83,14 @@ impl Buf {
     pub fn push_slice(&mut self, s: &Slice) {
         self.inner.push_wtf8(&s.inner)
     }
+
+    pub fn reserve(&mut self, additional: usize) {
+        self.inner.reserve(additional)
+    }
+
+    pub fn reserve_exact(&mut self, additional: usize) {
+        self.inner.reserve_exact(additional)
+    }
 }
 
 impl Slice {