Skip to content

Commit 7da0b18

Browse files
committed
rust: alloc: vec: Import .drain() / Drain from rust library
Contains the implementation from https://github.com/rust-lang/rust/blob/1.82.0/library/alloc/src/vec/mod.rs and the Drain struct from https://github.com/rust-lang/rust/blob/1.82.0/library/alloc/src/vec/drain.rs modified for the Kernel. Signed-off-by: Janne Grunau <j@jannau.net>
1 parent bbda769 commit 7da0b18

4 files changed

Lines changed: 252 additions & 0 deletions

File tree

rust/kernel/alloc/kvec.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,15 @@ use core::{
1616
ops::DerefMut,
1717
ops::Index,
1818
ops::IndexMut,
19+
ops::{Range, RangeBounds},
1920
ptr,
2021
ptr::NonNull,
2122
slice,
2223
slice::SliceIndex,
2324
};
2425

26+
mod drain;
27+
use self::drain::Drain;
2528
mod errors;
2629
pub use self::errors::{InsertError, PushError, RemoveError};
2730

@@ -732,6 +735,56 @@ where
732735
}
733736
self.truncate(num_kept);
734737
}
738+
739+
/// Removes the specified range from the vector in bulk, returning all
740+
/// removed elements as an iterator. If the iterator is dropped before
741+
/// being fully consumed, it drops the remaining removed elements.
742+
///
743+
/// The returned iterator keeps a mutable borrow on the vector to optimize
744+
/// its implementation.
745+
///
746+
/// # Panics
747+
///
748+
/// Panics if the starting point is greater than the end point or if
749+
/// the end point is greater than the length of the vector.
750+
///
751+
/// # Leaking
752+
///
753+
/// If the returned iterator goes out of scope without being dropped (due to
754+
/// [`mem::forget`], for example), the vector may have lost and leaked
755+
/// elements arbitrarily, including elements outside the range.
756+
///
757+
/// # Examples
758+
///
759+
/// ```
760+
/// let mut v = vec![1, 2, 3];
761+
/// let u: Vec<_> = v.drain(1..).collect();
762+
/// assert_eq!(v, &[1]);
763+
/// assert_eq!(u, &[2, 3]);
764+
///
765+
/// // A full range clears the vector, like `clear()` does
766+
/// v.drain(..);
767+
/// assert_eq!(v, &[]);
768+
/// ```
769+
pub fn drain<R>(&mut self, range: R) -> Drain<'_, T, A>
770+
where
771+
R: RangeBounds<usize>,
772+
{
773+
let len = self.len();
774+
let Range { start, end } = slice::range(range, ..len);
775+
776+
unsafe {
777+
// set self.vec length's to start, to be safe in case Drain is leaked
778+
self.set_len(start);
779+
let range_slice = slice::from_raw_parts(self.as_ptr().add(start), end - start);
780+
Drain {
781+
tail_start: end,
782+
tail_len: len - end,
783+
iter: range_slice.iter(),
784+
vec: NonNull::from(self),
785+
}
786+
}
787+
}
735788
}
736789

