Implementation of struct with optional owned data or borrowed data

I have this struct for handling 2d stuff inside a lineair vector.

#[derive(Default, Clone, PartialEq, Eq)]
pub struct Map2d<T> where T: Sized + Default + Clone + Copy
{
    pub width: i32,
    pub height: i32,
    pub data: Vec<T>,
}

It has a lot of functions to 'draw' a map completely or partially to another map in different ways.
My Bitmap structure is one implementation of this map: Map2d<Rgba>.
Now my wish has arisen to rewrite this struct for owned data (as above) or borrowed data.
To be detailed: I need to avoid copying a fullscreen bitmap buffer. A fullscreen can be a lot of megabytes.
To avoid copying I need a direct reference to borrowed data.

I know I can achieve it with a Trait but it would produce a lot of duplicated implementation code for the owned and borrowed version.
Would it be possible to somehow declare the struct as.

#[derive(Default, Clone, PartialEq, Eq)]
pub struct Map2d<T> where T: Sized + Default + Clone + Copy
{
    pub width: i32,
    pub height: i32,
    pub data: &mut [T], // owned or borrowed.
}

Or another smart implementation / idea?

Do you mean, you only want a single implementation? That depends on if you can encapsulate everything you need in the trait or not.

Anyway, if you can implement everything you need using &mut [T], presumably you just need data to be DerefMutable to [T].

use std::ops::DerefMut;
use std::ops::Deref;

#[derive(Default, Clone, PartialEq, Eq)]
pub struct Map2d<Data> {
    pub width: i32,
    pub height: i32,
    pub data: Data,
}

impl<T, Data> Map2d<Data>
where
    T: Default + Copy,
    Data: Deref<Target = [T]> + DerefMut,
{ /* .. */ }

image::ImageBuffer and imgref::Img are both already-existing “2D image wrapper” types that are generic over the kind of storage, with slightly different approaches.

1 Like

The code in ImageBuffer does something similar I see.

I actually do not want to change my bitmap. it is simple and straightforward.
The only thing I want is avoiding 1 extra copy of my pixels to softbuffer's pixels.
Ideal would be if softbuffer took my pixels as a source, but that is not possible.
Apart from the syntax which I cannot yet read very well, I have to rewrite the whole thing and replace it with something much more abstract and probably have to rewrite every function.
But it is probably the only way.

Heya, in case this fits, I made an own crate which lets you do this: (disclaimer -- untested)

use own::OwnedOrMutRef;

#[derive(Default, Clone, PartialEq, Eq)]
pub struct Map2d<T> where T: Sized + Default + Clone + Copy
{
    pub width: i32,
    pub height: i32,
    // either `Vec<T>`, or `&mut Vec<T>`
    pub data: OwnedOrMutRef<'data, Vec<T>>,
}

let mut map_2d_owner = Map2d {
    width: 2,
    height: 3,
    // or `vec![1, 2, 3, 4, 5, 6].into()`
    data: OwnedOrMutRef::from(vec![1, 2, 3, 4, 5, 6]),
};

// borrow the data
let data_borrowed = &mut map_2d_owner.data.reborrow();

let mut map_2d_borrower = Map2d {
    width: 2,
    height: 3,
    data: data_borrowed,
};

Though I can't tell if it also changes your bitmap like @quinedot's solution (which I like)

This looks like a nice solution. Though I have to change all inner functions for accessing stuff as pointers, slices, pixels etc. On top of that I am unable to read the syntax.
How would a function look for
fn new(w: i32, h: i32) -> Self {}
and
fn new_borrowed_data(w: i32, h: i32, refdata: ??) -> Self {}

Here's a possibility that could be more generic in a variety of ways.

1 Like

Still not convinced...
I have this implementation which is 'perfect' on its own. Containing all logic and access for a simple Vec.
Just to avoid copying data from my Bitmap to softbuffers pixelbuffer, I have to rewrite this Bitmap.
Making it less clear and filled with less clear code.
Philosophically stuck... Or lazy?
Maybe I can 'borrow' some logic from this img or image crate to see how they solve it there.

edit: the problem is insolvable with readable code. I don't like the code of - for example - imagebuffer. or maybe it is because I am not good enough with the language.

I tried a more (for me) readable approach.
Not advanced but workable. Comments welcome (learning learning...), altough the post is resolved already...

#[derive(Default, Clone, PartialEq, Eq)]
pub struct Map<T>
where
    T: Sized + Default + Clone + Copy
{
    pub width: i32,
    pub height: i32,
    pub data: Vec<T>,
}

#[derive(PartialEq, Eq)]
pub struct BorrowedMap<'a, T>
where
    T: Sized + Default + Clone + Copy
{
    pub width: i32,
    pub height: i32,
    pub data: &'a mut[T],
}

pub trait MapTrait<T>
where
    T: Sized + Default + Clone + Copy
{
    fn width(&self) -> i32; // must implement 2x
    fn height(&self) -> i32; // must implement 2x
    fn data(&self) -> &[T]; // must implement 2x
    fn data_mut(&mut self) -> &mut [T]; // must implement 2x

    // and all functions with 2d logic (get, set, copy, blend) can go in here.
}

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.