I have a basic struct ImageData which, primarily, holds an array of u8s (bytes) that represents a PNG image (layed out as rgbrgbrgb... or rgbargbargba...):
struct ImageData {
png_type: png::ColorType,
bytes: Vec<u8>,
width: u32,
height: u32,
is_srgb: bool,
}
I also have a PixelValue struct that will allow me to treat RGB and RGBA similarly - that is, I want to get PixelValues instead of an array of 3 or 4 u8s, because then I would be duplicating a lot of code to deal with those different types.
struct PixelValue {
r: u8,
g: u8,
b: u8,
a: u8,
}
So I want to implement IntoIterator on ImageData that will return an iterator on PixelValues. It should convert the u8 chunks into PixelValues:
impl<'a> IntoIterator for &'a ImageData {
type Item = PixelValue;
type IntoIter = Iter<PixelValue>; // this is definitely wrong
fn into_iter(self) -> Self::IntoIter {
let pixel_size = get_pixel_size(self.png_type); // 3 or 4, depending on RGB or RGBA
// Need to write something that can take an array of 3 or 4 u8s and returns the PixelValue
self.bytes.chunks(pixel_size).map(|ar| PixelValue(ar))
}
}
My questions are:
- Am I going in the right direction? Can I change the output value (
Item) of the iterator withmap? If not, why not? - Is there an obvious "best practice" way to go about this problem (turning an array of pixel rgb or rgba's into structs)?
impl Traitin traits, so you end up either having to quite frustratingly define theIntoIterassociated type rather unwieldily (something likeMap<Chunks<Iter<'a, u8>>, fn(&[u8]) -> PixelValue>and ensure the "closure" doesn't capture any environment so that its type can be "promoted" to afnpointer) or (often more preferably) you define your own struct implementingIteratorand return that.#[repr(C)]then you can cast a slice's data pointer to a struct reference (in unsafe code) and avoid the conversion altogether.[u8; 3](in the case of data without the alpha channel) be casted toPixelValue?