737790
impl<T: Clone, A: Allocator> Vec<T, A> {

rust/kernel/alloc/kvec/drain.rs

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
//! Rust standard library vendored code.
2+
//!
3+
//! The contents of this file come from the Rust standard library, hosted in
4+
//! the <https://github.com/rust-lang/rust> repository, licensed under
5+
//! "Apache-2.0 OR MIT" and adapted for kernel use. For copyright details,
6+
//! see <https://github.com/rust-lang/rust/blob/master/COPYRIGHT>.
7+
#![allow(clippy::undocumented_unsafe_blocks)]
8+
9+
use core::fmt;
10+
use core::iter::FusedIterator;
11+
use core::mem::{self, SizedTypeProperties};
12+
use core::ptr::{self, NonNull};
13+
use core::slice::{self};
14+
15+
use super::{Allocator, Vec};
16+
17+
/// A draining iterator for `Vec<T>`.
18+
///
19+
/// This `struct` is created by [`Vec::drain`].
20+
/// See its documentation for more.
21+
///
22+
/// # Example
23+
///
24+
/// ```
25+
/// let mut v = vec![0, 1, 2];
26+
/// let iter: std::vec::Drain<'_, _> = v.drain(..);
27+
/// ```
28+
// #[stable(feature = "drain", since = "1.6.0")]
29+
pub struct Drain<
30+
'a,
31+
T,
32+
A: Allocator,
33+
// #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + 'a = Global,
34+
> {
35+
/// Index of tail to preserve
36+
pub(super) tail_start: usize,
37+
/// Length of tail
38+
pub(super) tail_len: usize,
39+
/// Current remaining range to remove
40+
pub(super) iter: slice::Iter<'a, T>,
41+
pub(super) vec: NonNull<Vec<T, A>>,
42+
}
43+
44+
// #[stable(feature = "collection_debug", since = "1.17.0")]
45+
impl<T: fmt::Debug, A: Allocator> fmt::Debug for Drain<'_, T, A> {
46+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47+
f.debug_tuple("Drain").field(&self.iter.as_slice()).finish()
48+
}
49+
}
50+
51+
impl<'a, T, A: Allocator> Drain<'a, T, A> {
52+
/// Returns the remaining items of this iterator as a slice.
53+
///
54+
/// # Examples
55+
///
56+
/// ```
57+
/// let mut vec = vec!['a', 'b', 'c'];
58+
/// let mut drain = vec.drain(..);
59+
/// assert_eq!(drain.as_slice(), &['a', 'b', 'c']);
60+
/// let _ = drain.next().unwrap();
61+
/// assert_eq!(drain.as_slice(), &['b', 'c']);
62+
/// ```
63+
#[must_use]
64+
// #[stable(feature = "vec_drain_as_slice", since = "1.46.0")]
65+
pub fn as_slice(&self) -> &[T] {
66+
self.iter.as_slice()
67+
}
68+
}
69+
70+
// #[stable(feature = "vec_drain_as_slice", since = "1.46.0")]
71+
impl<'a, T, A: Allocator> AsRef<[T]> for Drain<'a, T, A> {
72+
fn as_ref(&self) -> &[T] {
73+
self.as_slice()
74+
}
75+
}
76+
77+
// #[stable(feature = "drain", since = "1.6.0")]
78+
unsafe impl<T: Sync, A: Sync + Allocator> Sync for Drain<'_, T, A> {}
79+
// #[stable(feature = "drain", since = "1.6.0")]
80+
unsafe impl<T: Send, A: Send + Allocator> Send for Drain<'_, T, A> {}
81+
82+
// #[stable(feature = "drain", since = "1.6.0")]
83+
impl<T, A: Allocator> Iterator for Drain<'_, T, A> {
84+
type Item = T;
85+
86+
#[inline]
87+
fn next(&mut self) -> Option<T> {
88+
self.iter
89+
.next()
90+
.map(|elt| unsafe { ptr::read(elt as *const _) })
91+
}
92+
93+
fn size_hint(&self) -> (usize, Option<usize>) {
94+
self.iter.size_hint()
95+
}
96+
}
97+
98+
// #[stable(feature = "drain", since = "1.6.0")]
99+
impl<T, A: Allocator> DoubleEndedIterator for Drain<'_, T, A> {
100+
#[inline]
101+
fn next_back(&mut self) -> Option<T> {
102+
self.iter
103+
.next_back()
104+
.map(|elt| unsafe { ptr::read(elt as *const _) })
105+
}
106+
}
107+
108+
// #[stable(feature = "drain", since = "1.6.0")]
109+
impl<T, A: Allocator> Drop for Drain<'_, T, A> {
110+
fn drop(&mut self) {
111+
/// Moves back the un-`Drain`ed elements to restore the original `Vec`.
112+
struct DropGuard<'r, 'a, T, A: Allocator>(&'r mut Drain<'a, T, A>);
113+
114+
impl<'r, 'a, T, A: Allocator> Drop for DropGuard<'r, 'a, T, A> {
115+
fn drop(&mut self) {
116+
if self.0.tail_len > 0 {
117+
unsafe {
118+
let source_vec = self.0.vec.as_mut();
119+
// memmove back untouched tail, update to new length
120+
let start = source_vec.len();
121+
let tail = self.0.tail_start;
122+
if tail != start {
123+
let src = source_vec.as_ptr().add(tail);
124+
let dst = source_vec.as_mut_ptr().add(start);
125+
ptr::copy(src, dst, self.0.tail_len);
126+
}
127+
source_vec.set_len(start + self.0.tail_len);
128+
}
129+
}
130+
}
131+
}
132+
133+
let iter = mem::take(&mut self.iter);
134+
let drop_len = iter.len();
135+
136+
let mut vec = self.vec;
137+
138+
if T::IS_ZST {
139+
// ZSTs have no identity, so we don't need to move them around, we only need to drop the correct amount.
140+
// this can be achieved by manipulating the Vec length instead of moving values out from `iter`.
141+
unsafe {
142+
let vec = vec.as_mut();
143+
let old_len = vec.len();
144+
vec.set_len(old_len + drop_len + self.tail_len);
145+
vec.truncate(old_len + self.tail_len);
146+
}
147+
148+
return;
149+
}
150+
151+
// ensure elements are moved back into their appropriate places, even when drop_in_place panics
152+
let _guard = DropGuard(self);
153+
154+
if drop_len == 0 {
155+
return;
156+
}
157+
158+
// as_slice() must only be called when iter.len() is > 0 because
159+
// it also gets touched by vec::Splice which may turn it into a dangling pointer
160+
// which would make it and the vec pointer point to different allocations which would
161+
// lead to invalid pointer arithmetic below.
162+
let drop_ptr = iter.as_slice().as_ptr();
163+
164+
unsafe {
165+
// drop_ptr comes from a slice::Iter which only gives us a &[T] but for drop_in_place
166+
// a pointer with mutable provenance is necessary. Therefore we must reconstruct
167+
// it from the original vec but also avoid creating a &mut to the front since that could
168+
// invalidate raw pointers to it which some unsafe code might rely on.
169+
let vec_ptr = vec.as_mut().as_mut_ptr();
170+
#[cfg(not(version("1.87")))]
171+
let drop_offset = drop_ptr.sub_ptr(vec_ptr);
172+
#[cfg(version("1.87"))]
173+
let drop_offset = drop_ptr.offset_from_unsigned(vec_ptr);
174+
let to_drop = ptr::slice_from_raw_parts_mut(vec_ptr.add(drop_offset), drop_len);
175+
ptr::drop_in_place(to_drop);
176+
}
177+
}
178+
}
179+
180+
// #[stable(feature = "fused", since = "1.26.0")]
181+
impl<T, A: Allocator> FusedIterator for Drain<'_, T, A> {}

