Skip to content

Commit 7685445

Browse files
bors[bot]samlich
andauthored
Merge #170
170: Buffer methods for Vec and as_mut_vec for String r=japaric a=samlich This adds `set_len` to `Vec`, identical to the `std` version, with the documentation copied from `std`. This is useful for using it as a buffer by writing to the uninitialized portion and then setting the length to include those bytes. It also adds `as_mut_vec` to `String` (also from `std`), which enables using `String` as a buffer in the same manner. Co-authored-by: samlich <1349989+samlich@users.noreply.github.com>
2 parents 4bb5df5 + 90d6524 commit 7685445

File tree

2 files changed

+128
-1
lines changed

2 files changed

+128
-1
lines changed

src/string.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,34 @@ where
178178
unsafe { str::from_utf8_unchecked_mut(self.0.vec.as_mut_slice()) }
179179
}
180180

181+
/// Returns a mutable reference to the contents of this `String`.
182+
///
183+
/// # Safety
184+
///
185+
/// This function is unsafe because it does not check that the bytes passed
186+
/// to it are valid UTF-8. If this constraint is violated, it may cause
187+
/// memory unsafety issues with future users of the `String`, as the rest of
188+
/// the library assumes that `String`s are valid UTF-8.
189+
///
190+
/// # Examples
191+
///
192+
/// Basic usage:
193+
///
194+
/// ```
195+
/// let mut s = String::from("hello");
196+
///
197+
/// unsafe {
198+
/// let vec = s.as_mut_vec();
199+
/// assert_eq!(&[104, 101, 108, 108, 111][..], &vec[..]);
200+
///
201+
/// vec.reverse();
202+
/// }
203+
/// assert_eq!(s, "olleh");
204+
/// ```
205+
pub unsafe fn as_mut_vec(&mut self) -> &mut Vec<u8, N> {
206+
&mut *(&mut self.0.vec as *mut crate::i::Vec<GenericArray<u8, N>> as *mut Vec<u8, N>)
207+
}
208+
181209
/// Appends a given string slice onto the end of this `String`.
182210
///
183211
/// # Examples

src/vec.rs

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,8 @@ where
160160
/// }
161161
/// assert_eq!(vec, [7, 1, 2, 3]);
162162
/// ```
163+
// repr(transparent) is needed for [`String::as_mut_vec`]
164+
#[repr(transparent)]
163165
pub struct Vec<T, N>(#[doc(hidden)] pub crate::i::Vec<GenericArray<T, N>>)
164166
where
165167
N: ArrayLength<T>;
@@ -327,6 +329,103 @@ where
327329
self.resize(new_len, T::default())
328330
}
329331

332+
/// Forces the length of the vector to `new_len`.
333+
///
334+
/// This is a low-level operation that maintains none of the normal
335+
/// invariants of the type. Normally changing the length of a vector
336+
/// is done using one of the safe operations instead, such as
337+
/// [`truncate`], [`resize`], [`extend`], or [`clear`].
338+
///
339+
/// [`truncate`]: #method.truncate
340+
/// [`resize`]: #method.resize
341+
/// [`extend`]: https://doc.rust-lang.org/stable/core/iter/trait.Extend.html#tymethod.extend
342+
/// [`clear`]: #method.clear
343+
///
344+
/// # Safety
345+
///
346+
/// - `new_len` must be less than or equal to [`capacity()`].
347+
/// - The elements at `old_len..new_len` must be initialized.
348+
///
349+
/// [`capacity()`]: #method.capacity
350+
///
351+
/// # Examples
352+
///
353+
/// This method can be useful for situations in which the vector
354+
/// is serving as a buffer for other code, particularly over FFI:
355+
///
356+
/// ```no_run
357+
/// # #![allow(dead_code)]
358+
/// use heapless::Vec;
359+
/// use heapless::consts::*;
360+
///
361+
/// # // This is just a minimal skeleton for the doc example;
362+
/// # // don't use this as a starting point for a real library.
363+
/// # pub struct StreamWrapper { strm: *mut core::ffi::c_void }
364+
/// # const Z_OK: i32 = 0;
365+
/// # extern "C" {
366+
/// # fn deflateGetDictionary(
367+
/// # strm: *mut core::ffi::c_void,
368+
/// # dictionary: *mut u8,
369+
/// # dictLength: *mut usize,
370+
/// # ) -> i32;
371+
/// # }
372+
/// # impl StreamWrapper {
373+
/// pub fn get_dictionary(&self) -> Option<Vec<u8, U32768>> {
374+
/// // Per the FFI method's docs, "32768 bytes is always enough".
375+
/// let mut dict = Vec::new();
376+
/// let mut dict_length = 0;
377+
/// // SAFETY: When `deflateGetDictionary` returns `Z_OK`, it holds that:
378+
/// // 1. `dict_length` elements were initialized.
379+
/// // 2. `dict_length` <= the capacity (32_768)
380+
/// // which makes `set_len` safe to call.
381+
/// unsafe {
382+
/// // Make the FFI call...
383+
/// let r = deflateGetDictionary(self.strm, dict.as_mut_ptr(), &mut dict_length);
384+
/// if r == Z_OK {
385+
/// // ...and update the length to what was initialized.
386+
/// dict.set_len(dict_length);
387+
/// Some(dict)
388+
/// } else {
389+
/// None
390+
/// }
391+
/// }
392+
/// }
393+
/// # }
394+
/// ```
395+
///
396+
/// While the following example is sound, there is a memory leak since
397+
/// the inner vectors were not freed prior to the `set_len` call:
398+
///
399+
/// ```
400+
/// use core::iter::FromIterator;
401+
/// use heapless::Vec;
402+
/// use heapless::consts::*;
403+
///
404+
/// let mut vec = Vec::<Vec<u8, U3>, U3>::from_iter(
405+
/// [
406+
/// Vec::from_iter([1, 0, 0].iter().cloned()),
407+
/// Vec::from_iter([0, 1, 0].iter().cloned()),
408+
/// Vec::from_iter([0, 0, 1].iter().cloned()),
409+
/// ]
410+
/// .iter()
411+
/// .cloned()
412+
/// );
413+
/// // SAFETY:
414+
/// // 1. `old_len..0` is empty so no elements need to be initialized.
415+
/// // 2. `0 <= capacity` always holds whatever `capacity` is.
416+
/// unsafe {
417+
/// vec.set_len(0);
418+
/// }
419+
/// ```
420+
///
421+
/// Normally, here, one would use [`clear`] instead to correctly drop
422+
/// the contents and thus not leak memory.
423+
pub unsafe fn set_len(&mut self, new_len: usize) {
424+
debug_assert!(new_len <= self.capacity());
425+
426+
self.0.len = new_len
427+
}
428+
330429
/// Removes an element from the vector and returns it.
331430
///
332431
/// The removed element is replaced by the last element of the vector.
@@ -726,8 +825,8 @@ where
726825

727826
#[cfg(test)]
728827
mod tests {
729-
use as_slice::AsSlice;
730828
use crate::{consts::*, Vec};
829+
use as_slice::AsSlice;
731830
use core::fmt::Write;
732831

733832
#[test]

0 commit comments

Comments
 (0)