Skip to content

Commit f41d5f4

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 00dcdcf commit f41d5f4

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
@@ -647,3 +647,173 @@ impl_slice_eq! {
647647
[A: Allocator, const N: usize] Vec<T, A>, [U; N],
648648
[A: Allocator, const N: usize] Vec<T, A>, &[U; N],
649649
}
650+
651+
impl<'a, T, A> IntoIterator for &'a Vec<T, A>
652+
where
653+
A: Allocator,
654+
{
655+
type Item = &'a T;
656+
type IntoIter = slice::Iter<'a, T>;
657+
658+
fn into_iter(self) -> Self::IntoIter {
659+
self.iter()
660+
}
661+
}
662+
663+
impl<'a, T, A: Allocator> IntoIterator for &'a mut Vec<T, A>
664+
where
665+
A: Allocator,
666+
{
667+
type Item = &'a mut T;
668+
type IntoIter = slice::IterMut<'a, T>;
669+
670+
fn into_iter(self) -> Self::IntoIter {
671+
self.iter_mut()
672+
}
673+
}
674+
675+
/// An [`Iterator`] implementation for [`Vec`] that moves elements out of a vector.
676+
///
677+
/// This structure is created by the [`Vec::into_iter`] method on [`Vec`] (provided by the
678+
/// [`IntoIterator`] trait).
679+
///
680+
/// # Examples
681+
///
682+
/// ```
683+
/// let v = kernel::kvec![0, 1, 2]?;
684+
/// let iter = v.into_iter();
685+
///
686+
/// # Ok::<(), Error>(())
687+
/// ```
688+
pub struct IntoIter<T, A: Allocator> {
689+
ptr: *mut T,
690+
buf: NonNull<T>,
691+
len: usize,
692+
layout: ArrayLayout<T>,
693+
_p: PhantomData<A>,
694+
}
695+
696+
impl<T, A> Iterator for IntoIter<T, A>
697+
where
698+
A: Allocator,
699+
{
700+
type Item = T;
701+
702+
/// # Examples
703+
///
704+
/// ```
705+
/// let v = kernel::kvec![1, 2, 3]?;
706+
/// let mut it = v.into_iter();
707+
///
708+
/// assert_eq!(it.next(), Some(1));
709+
/// assert_eq!(it.next(), Some(2));
710+
/// assert_eq!(it.next(), Some(3));
711+
/// assert_eq!(it.next(), None);
712+
///
713+
/// # Ok::<(), Error>(())
714+
/// ```
715+
fn next(&mut self) -> Option<T> {
716+
if self.len == 0 {
717+
return None;
718+
}
719+
720+
let current = self.ptr;
721+
722+
// SAFETY: We can't overflow; decreasing `self.len` by one every time we advance `self.ptr`
723+
// by one guarantees that.
724+
unsafe { self.ptr = self.ptr.add(1) };
725+
726+
self.len -= 1;
727+
728+
// SAFETY: `current` is guaranteed to point at a valid element within the buffer.
729+
Some(unsafe { current.read() })
730+
}
731+
732+
/// # Examples
733+
///
734+
/// ```
735+
/// let v: KVec<u32> = kernel::kvec![1, 2, 3]?;
736+
/// let mut iter = v.into_iter();
737+
/// let size = iter.size_hint().0;
738+
///
739+
/// iter.next();
740+
/// assert_eq!(iter.size_hint().0, size - 1);
741+
///
742+
/// iter.next();
743+
/// assert_eq!(iter.size_hint().0, size - 2);
744+
///
745+
/// iter.next();
746+
/// assert_eq!(iter.size_hint().0, size - 3);
747+
///
748+
/// # Ok::<(), Error>(())
749+
/// ```
750+
fn size_hint(&self) -> (usize, Option<usize>) {
751+
(self.len, Some(self.len))
752+
}
753+
}
754+
755+
impl<T, A> Drop for IntoIter<T, A>
756+
where
757+
A: Allocator,
758+
{
759+
fn drop(&mut self) {
760+
// SAFETY: `self.ptr` is guaranteed to be valid by the type invariant.
761+
unsafe { ptr::drop_in_place(ptr::slice_from_raw_parts_mut(self.ptr, self.len)) };
762+
763+
// SAFETY:
764+
// - `self.buf` was previously allocated with `A`.
765+
// - `self.layout` matches the `ArrayLayout` of the preceding allocation.
766+
unsafe { A::free(self.buf.cast(), self.layout.into()) };
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 buf = self.ptr;
808+
let layout = self.layout;
809+
let (ptr, len, _) = self.into_raw_parts();
810+
811+
IntoIter {
812+
ptr,
813+
buf,
814+
len,
815+
layout,
816+
_p: PhantomData::<A>,
817+
}
818+
}
819+
}

0 commit comments

Comments
 (0)