rust/kernel/lib.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,21 @@
1616
// Please see https://github.com/Rust-for-Linux/linux/issues/2 for details on
1717
// the unstable features in use.
1818
//
19+
// ============ start asahi downstream features ===========
20+
#![feature(associated_type_defaults)]
21+
//
22+
#![feature(cfg_version)]
23+
//
24+
// Stable since Rust 1.87.0.
25+
#![feature(ptr_sub_ptr)]
26+
//
27+
#![feature(sized_type_properties)]
28+
//
29+
#![feature(slice_range)]
30+
//
31+
#![cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, feature(pin_coerce_unsized_trait))]
32+
// ============ end asahi dowanstream features ============
33+
//
1934
// Stable since Rust 1.79.0.
2035
#![feature(inline_const)]
2136
//

scripts/Makefile.build

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,9 @@ $(obj)/%.lst: $(obj)/%.c FORCE
319319
# the unstable features in use.
320320
rust_allowed_features := asm_const,asm_goto,arbitrary_self_types,lint_reasons,offset_of_nested,raw_ref_op,used_with_arg
321321

322+
# additional rust features used by the downstream asahi kernel
323+
rust_allowed_features := $(rust_allowed_features),ptr_sub_ptr
324+
322325
# `--out-dir` is required to avoid temporaries being created by `rustc` in the
323326
# current working directory, which may be not accessible in the out-of-tree
324327
# modules case.

0 commit comments

Comments
 (0)