about summary refs log tree commit diff
path: root/src/liballoc
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-01-12 10:54:51 +0100
committerGitHub <noreply@github.com>2019-01-12 10:54:51 +0100
commite69a5cb2d7d7a8ae40a6ea3687b7c1f319a2a8ea (patch)
treec2710fd1d04802eb92bcef10facef4ed041f6c15 /src/liballoc
parent0c91f3d97fe78d31c8cf3abb1858c65d73c6aa17 (diff)
parent986e49da04fbe2543267561eb8326765c9f48195 (diff)
downloadrust-e69a5cb2d7d7a8ae40a6ea3687b7c1f319a2a8ea.tar.gz
rust-e69a5cb2d7d7a8ae40a6ea3687b7c1f319a2a8ea.zip
Rollup merge of #56425 - scottmcm:redo-vec-set_len-docs, r=Centril
Redo the docs for Vec::set_len

Inspired by the [recent conversation on IRLO](https://internals.rust-lang.org/t/make-vec-set-len-enforce-the-len-cap-invariant/8927/23?u=scottmcm).

This is just my first stab at this; suggestions welcome.
Diffstat (limited to 'src/liballoc')
-rw-r--r--src/liballoc/vec.rs89
1 files changed, 62 insertions, 27 deletions
diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs
index b69c114ed45..e1c5ab15bb5 100644
--- a/src/liballoc/vec.rs
+++ b/src/liballoc/vec.rs
@@ -738,53 +738,88 @@ impl<T> Vec<T> {
         self
     }
 
-    /// Sets the length of a vector.
+    /// Forces the length of the vector to `new_len`.
     ///
-    /// This will explicitly set the size of the vector, without actually
-    /// modifying its buffers, so it is up to the caller to ensure that the
-    /// vector is actually the specified size.
+    /// This is a low-level operation that maintains none of the normal
+    /// invariants of the type.  Normally changing the length of a vector
+    /// is done using one of the safe operations instead, such as
+    /// [`truncate`], [`resize`], [`extend`], or [`clear`].
     ///
-    /// # Examples
+    /// [`truncate`]: #method.truncate
+    /// [`resize`]: #method.resize
+    /// [`extend`]: #method.extend-1
+    /// [`clear`]: #method.clear
     ///
-    /// ```
-    /// use std::ptr;
+    /// # Safety
     ///
-    /// let mut vec = vec!['r', 'u', 's', 't'];
+    /// - `new_len` must be less than or equal to [`capacity()`].
+    /// - The elements at `old_len..new_len` must be initialized.
     ///
-    /// unsafe {
-    ///     ptr::drop_in_place(&mut vec[3]);
-    ///     vec.set_len(3);
+    /// [`capacity()`]: #method.capacity
+    ///
+    /// # Examples
+    ///
+    /// This method can be useful for situations in which the vector
+    /// is serving as a buffer for other code, particularly over FFI:
+    ///
+    /// ```no_run
+    /// # #![allow(dead_code)]
+    /// # // This is just a minimal skeleton for the doc example;
+    /// # // don't use this as a starting point for a real library.
+    /// # pub struct StreamWrapper { strm: *mut std::ffi::c_void }
+    /// # const Z_OK: i32 = 0;
+    /// # extern "C" {
+    /// #     fn deflateGetDictionary(
+    /// #         strm: *mut std::ffi::c_void,
+    /// #         dictionary: *mut u8,
+    /// #         dictLength: *mut usize,
+    /// #     ) -> i32;
+    /// # }
+    /// # impl StreamWrapper {
+    /// pub fn get_dictionary(&self) -> Option<Vec<u8>> {
+    ///     // Per the FFI method's docs, "32768 bytes is always enough".
+    ///     let mut dict = Vec::with_capacity(32_768);
+    ///     let mut dict_length = 0;
+    ///     // SAFETY: When `deflateGetDictionary` returns `Z_OK`, it holds that:
+    ///     // 1. `dict_length` elements were initialized.
+    ///     // 2. `dict_length` <= the capacity (32_768)
+    ///     // which makes `set_len` safe to call.
+    ///     unsafe {
+    ///         // Make the FFI call...
+    ///         let r = deflateGetDictionary(self.strm, dict.as_mut_ptr(), &mut dict_length);
+    ///         if r == Z_OK {
+    ///             // ...and update the length to what was initialized.
+    ///             dict.set_len(dict_length);
+    ///             Some(dict)
+    ///         } else {
+    ///             None
+    ///         }
+    ///     }
     /// }
-    /// assert_eq!(vec, ['r', 'u', 's']);
+    /// # }
     /// ```
     ///
-    /// In this example, there is a memory leak since the memory locations
-    /// owned by the inner vectors were not freed prior to the `set_len` call:
+    /// While the following example is sound, there is a memory leak since
+    /// the inner vectors were not freed prior to the `set_len` call:
     ///
     /// ```
     /// let mut vec = vec![vec![1, 0, 0],
     ///                    vec![0, 1, 0],
     ///                    vec![0, 0, 1]];
+    /// // SAFETY:
+    /// // 1. `old_len..0` is empty so no elements need to be initialized.
+    /// // 2. `0 <= capacity` always holds whatever `capacity` is.
     /// unsafe {
     ///     vec.set_len(0);
     /// }
     /// ```
     ///
-    /// In this example, the vector gets expanded from zero to four items
-    /// without any memory allocations occurring, resulting in vector
-    /// values of unallocated memory:
-    ///
-    /// ```
-    /// let mut vec: Vec<char> = Vec::new();
-    ///
-    /// unsafe {
-    ///     vec.set_len(4);
-    /// }
-    /// ```
+    /// Normally, here, one would use [`clear`] instead to correctly drop
+    /// the contents and thus not leak memory.
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub unsafe fn set_len(&mut self, len: usize) {
-        self.len = len;
+    pub unsafe fn set_len(&mut self, new_len: usize) {
+        self.len = new_len;
     }
 
     /// Removes an element from the vector and returns it.