Skip to content

Commit 14cebdf

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 <[email protected]> Reviewed-by: Benno Lossin <[email protected]> Reviewed-by: Gary Guo <[email protected]> Signed-off-by: Danilo Krummrich <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 3d8ea2e commit 14cebdf

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

0 commit comments

Comments
 (0)