imgref icon indicating copy to clipboard operation
imgref copied to clipboard

Add a way to construct a sub-image without lifetime shortening

Open kpreid opened this issue 8 months ago • 2 comments

Suppose that you want to write a function like

struct Foo {
    pixels: Vec<[u8; 4]>, // not an ImgVec for whatever reason
    ...
}
impl Foo {
    fn get_image(&self, rectangle: Rectangle) -> imgref::ImgRefMut<'_, [u8; 4]> {
        todo!();
    }
}

With the current API of ImgRefMut, there is no way to construct such an ImgRefMut using sub_image_mut() or any other rectangle-oriented operation; you can only use new_stride(). This is because the signature of ImgRefMut::sub_image_mut() is:

pub fn sub_image_mut(&mut self, left: usize, top: usize, width: usize, height: usize) -> ImgRefMut<'_, T> {

which is always a borrow of the initial ImgRefMut, so if you write ImgRefMut::new(&mut self.pixels).sub_image(...), you'll be getting “cannot return value referencing temporary value”. Ideally, there would be something like:

impl<'slice, T> ImgRefMut<'slice, T> {
    pub fn into_sub_image_mut(self, left: usize, top: usize, width: usize, height: usize) -> ImgRefMut<'slice, T> {

which takes ownership of the existing mutable reference and thus does not shorten its lifetime. This is of course not a critical expressiveness issue since new_stride() does exist, but it feels like it would be a good API addition, aligned with imgref's goals, to not require the caller to compute stride manually.

This issue does not apply to the non-mutable version ImgRef::sub_image() since its signature copies the original 'slice lifetime already (and relies on the fact that you can get a &'a T from a &'b &'a T, which you cannot do analogously with mutable references).

kpreid avatar Apr 01 '25 16:04 kpreid

Actually, this is straightforwardly solvable by adding the proposed method; guess I should write a PR for it. When I started writing this issue (and accidentally submitted it too soon) I was thinking this was only fixable as a breaking change (i.e. version 2.0).

kpreid avatar Apr 01 '25 16:04 kpreid

Yeah, an into_ version makes sense.

The regular method has to preserve aliasing guarantees. I'm also thinking about adding split_at_mut or tiling methods.

kornelski avatar Apr 02 '25 01:04 kornelski