Skip to content

Commit 1d1d223

Browse files
Danilo Krummrichojeda
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 correspondingly 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> Reviewed-by: Benno Lossin <benno.lossin@proton.me> Reviewed-by: Gary Guo <gary@garyguo.net> Signed-off-by: Danilo Krummrich <dakr@kernel.org> Link: https://lore.kernel.org/r/20241004154149.93856-18-dakr@kernel.org [ Fixed typos. - Miguel ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
1 parent 2aac4cd commit 1d1d223

File tree

2 files changed

+171
-0
lines changed

2 files changed

+171
-0
lines changed

rust/kernel/alloc.rs

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

23+
pub use self::kvec::IntoIter;
2324
pub use self::kvec::KVVec;
2425
pub use self::kvec::KVec;
2526
pub use self::kvec::VVec;

rust/kernel/alloc/kvec.rs

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -646,3 +646,173 @@ impl_slice_eq! {
646646
[A: Allocator, const N: usize] Vec<T, A>, [U; N],
647647
[A: Allocator, const N: usize] Vec<T, A>, &[U; N],
648648
}
649+
650+
impl<'a, T, A> IntoIterator for &'a Vec<T, A>
651+
where
652+
A: Allocator,
653+
{
654+
type Item = &'a T;
655+
type IntoIter = slice::Iter<'a, T>;
656+
657+
fn into_iter(self) -> Self::IntoIter {
658+
self.iter()
659+
}
660+
}
661+
662+
impl<'a, T, A: Allocator> IntoIterator for &'a mut Vec<T, A>
663+
where
664+
A: Allocator,
665+
{
666+
type Item = &'a mut T;
667+
type IntoIter = slice::IterMut<'a, T>;
668+
669+
fn into_iter(self) -> Self::IntoIter {
670+
self.iter_mut()
671+
}
672+
}
673+
674+
/// An [`Iterator`] implementation for [`Vec`] that moves elements out of a vector.
675+
///
676+
/// This structure is created by the [`Vec::into_iter`] method on [`Vec`] (provided by the
677+
/// [`IntoIterator`] trait).
678+
///
679+
/// # Examples
680+
///
681+
/// ```
682+
/// let v = kernel::kvec![0, 1, 2]?;
683+
/// let iter = v.into_iter();
684+
///
685+
/// # Ok::<(), Error>(())
686+
/// ```
687+
pub struct IntoIter<T, A: Allocator> {
688+
ptr: *mut T,
689+
buf: NonNull<T>,
690+
len: usize,
691+
layout: ArrayLayout<T>,
692+
_p: PhantomData<A>,
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: `self.ptr` is guaranteed to be valid by the type invariant.
760+
unsafe { ptr::drop_in_place(ptr::slice_from_raw_parts_mut(self.ptr, self.len)) };
761+
762+
// SAFETY:
763+
// - `self.buf` was previously allocated with `A`.
764+
// - `self.layout` matches the `ArrayLayout` of the preceding allocation.
765+
unsafe { A::free(self.buf.cast(), self.layout.into()) };
766+
}
767+
}
768+
769+
impl<T, A> IntoIterator for Vec<T, A>
770+
where
771+
A: Allocator,
772+
{
773+
type Item = T;
774+
type IntoIter = IntoIter<T, A>;
775+
776+
/// Consumes the `Vec<T, A>` and creates an `Iterator`, which moves each value out of the
777+
/// vector (from start to end).
778+
///
779+
/// # Examples
780+
///
781+
/// ```
782+
/// let v = kernel::kvec![1, 2]?;
783+
/// let mut v_iter = v.into_iter();
784+
///
785+
/// let first_element: Option<u32> = v_iter.next();
786+
///
787+
/// assert_eq!(first_element, Some(1));
788+
/// assert_eq!(v_iter.next(), Some(2));
789+
/// assert_eq!(v_iter.next(), None);
790+
///
791+
/// # Ok::<(), Error>(())
792+
/// ```
793+
///
794+
/// ```
795+
/// let v = kernel::kvec![];
796+
/// let mut v_iter = v.into_iter();
797+
///
798+
/// let first_element: Option<u32> = v_iter.next();
799+
///
800+
/// assert_eq!(first_element, None);
801+
///
802+
/// # Ok::<(), Error>(())
803+
/// ```
804+
#[inline]
805+
fn into_iter(self) -> Self::IntoIter {
806+
let buf = self.ptr;
807+
let layout = self.layout;
808+
let (ptr, len, _) = self.into_raw_parts();
809+
810+
IntoIter {
811+
ptr,
812+
buf,
813+
len,
814+
layout,
815+
_p: PhantomData::<A>,
816+
}
817+
}
818+
}

0 commit comments

Comments
 (0)