#How to reduce code duplication?

23 messages · Page 1 of 1 (latest)

dim geyser
#
pub(crate) struct RefMatrix<'a> {
    inner: &'a [u8],
    len: usize,
}

impl<'a> RefMatrix<'a> {
    fn new(from: &'a [u8]) -> Self {
        let len = from
            .iter()
            .position(|ch| *ch == b'\n')
            .expect("Input had no \\n");
        Self { inner: from, len }
    }
    fn get(&self, x: usize, y: usize) -> u8 {
        self.inner[y * (self.len + 1) + x]
    }
}

pub(crate) struct RefMatrixMut<'a> {
    inner: &'a mut [u8],
    len: usize,
}

impl<'a> RefMatrixMut<'a> {
    fn new(from: &'a mut [u8]) -> Self {
        let len = from
            .iter()
            .position(|ch| *ch == b'\n')
            .expect("Input had no \\n");
        Self { inner: from, len }
    }
    fn get(&self, x: usize, y: usize) -> u8 {
        self.inner[y * (self.len + 1) + x]
    }

    pub(crate) fn get_mut(&mut self, x: usize, y: usize) -> &mut u8 {
        &mut self.inner[y * (self.len) + x]
    }

    pub(crate) fn set(&mut self, x: usize, y: usize, value: u8) {
        self.inner[y * (self.len) + x] = value;
    }
}

pub(crate) struct OwnedMatrix {
    inner: Vec<u8>,
    len: usize,
}

impl OwnedMatrix {
    pub(crate) fn new(from: &[u8]) -> Self {
        let len = from
            .into_iter()
            .position(|ch| *ch == b'\n')
            .expect("Input had no \\n");
        let number_of_newlines = from.len() / (len + 1);
        let mut inner = Vec::with_capacity(from.len() - number_of_newlines);

        for i in 0..number_of_newlines + 1 {
            inner.extend_from_slice(&from[i * (len + 1)..(i + 1) * (len + 1) - 1]);
        }
        Self { inner, len }
    }

    pub(crate) fn get(&self, x: usize, y: usize) -> u8 {
        self.inner[y * (self.len) + x]
    }

    pub(crate) fn get_mut(&mut self, x: usize, y: usize) -> &mut u8 {
        &mut self.inner[y * (self.len) + x]
    }

    pub(crate) fn set(&mut self, x: usize, y: usize, value: u8) {
        self.inner[y * (self.len) + x] = value;
    }
}
#

I don't like the whole

    pub(crate) fn get(&self, x: usize, y: usize) -> u8 {
        self.inner[y * (self.len) + x]
    }

    pub(crate) fn get_mut(&mut self, x: usize, y: usize) -> &mut u8 {
        &mut self.inner[y * (self.len) + x]
    }

    pub(crate) fn set(&mut self, x: usize, y: usize, value: u8) {
        self.inner[y * (self.len) + x] = value;
    }
}

thing repeated 3 times.

I also don't like having 3 structs here

#

I'd much rather have 2

lyric shore
#

You could make a generic Matrix<T> where T: Deref<[u8]>

#

(I think it's Deref, but I could be wrong)

dim geyser
#

What do I do with it?

#

I can't put it in the OwnedMatrix for example

#

I'm not sure what you mean

lyric shore
#

Well, perhaps not a generic struct, because the new impls may have to be different, but you could probably make a trait

#

Just have fn as_slice[_mut](&[mut ]self) -> &[mut ][u8]; so you can use default impls for the methods

dim geyser
#

What do I do with the trait? I can't have a blanket implementation because I can't access self. inner and self.len :/

lyric shore
#

You can have a method to return a slice that each struct implements, and the same for self.len

lyric shore
dim geyser
#

Thanks, I always wondered why things had such trivial functions

#

It makes sense now

lyric shore
#

Note that, since RefMatrix doesn't have the same mutability, it won't be able to implement the trait; to work around this, you could instead use a macro like impl_matrix!(RefMatrix<'a>, immut); impl_matrix!(OwnedMatrix, mut);

dim geyser
#

how can I make a trait depend on another trait? Make MatrixMut require Matrix to be implemented

lyric shore
#

trait MatrixMut: Matrix

dim geyser
#

thanks

lyric shore
#

Here's your example implemented with traits. It still has some code duplication, but now it's much more readable and extensible

dim geyser
#

Thank you!