rustfilestreamownership

How to access lines from a referenced BufReader in Rust


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?


Solution

  • 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());
            }
        }
    }