Feedback on Code That Reads a File Header

Hello, I'm a very inexperienced Rustacean and I'm currently writing a program that reads .shp files. So far, I've put together a module to read the header of the file which is always 100 bytes in length. I'd like to get some feedback before I move on to writing additional modules that read the contents of the files.

use std::fmt;
use std::fs::File;
use std::io::prelude::*;

use byteorder::{ BigEndian, LittleEndian, ReadBytesExt };

pub struct Header {
    file_length: i32,
    version: i32,
    shape_type: i32,
    bbox_xmin: f64,
    bbox_ymin: f64,
    bbox_xmax: f64,
    bbox_ymax: f64,
}

pub fn read_header(filename: &str) -> Result<Header, std::io::Error> {
    const BUFFER_SIZE: usize = 100;

    let mut file = File::open(&filename)?;
    let mut buffer = [0; BUFFER_SIZE];

    file.read(&mut buffer)?;

    let mut file_length = &buffer[24..28];
    let mut version = &buffer[28..32];
    let mut shape_type = &buffer[32..36];
    let mut bbox_xmin = &buffer[36..44];
    let mut bbox_ymin = &buffer[44..52];
    let mut bbox_xmax = &buffer[52..60];
    let mut bbox_ymax = &buffer[60..68];

    Ok(Header {
        file_length: file_length.read_i32::<BigEndian>().unwrap(),
        version: version.read_i32::<LittleEndian>().unwrap(),
        shape_type: shape_type.read_i32::<LittleEndian>().unwrap(),
        bbox_xmin: bbox_xmin.read_f64::<LittleEndian>().unwrap(),
        bbox_ymin: bbox_ymin.read_f64::<LittleEndian>().unwrap(),
        bbox_xmax: bbox_xmax.read_f64::<LittleEndian>().unwrap(),
        bbox_ymax: bbox_ymax.read_f64::<LittleEndian>().unwrap(),
    })
}

Specific questions I have are:

  1. Is it normal to have use statements in each module file or is it possible/idiomatic to have them all in the main.rs file and then export them to the modules as needed?
  2. I've defined file_length, version, etc., which point to borrowed slices of my buffer array. I can then call file_length.read_i32, for example, and it works fine. However, I originally tried to do &buffer[24..28].read_i32 and I get an unsatisfied trait bounds error. What's going on there? Why do I have to assign it to a variable first?
  3. When I call file.read, is it just reading the first 100 bytes of the file into my buffer or is it reading the whole file but just keeping the first 100 bytes?

Thanks in advance! I love this community! :heart_eyes:

Yes.

is the same as &(buffer[24..28].read_i32), not (&buffer[24..28]).read_i32. Please consult the operator precedence table.

This can easily be answered by reading the relevant documentation. It reads at most 100 bytes; you have to check the return value in order to ensure it actually did read that many.

1 Like
  1. Yes, it is normal to have imports in each file.
  2. I believe this should work, though you need to remove the ampersand.
  3. The read call will read between 1 and 100 bytes, and it returns how many bytes it read. Use read_exact to make sure that you are really reading exactly 100 bytes.
2 Likes

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.