How to generalise reading an array from binary file into function

These lines of code are repeated many times throughout my code, but each time the array being read is of a different numeric type and different size:

let mut section_offsets = [0u32; 15];
for x in section_offsets.iter_mut() {
    *x = rdr.read_u32::<BE>()?;
}

What I want is a function read_array which takes in the size and numeric type of the array to be read (as well as rdr: &mut impl Read), reads the array and returns an io::Result of the array. Is there any way of doing this without having to write loads of functions for each array type?
I got as far as using const generics to define the size of the array but couldn't figure out how to do it using generic types.

An easy solution would be to just treat everything as convertible to a byte slice and read into that with bytemuck:

fn read_int<T, R, const N: usize>(mut reader: R) -> io::Result<[T; N]>
where
    T: Default + Pod + PrimInt,
    R: Read,
{
    let mut result = [T::default(); N];
    reader.read_exact(cast_slice_mut(&mut result))?;

    for x in &mut result {
        *x = x.to_be();
    }
    
    Ok(result)
}

Playground

Edit: here's a zero-dependency version using a macro to generate some trait impls, and a generic function using that trait:

fn read_int<T, R, const N: usize>(mut reader: R) -> io::Result<[T; N]>
where
    T: Copy + Default + ReadSelf,
    R: Read,
{
    let mut result = [T::default(); N];
    
    for x in &mut result {
        *x = T::read_be(&mut reader)?;
    }

    Ok(result)
}

if it helps anyone, here's what I ended up doing:

trait ReadArrays: Read {
    fn read_vec3(&mut self) -> io::Result<Vec3> {
        let mut result = [0f32; 3];
        for x in result.iter_mut() {
            *x = self.read_f32::<BE>()?;
        }
        Ok(result.into())
    }
    fn read_array<T, const N: usize>(&mut self) -> io::Result<[T; N]>
    where
        T: Default + Pod + PrimInt,
    {
        let mut result = [T::default(); N];
        self.read_exact(cast_slice_mut(&mut result))?;
        result.iter_mut().for_each(|x| *x = x.to_be());
        Ok(result)
    }
}
impl<R: Read> ReadArrays for R {}

I used an extension trait to add the functions read_vec3 and read_array to the Read trait.

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.