From 0364e0576607caf49d198c517801f278bba53bcd Mon Sep 17 00:00:00 2001 From: samlich <1349989+samlich@users.noreply.github.com> Date: Fri, 24 Jul 2020 12:25:54 +0000 Subject: [PATCH] Vec: add set_len --- src/vec.rs | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 98 insertions(+), 1 deletion(-) diff --git a/src/vec.rs b/src/vec.rs index f3553fce..70c1878d 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -327,6 +327,103 @@ where self.resize(new_len, T::default()) } + /// Forces the length of the vector to `new_len`. + /// + /// 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`]. + /// + /// [`truncate`]: #method.truncate + /// [`resize`]: #method.resize + /// [`extend`]: https://doc.rust-lang.org/stable/core/iter/trait.Extend.html#tymethod.extend + /// [`clear`]: #method.clear + /// + /// # Safety + /// + /// - `new_len` must be less than or equal to [`capacity()`]. + /// - The elements at `old_len..new_len` must be initialized. + /// + /// [`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)] + /// use heapless::Vec; + /// use heapless::consts::*; + /// + /// # // 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 core::ffi::c_void } + /// # const Z_OK: i32 = 0; + /// # extern "C" { + /// # fn deflateGetDictionary( + /// # strm: *mut core::ffi::c_void, + /// # dictionary: *mut u8, + /// # dictLength: *mut usize, + /// # ) -> i32; + /// # } + /// # impl StreamWrapper { + /// pub fn get_dictionary(&self) -> Option> { + /// // Per the FFI method's docs, "32768 bytes is always enough". + /// let mut dict = Vec::new(); + /// 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 + /// } + /// } + /// } + /// # } + /// ``` + /// + /// While the following example is sound, there is a memory leak since + /// the inner vectors were not freed prior to the `set_len` call: + /// + /// ``` + /// use core::iter::FromIterator; + /// use heapless::Vec; + /// use heapless::consts::*; + /// + /// let mut vec = Vec::, U3>::from_iter( + /// [ + /// Vec::from_iter([1, 0, 0].iter().cloned()), + /// Vec::from_iter([0, 1, 0].iter().cloned()), + /// Vec::from_iter([0, 0, 1].iter().cloned()), + /// ] + /// .iter() + /// .cloned() + /// ); + /// // 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); + /// } + /// ``` + /// + /// Normally, here, one would use [`clear`] instead to correctly drop + /// the contents and thus not leak memory. + pub unsafe fn set_len(&mut self, new_len: usize) { + debug_assert!(new_len <= self.capacity()); + + self.0.len = new_len + } + /// Removes an element from the vector and returns it. /// /// The removed element is replaced by the last element of the vector. @@ -726,8 +823,8 @@ where #[cfg(test)] mod tests { - use as_slice::AsSlice; use crate::{consts::*, Vec}; + use as_slice::AsSlice; use core::fmt::Write; #[test]