Analyzing functional solution to streaming_iterator (?)
By: George Shuklin
Tags: Functional Programming, Iterators, Learning To Code, Rust

The last post and corresponding question brought me the answer from Yandros. I’m trying to understand it.

The code:

#![deny(elided_lifetimes_in_paths)]



struct Pixel<'img> {

value: &'img mut u32,

i: usize,

}



struct Canvas {

imgs: Vec<u32>,

max_i: usize,

}



impl Canvas {

pub

fn iter_mut<'iter> (

self: &'iter mut Self,

) -> impl Iterator<Item = Pixel<'iter>>

{

self.imgs[.. self.max_i]

.iter_mut()

.enumerate()

.map(|(i, value)| Pixel { value, i })

}

}

Let’s start from #![deny(elided_lifetimes_in_paths)] .

deny in new to me, but I somewhat understand: the same as #![feature()] or #![derive()] .

or . elided_lifetimes_in_paths — I can’t find a documentation for it. I asked for explanation. I’ll try to compile this code with no pragma, and see what would change. ..Nothing. I’ll just skip it for now.

Next: structures are exactly like mine.

Next: We implement associated functions for structure ( impl for structure). The function we create — is iter_mut , which is part of the IterMut trait, but we do not implement this trait… Funny, we implement just an associated function which do the same thing. Can I do this with other traits? I believe, it’s important, so I take small sidestep to investigate. Nope, I can’t:

struct X{

x:u32

} impl X{

fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

write!(f, "x: {}", self.x)

}

}

cause the error: the trait `std::fmt::Display` is not implemented for `X`

So, returning to the code, iter_mut is just an associated function, and we call it ‘as usual’, but return value of iter_mut is an iterator. To be honest I though about doing this by chaining iterator from img (Vec), but decided to do it ‘manually’ before getting into chaining. As it appears, ‘manually’ is impossibly hard right now in Rust. Before analyzing the pipe, I want to stare to the function signature:

fn iter_mut<'iter> (

self: &'iter mut Self,

) -> impl Iterator<Item = Pixel<'iter>>

iter_mut takes self as mutable reference with lifetime ‘iter’ and return something that implements Iterator trait with parameter for internal object inside Option to be of the type ‘Pixel’ with the same lifetime as the ‘self’. Hard to read, hard to grasp. In other words, it takes mutable reference to itself and promise to return a type, which has a trait ‘Iterator’, with return value of Option(Pixel), or, precisely, with any return type (the selection of return type is does not matter, as long as it follows the rules defined by associated type of the trait. I still can’t dissolve it to something digestible. I can point to Iterator trait declaration and points that ‘this things goes here’, but I can’t keep all those abstractions in a stack without dropping this stack.

Next, is a body of the function:

self.imgs[.. self.max_i]

.iter_mut()

.enumerate()

.map(|(i, value)| Pixel { value, i })

.. self.max_i is right-exclusive range interval, which used together with Index trait. Index<Range<Vec<u32>>>> in my case. Is it so? Let me to try:

19 | let u:u32 = self.imgs[.. self.max_i];

| ^^^^^^^^^^^^^^^^^^^^^^^^ expected u32, found slice

|

= note: expected type `u32`

found type `[u32]`

Nope. It’s a slice. Lesson learned.

That slice is iterated as mutable. Some there is crazy ‘telescopic typing’ stacking (as far as I understand from video lectures), but it’s too hard for me to think about this now. For humble iterator user it looks like a normal piping. Got an iterator, enumerate it, apply a lambda via a map.

The key thing here is that we do not ‘collect’ it, but return ‘as is’ (as iterator).

Just to help myself to get used to it, let’s make it verbose:

let range = .. self.max_i;

let mut slice = self.imgs[range];

let mut_iterator = slice.iter_mut();

let enumerated_iterator = mut_iterator.enumerate();

let pixelizator = |(i, value)| Pixel{value, i};

let pixel_iterator = enumerated_iterator.map(pixelizator);

pixel_iterator

Nope, it’s not the same:

20 | let mut slice = self.imgs[range];

| ^^^^^^^^^ ---------------- help: consider borrowing here: `&self.imgs[range]`

| |

| doesn't have a size known at compile-time

And if we follow advise (with mut ), it works. Full version with verbosity:

fn iter_mut<'iter> (self: &'iter mut Self)

-> impl Iterator<Item = Pixel<'iter>>

{

let range = .. self.max_i;

let mut slice = & mut self.imgs[range];

let mut_iterator = slice.iter_mut();

let enumerated_iterator = mut_iterator.enumerate();

let pixelizator = |(i, value)| Pixel{value, i};

let pixel_iterator = enumerated_iterator.map(pixelizator);

pixel_iterator

}

There is an additional warning about unused ‘i’ in Pixel structure. I’ve tried get rid of it, but got another warning, which is strange to me:

let range = .. self.max_i;

let mut slice = & mut self.imgs[range];

let mut_iterator = slice.iter_mut();

let pixelizator = |value| Pixel{value};

let pixel_iterator = mut_iterator.map(pixelizator);

pixel_iterator

...

warning: variable does not need to be mutable

--> src/main.rs:19:13

|

19 | let mut slice = & mut self.imgs[range];

| ----^^^^^

| |

| help: remove this `mut`

But I do mutate returned value by reference! What’s going on?

I removed ‘ mut ’ here, and my code worked. Now I’m confused. Hah. It’s easy. slice is a reference. The reference itself does not need to to mutate, only data where slice is pointing to, so we write a constant reference to volatile data.

… I hope so, or I’ll become a crazy.