Skip to content

Commit 303fec8

Browse files
Genericise drain function over storage
1 parent cfb636a commit 303fec8

File tree

2 files changed

+26
-111
lines changed

2 files changed

+26
-111
lines changed

src/string/mod.rs

Lines changed: 24 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -59,71 +59,6 @@ pub type String<const N: usize> = StringInner<OwnedVecStorage<u8, N>>;
5959
/// A dynamic capacity [`String`](https://doc.rust-lang.org/std/string/struct.String.html).
6060
pub type StringView = StringInner<ViewVecStorage<u8>>;
6161

62-
impl StringView {
63-
/// Removes the specified range from the string in bulk, returning all
64-
/// removed characters as an iterator.
65-
///
66-
/// The returned iterator keeps a mutable borrow on the string to optimize
67-
/// its implementation.
68-
///
69-
/// # Panics
70-
///
71-
/// Panics if the starting point or end point do not lie on a [`char`]
72-
/// boundary, or if they're out of bounds.
73-
///
74-
/// # Leaking
75-
///
76-
/// If the returned iterator goes out of scope without being dropped (due to
77-
/// [`core::mem::forget`], for example), the string may still contain a copy
78-
/// of any drained characters, or may have lost characters arbitrarily,
79-
/// including characters outside the range.
80-
///
81-
/// # Examples
82-
///
83-
/// ```
84-
/// use heapless::String;
85-
///
86-
/// let mut s = String::<32>::try_from("α is alpha, β is beta").unwrap();
87-
/// let beta_offset = s.find('β').unwrap_or(s.len());
88-
///
89-
/// // Remove the range up until the β from the string
90-
/// let t: String<32> = s.drain(..beta_offset).collect();
91-
/// assert_eq!(t, "α is alpha, ");
92-
/// assert_eq!(s, "β is beta");
93-
///
94-
/// // A full range clears the string, like `clear()` does
95-
/// s.drain(..);
96-
/// assert_eq!(s, "");
97-
/// ```
98-
pub fn drain<R>(&mut self, range: R) -> Drain<'_>
99-
where
100-
R: RangeBounds<usize>,
101-
{
102-
// Memory safety
103-
//
104-
// The `String` version of `Drain` does not have the memory safety issues
105-
// of the `Vec` version. The data is just plain bytes.
106-
// Because the range removal happens in `Drop`, if the `Drain` iterator is leaked,
107-
// the removal will not happen.
108-
let Range { start, end } = crate::slice::range(range, ..self.len());
109-
assert!(self.is_char_boundary(start));
110-
assert!(self.is_char_boundary(end));
111-
112-
// Take out two simultaneous borrows. The &mut String won't be accessed
113-
// until iteration is over, in Drop.
114-
let self_ptr = self as *mut _;
115-
// SAFETY: `slice::range` and `is_char_boundary` do the appropriate bounds checks.
116-
let chars_iter = unsafe { self.get_unchecked(start..end) }.chars();
117-
118-
Drain {
119-
start,
120-
end,
121-
iter: chars_iter,
122-
string: self_ptr,
123-
}
124-
}
125-
}
126-
12762
impl<const N: usize> String<N> {
12863
/// Constructs a new, empty `String` with a fixed capacity of `N` bytes.
12964
///
@@ -266,7 +201,9 @@ impl<const N: usize> String<N> {
266201
pub fn into_bytes(self) -> Vec<u8, N> {
267202
self.vec
268203
}
204+
}
269205

206+
impl<S: VecStorage<u8> + ?Sized> StringInner<S> {
270207
/// Removes the specified range from the string in bulk, returning all
271208
/// removed characters as an iterator.
272209
///
@@ -306,11 +243,30 @@ impl<const N: usize> String<N> {
306243
where
307244
R: RangeBounds<usize>,
308245
{
309-
self.as_mut_view().drain(range)
246+
// Memory safety
247+
//
248+
// The `String` version of `Drain` does not have the memory safety issues
249+
// of the `Vec` version. The data is just plain bytes.
250+
// Because the range removal happens in `Drop`, if the `Drain` iterator is leaked,
251+
// the removal will not happen.
252+
let Range { start, end } = crate::slice::range(range, ..self.len());
253+
assert!(self.is_char_boundary(start));
254+
assert!(self.is_char_boundary(end));
255+
256+
// Take out two simultaneous borrows. The &mut String won't be accessed
257+
// until iteration is over, in Drop.
258+
let self_ptr = self.as_mut_view() as *mut _;
259+
// SAFETY: `slice::range` and `is_char_boundary` do the appropriate bounds checks.
260+
let chars_iter = unsafe { self.get_unchecked(start..end) }.chars();
261+
262+
Drain {
263+
start,
264+
end,
265+
iter: chars_iter,
266+
string: self_ptr,
267+
}
310268
}
311-
}
312269

313-
impl<S: VecStorage<u8> + ?Sized> StringInner<S> {
314270
/// Get a reference to the `String`, erasing the `N` const-generic.
315271
///
316272
///

src/vec/mod.rs

Lines changed: 2 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -480,45 +480,6 @@ impl<T, const N: usize> Vec<T, N> {
480480
new
481481
}
482482

483-
/// Removes the specified range from the vector in bulk, returning all
484-
/// removed elements as an iterator. If the iterator is dropped before
485-
/// being fully consumed, it drops the remaining removed elements.
486-
///
487-
/// The returned iterator keeps a mutable borrow on the vector to optimize
488-
/// its implementation.
489-
///
490-
/// # Panics
491-
///
492-
/// Panics if the starting point is greater than the end point or if
493-
/// the end point is greater than the length of the vector.
494-
///
495-
/// # Leaking
496-
///
497-
/// If the returned iterator goes out of scope without being dropped (due to
498-
/// [`mem::forget`], for example), the vector may have lost and leaked
499-
/// elements arbitrarily, including elements outside the range.
500-
///
501-
/// # Examples
502-
///
503-
/// ```
504-
/// use heapless::Vec;
505-
///
506-
/// let mut v = Vec::<_, 8>::from_array([1, 2, 3]);
507-
/// let u: Vec<_, 8> = v.drain(1..).collect();
508-
/// assert_eq!(v, &[1]);
509-
/// assert_eq!(u, &[2, 3]);
510-
///
511-
/// // A full range clears the vector, like `clear()` does.
512-
/// v.drain(..);
513-
/// assert_eq!(v, &[]);
514-
/// ```
515-
pub fn drain<R>(&mut self, range: R) -> Drain<'_, T>
516-
where
517-
R: RangeBounds<usize>,
518-
{
519-
self.as_mut_view().drain(range)
520-
}
521-
522483
/// Returns the maximum number of elements the vector can hold.
523484
///
524485
/// This method is not available on a `VecView`, use [`storage_len`](VecInner::storage_capacity) instead
@@ -527,7 +488,7 @@ impl<T, const N: usize> Vec<T, N> {
527488
}
528489
}
529490

530-
impl<T> VecView<T> {
491+
impl<T, S: VecStorage<T> + ?Sized> VecInner<T, S> {
531492
/// Removes the specified range from the vector in bulk, returning all
532493
/// removed elements as an iterator. If the iterator is dropped before
533494
/// being fully consumed, it drops the remaining removed elements.
@@ -580,7 +541,7 @@ impl<T> VecView<T> {
580541
unsafe {
581542
// Set `self.vec` length's to `start`, to be safe in case `Drain` is leaked.
582543
self.set_len(start);
583-
let vec = NonNull::from(self);
544+
let vec = NonNull::from(self.as_mut_view());
584545
let range_slice = slice::from_raw_parts(vec.as_ref().as_ptr().add(start), end - start);
585546
Drain {
586547
tail_start: end,
@@ -590,9 +551,7 @@ impl<T> VecView<T> {
590551
}
591552
}
592553
}
593-
}
594554

595-
impl<T, S: VecStorage<T> + ?Sized> VecInner<T, S> {
596555
/// Get a reference to the `Vec`, erasing the `N` const-generic.
597556
///
598557
///

0 commit comments

Comments
 (0)