Skip to content

Commit 5c648f9

Browse files
Danilo Krummrichfbq
authored andcommitted
rust: alloc: implement IntoIterator for Vec
Implement `IntoIterator` for `Vec`, `Vec`'s `IntoIter` type, as well as `Iterator` for `IntoIter`. `Vec::into_iter` disassembles the `Vec` into its raw parts; additionally, `IntoIter` keeps track of a separate pointer, which is incremented correspondingsly as the iterator advances, while the length, or the count of elements, is decremented. This also means that `IntoIter` takes the ownership of the backing buffer and is responsible to drop the remaining elements and free the backing buffer, if it's dropped. Reviewed-by: Alice Ryhl <aliceryhl@google.com> Signed-off-by: Danilo Krummrich <dakr@kernel.org> Reviewed-by: Benno Lossin <benno.lossin@proton.me> Reviewed-by: Gary Guo <gary@garyguo.net> Link: https://lore.kernel.org/r/20240911225449.152928-15-dakr@kernel.org
1 parent bb7704f commit 5c648f9

2 files changed

Lines changed: 182 additions & 0 deletions

File tree

rust/kernel/alloc.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub use self::kbox::KBox;
1919
pub use self::kbox::KVBox;
2020
pub use self::kbox::VBox;
2121

22+
pub use self::kvec::IntoIter;
2223
pub use self::kvec::KVVec;
2324
pub use self::kvec::KVec;
2425
pub use self::kvec::VVec;

