Iterator and ParallelIterator on a struct

I have a

struct MeshGroup(Vec<IndexedMesh>)

Narturally, it grows into more than just a new type to include extra information.

struct MeshGroup {
    meshes: Vec<IndexedMesh>,
    _aabb: Aabb,
}

When it comes to iteration/looping on the MeshGroup, it is always about the meshes, i.e.

for mesh in meshgroup {
   // looping always work on the meshes
   let mesh: IndexedMesh = mesh;
}
// indexing is about meshes too
let mesh: &IndexedMesh = &meshgruop[0];

To accomplish this, I have implemented IntoIterator on the MeshGroup (ignoring the Index trait for simplicity)

impl IntoIterator for MeshGroup {
    type Item = IndexedMesh;
    type IntoIter = std::vec::IntoIter<Self::Item>;

    fn into_iter(self) -> Self::IntoIter {
        self.meshes.into_iter()
    }
}

impl MeshGroup {
    // copied frmo Vec
    fn iter(&self) -> std::slice::Iter<IndexedMesh> {
        self.meshes.iter()
    }
    
    // copied frmo Vec
    fn iter_mut(&mut self) -> std::slice::IterMut<IndexedMesh> {
        self.meshes.iter_mut()
    }
}

Question 1

How can I for loop directly on &MeshGroup?

fn for_loop_ref(meshgroup: &mut MeshGroup) {
    // for _ in meshgroup { }
}

Question 2

How to implmennt rayon::preldue::IntoParallelIterator?

impl IntoParallelIterator for MeshGroup {
    type Item = IndexedMesh;
    type Iter = rayon::vec::IntoIter<IndexedMesh>;

    fn into_par_iter(self) -> Self::Iter {
        // cannot make `rayon::vec::IntoIter` as `vec` is a private field
        rayon::vec::IntoIter { vec: self.meshes }
    }
}

Question 3

How to do par_iter on the meshgroup?

fn par_loop_ref(meshgroup: &MeshGroup) {
    meshgroup.par_iter().for_each(|_| {});
}

Here is the playground for the problems

You can write

impl<'a> IntoIterator for &'a MeshGroup {
    type Item = &'a IndexedMesh;
    type IntoIter = std::slice::Iter<Self::Item>;
    fn into_iter(self) -> Self::IntoIter {
        self.meshes.iter()
        // or (&self.meshes).into_iter()
    }
}
impl<'a> IntoIterator for &'a mut MeshGroup {
    type Item = &'a mut IndexedMesh;
    type IntoIter = std::slice::IterMut<Self::Item>;
    fn into_iter(self) -> Self::IntoIter {
        self.meshes.iter_mut()
        // or (&mut self.meshes).into_iter()
    }
}

Use self.meshes.into_par_iter() to construct rayon's iterator.

The general principle in both these cases is that when you are implementing IntoIterator and IntoParallelIterator, you can delegate to existing IntoIterator and IntoParallelIterator implementations on other types, or other functions that return iterators.

1 Like

Implement IntoIterator for &MeshGroup (and IntoIterator for &mut MeshGroup if desired). And for convention's sake, add inherent iter and iter_mut methods that forward to those implementations, if you like.

impl<'a> IntoIterator for &'a MeshGroup {
    type Item = &'a IndexedMesh;
    type IntoIter = std::slice::Iter<'a, IndexedMesh>;
    fn into_iter(self) -> Self::IntoIter {
        self.meshes.iter()
    }
}
    fn into_par_iter(self) -> Self::Iter {
        self.meshes.into_par_iter()
    }

The docs tell you how: implement IntoParallelIterator for &_.

impl<'a> IntoParallelIterator for &'a MeshGroup {
    type Item = &'a IndexedMesh;
    type Iter = rayon::slice::Iter<'a, IndexedMesh>;
    fn into_par_iter(self) -> Self::Iter {
        self.meshes.par_iter()
    }
}
1 Like

Do you mean adding iter and iter_mut like so?

impl MeshGroup {
    fn iter(&self) -> std::slice::Iter<IndexedMesh> {
        self.meshes.iter()
    }

    fn iter_mut(&mut self) -> std::slice::IterMut<IndexedMesh> {
        self.meshes.iter_mut()
    }
}

Oh yeah, I see now you already had those methods.

Once you have the impl<'a> IntoIterator for &'a MeshGroup, you can

    fn iter(&self) -> std::slice::Iter<IndexedMesh> {
        self.into_iter()
    }

(if you prefer).


The main point I was attempting is that it's common to have three implementations:

impl IntoIterator for Collection
impl<'a> IntoIterator for &'a Collection
impl<'a> IntoIterator for &'a mut Collection

after which into_iter is a (trait) method on Collection, but iter and iter_mut are not (they're not part of a trait). But there's a convention to add them as inherent methods.

1 Like