How to access lines from a referenced BufReader in Rust

88 Views Asked by At

I'm just trying to figure out how ownership works in Rust, I just have an example file helper as :

pub struct FileHelper {
    pub reader:Option<BufReader<File>>
}

impl FileHelper {
    pub fn new() -> Self {
        FileHelper{ reader: None }
    }

    pub fn open_read(&mut self, file:&str) {
        let file_stream:File = File::open(file).expect("FAIL");
        self.reader = Some(BufReader::new(file_stream));
    }

    pub fn get_reader(&self) -> Option<&BufReader<File>> {
        match &self.reader {
            Some(reader) => { return Some(reader); }
            None => { return None; }
        }
    }
}

All it does it separate the creation of a BufReader and the retrieval of the same BufReader. I'm using it as :

let mut file_helper:FileHelper = FileHelper::new();

file_helper.open_read("/tmp/someFile.txt");

match file_helper.get_reader() {
    Some(reader) => {
        for read_line in reader.lines() { println!("{:?}", read_line.unwrap()); }
    },
    None => {}
}

It seems to be able to get the reference to the BufReader but I'm unable to interact with the reader.lines() because it gives the error :

move occurs because `*reader` has type `std::io::BufReader<std::fs::File>`, which does not implement the `Copy` trait

So I'm guessing the reader.lines() is trying to take ownership? I don't really understand how the ownership and referencing is working here but was wondering if there's a way to still use the reader.lines() on a referenced BufReader?

1

There are 1 best solutions below

3
Aleksander Krauze On BEST ANSWER

BufRead is implemented for impl<B: BufRead + ?Sized> BufRead for &mut B. But you are returning a shared reference to underling reader. Method BufRead::lines consumes self. Since you provided &BufReader compiler tries to dereference it and take BufRead which is impossible since it is behind a shared reference and is not Copy.

Solution is very simple. Just return exclusive/mutable reference to the buf reader.

use std::io::{BufReader, BufRead};
use std::fs::File;

pub struct FileHelper {
    pub reader: Option<BufReader<File>>
}

impl FileHelper {
    pub fn new() -> Self {
        FileHelper {reader: None }
    }

    pub fn open_read(&mut self, file: &str) {
        let file_stream: File = File::open(file).expect("FAIL");
        self.reader = Some(BufReader::new(file_stream));
    }

    pub fn get_reader(&mut self) -> Option<&mut BufReader<File>> {
        self.reader.as_mut()
    }
}

fn main() {
   let mut file_helper: FileHelper = FileHelper::new();

    file_helper.open_read("/tmp/someFile.txt");

    if let Some(reader) = file_helper.get_reader() {
        for read_line in reader.lines() {
            println!("{:?}", read_line.unwrap());
        }
    }
}