rust/kernel/alloc/kvec.rs

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use core::{
1414
ops::DerefMut,
1515
ops::Index,
1616
ops::IndexMut,
17+
ptr,
1718
ptr::NonNull,
1819
slice,
1920
slice::SliceIndex,
@@ -636,3 +637,183 @@ impl_slice_eq! { [A: Allocator] Vec<T, A>, [U] }
636637
impl_slice_eq! { [A: Allocator] [T], Vec<U, A> }
637638
impl_slice_eq! { [A: Allocator, const N: usize] Vec<T, A>, [U; N] }
638639
impl_slice_eq! { [A: Allocator, const N: usize] Vec<T, A>, &[U; N] }
640+
641+
impl<'a, T, A> IntoIterator for &'a Vec<T, A>
642+
where
643+
A: Allocator,
644+
{
645+
type Item = &'a T;
646+
type IntoIter = slice::Iter<'a, T>;
647+
648+
fn into_iter(self) -> Self::IntoIter {
649+
self.iter()
650+
}
651+
}
652+
653+
impl<'a, T, A: Allocator> IntoIterator for &'a mut Vec<T, A>
654+
where
655+
A: Allocator,
656+
{
657+
type Item = &'a mut T;
658+
type IntoIter = slice::IterMut<'a, T>;
659+
660+
fn into_iter(self) -> Self::IntoIter {
661+
self.iter_mut()
662+
}
663+
}
664+
665+
/// An [`Iterator`] implementation for [`Vec`] that moves elements out of a vector.
666+
///
667+
/// This structure is created by the [`Vec::into_iter`] method on [`Vec`] (provided by the
668+
/// [`IntoIterator`] trait).
669+
///
670+
/// # Examples
671+
///
672+
/// ```
673+
/// let v = kernel::kvec![0, 1, 2]?;
674+
/// let iter = v.into_iter();
675+
///
676+
/// # Ok::<(), Error>(())
677+
/// ```
678+
pub struct IntoIter<T, A: Allocator> {
679+
ptr: *mut T,
680+
buf: NonNull<T>,
681+
len: usize,
682+
cap: usize,
683+
_p: PhantomData<A>,
684+
}
685+
686+
impl<T, A> IntoIter<T, A>
687+
where
688+
A: Allocator,
689+
{
690+
fn as_raw_mut_slice(&mut self) -> *mut [T] {
691+
ptr::slice_from_raw_parts_mut(self.ptr, self.len)
692+
}
693+
}
694+
695+
impl<T, A> Iterator for IntoIter<T, A>
696+
where
697+
A: Allocator,
698+
{
699+
type Item = T;
700+
701+
/// # Examples
702+
///
703+
/// ```
704+
/// let v = kernel::kvec![1, 2, 3]?;
705+
/// let mut it = v.into_iter();
706+
///
707+
/// assert_eq!(it.next(), Some(1));
708+
/// assert_eq!(it.next(), Some(2));
709+
/// assert_eq!(it.next(), Some(3));
710+
/// assert_eq!(it.next(), None);
711+
///
712+
/// # Ok::<(), Error>(())
713+
/// ```
714+
fn next(&mut self) -> Option<T> {
715+
if self.len == 0 {
716+
return None;
717+
}
718+
719+
let current = self.ptr;
720+
721+
// SAFETY: We can't overflow; decreasing `self.len` by one every time we advance `self.ptr`
722+
// by one guarantees that.
723+
unsafe { self.ptr = self.ptr.add(1) };
724+
725+
self.len -= 1;
726+
727+
// SAFETY: `current` is guaranteed to point at a valid element within the buffer.
728+
Some(unsafe { current.read() })
729+
}
730+
731+
/// # Examples
732+
///
733+
/// ```
734+
/// let v: KVec<u32> = kernel::kvec![1, 2, 3]?;
735+
/// let mut iter = v.into_iter();
736+
/// let size = iter.size_hint().0;
737+
///
738+
/// iter.next();
739+
/// assert_eq!(iter.size_hint().0, size - 1);
740+
///
741+
/// iter.next();
742+
/// assert_eq!(iter.size_hint().0, size - 2);
743+
///
744+
/// iter.next();
745+
/// assert_eq!(iter.size_hint().0, size - 3);
746+
///
747+
/// # Ok::<(), Error>(())
748+
/// ```
749+
fn size_hint(&self) -> (usize, Option<usize>) {
750+
(self.len, Some(self.len))
751+
}
752+
}
753+
754+
impl<T, A> Drop for IntoIter<T, A>
755+
where
756+
A: Allocator,
757+
{
758+
fn drop(&mut self) {
759+
// SAFETY: The pointer in `self.0` is guaranteed to be valid by the type invariant.
760+
unsafe { ptr::drop_in_place(self.as_raw_mut_slice()) };
761+
762+
// If `cap == 0` we never allocated any memory in the first place.
763+
if self.cap != 0 {
764+
// SAFETY: `self.buf` was previously allocated with `A`.
765+
unsafe { A::free(self.buf.cast()) };
766+
}
767+
}
768+
}
769+
770+
impl<T, A> IntoIterator for Vec<T, A>
771+
where
772+
A: Allocator,
773+
{
774+
type Item = T;
775+
type IntoIter = IntoIter<T, A>;
776+
777+
/// Consumes the `Vec<T, A>` and creates an `Iterator`, which moves each value out of the
778+
/// vector (from start to end).
779+
///
780+
/// # Examples
781+
///
782+
/// ```
783+
/// let v = kernel::kvec![1, 2]?;
784+
/// let mut v_iter = v.into_iter();
785+
///
786+
/// let first_element: Option<u32> = v_iter.next();
787+
///
788+
/// assert_eq!(first_element, Some(1));
789+
/// assert_eq!(v_iter.next(), Some(2));
790+
/// assert_eq!(v_iter.next(), None);
791+
///
792+
/// # Ok::<(), Error>(())
793+
/// ```
794+
///
795+
/// ```
796+
/// let v = kernel::kvec![];
797+
/// let mut v_iter = v.into_iter();
798+
///
799+
/// let first_element: Option<u32> = v_iter.next();
800+
///
801+
/// assert_eq!(first_element, None);
802+
///
803+
/// # Ok::<(), Error>(())
804+
/// ```
805+
#[inline]
806+
fn into_iter(self) -> Self::IntoIter {
807+
let (ptr, len, cap) = self.into_raw_parts();
808+
809+
IntoIter {
810+
ptr,
811+
// SAFETY: `ptr` is either a dangling pointer or a pointer to a valid memory
812+
// allocation, allocated with `A`.
813+
buf: unsafe { NonNull::new_unchecked(ptr) },
814+
len,
815+
cap,
816+
_p: PhantomData::<A>,
817+
}
818+
}
819+
}

0 commit comments

Comments
 (0)