plumers 1.0.2

Multi-format image library with first-class support for paletted images
Documentation
use std::{
    iter::FusedIterator,
    marker::PhantomData,
    ops::{Index, IndexMut},
};

use crate::prelude::*;

use super::raw::PlumWrapper;

/// A reference to a specific frame of an image.
#[derive(Debug, Clone)]
pub struct Frame<'img, Fmt: ColorFmt, Img: Image<Fmt> + ?Sized>(
    pub(super) &'img Img,
    pub(super) usize,
    pub(super) PhantomData<Fmt>,
);
/// A mutable reference to a specific frame of an image.
#[derive(Debug)]
pub struct FrameMut<'img, Fmt: ColorFmt, Img: Image<Fmt> + ?Sized>(
    pub(super) &'img mut Img,
    pub(super) usize,
    pub(super) PhantomData<Fmt>,
);

impl<'img, Fmt: ColorFmt, Img: Image<Fmt> + ?Sized> Frame<'img, Fmt, Img> {
    /// Creates a reference to `img`'s `frame_idx`th frame.
    ///
    /// [`img.frame(frame_idx)`][Image::frame()] may be more concise, if it's available.
    pub fn new(img: &'img Img, frame_idx: usize) -> Self {
        Self(img, frame_idx, PhantomData)
    }

    /// Retrieves a reference to the image that this frame is part of.
    pub fn image(&self) -> &'img Img {
        self.0
    }

    /// Retrieves a copy of the pixel at the given coordinates.
    pub fn pixel(&self, x: usize, y: usize) -> Fmt {
        self.image().pixel(self.1, x, y)
    }
}

impl<'img, Fmt: ColorFmt, Img: Image<Fmt> + ?Sized> FrameMut<'img, Fmt, Img> {
    /// Creates a reference to `img`'s `frame_idx`th frame.
    ///
    /// [`img.frame_mut(frame_idx)`][Image::frame_mut()] may be more concise, if it's available.
    pub fn new(img: &'img mut Img, frame_idx: usize) -> Self {
        Self(img, frame_idx, PhantomData)
    }

    /// Retrieves a reference to the image that this frame is part of.
    pub fn image(&self) -> &Img {
        self.0
    }

    /// Retrieves a mutable reference to the image that this frame is part of.
    pub fn image_mut(&'img mut self) -> &'img mut Img {
        self.0
    }

    /// Retrieves a copy of the pixel at the given coordinates.
    pub fn pixel(&self, x: usize, y: usize) -> Fmt {
        self.image().pixel(self.1, x, y)
    }
}

impl<Fmt: ColorFmt> Index<(usize, usize)> for Frame<'_, Fmt, DirectImage<Fmt>> {
    type Output = Fmt;

    fn index(&self, (x, y): (usize, usize)) -> &Self::Output {
        PlumWrapper::pixel_ref(self.0, self.1, x, y)
    }
}

impl<Fmt: ColorFmt> Index<(usize, usize)> for FrameMut<'_, Fmt, DirectImage<Fmt>> {
    type Output = Fmt;

    fn index(&self, (x, y): (usize, usize)) -> &Self::Output {
        PlumWrapper::pixel_ref(self.0, self.1, x, y)
    }
}
impl<Fmt: ColorFmt> IndexMut<(usize, usize)> for FrameMut<'_, Fmt, DirectImage<Fmt>> {
    fn index_mut(&mut self, (x, y): (usize, usize)) -> &mut Self::Output {
        let frame_idx = self.1;
        PlumWrapper::pixel_mut(self.0, frame_idx, x, y)
    }
}

impl<Fmt: ColorFmt> Index<(usize, usize)> for Frame<'_, Fmt, PalettedImage<Fmt>> {
    type Output = u8;

    fn index(&self, (x, y): (usize, usize)) -> &Self::Output {
        self.0.index_at(self.1, x, y)
    }
}

impl<Fmt: ColorFmt> Index<(usize, usize)> for FrameMut<'_, Fmt, PalettedImage<Fmt>> {
    type Output = u8;

    fn index(&self, (x, y): (usize, usize)) -> &Self::Output {
        self.0.index_at(self.1, x, y)
    }
}
impl<Fmt: ColorFmt> IndexMut<(usize, usize)> for FrameMut<'_, Fmt, PalettedImage<Fmt>> {
    fn index_mut(&mut self, (x, y): (usize, usize)) -> &mut Self::Output {
        self.0.index_at_mut(self.1, x, y)
    }
}

/// Iterator through an image's frames.
///
/// Created by [`Image::frames()`].
#[derive(Debug, Clone)]
pub struct Frames<'img, Fmt: ColorFmt, Img: Image<Fmt> + ?Sized> {
    pub(super) img: &'img Img,
    pub(super) begin: usize,
    pub(super) end: usize,
    pub(super) _pix_fmt: PhantomData<Fmt>,
}

impl<'img, Fmt: ColorFmt, Img: Image<Fmt>> Iterator for Frames<'img, Fmt, Img> {
    type Item = Frame<'img, Fmt, Img>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.begin == self.end {
            return None;
        }

        let frame = self.img.frame(self.begin);
        self.begin += 1;
        Some(frame)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let nb_frames = self.end - self.begin;
        (nb_frames, Some(nb_frames))
    }
}
impl<Fmt: ColorFmt, Img: Image<Fmt>> DoubleEndedIterator for Frames<'_, Fmt, Img> {
    fn next_back(&mut self) -> Option<Self::Item> {
        if self.begin == self.end {
            return None;
        }

        self.end -= 1;
        Some(self.img.frame(self.end))
    }
}
impl<Fmt: ColorFmt, Img: Image<Fmt>> FusedIterator for Frames<'_, Fmt, Img> {}
impl<Fmt: ColorFmt, Img: Image<Fmt>> ExactSizeIterator for Frames<'_, Fmt, Img> {}

// No `Iterator` implementation for `FramesMut`, because the frames returned by the iterator cannot exist concurrently.
// (We'd need a `LendingIterator` for that.)