How to copy Read trait?

Hi there :slight_smile:

Basically a continuation on a set of my previous posts (PS is there a way to link all the posts created by OP that are more or less linked together ? ) now i encountered a problem where i want to scale up my "reading" across multiple input files. Initially i had something like this:

use std::io::Read;
use std::path::Path;


pub struct ObjA<R: Read> {
     reader: R,
}

impl<'a, R: 'a + Read> ObjA<R> {
    pub fn new(reader: R) -> ObjA<R> {
        ObjA { reader: reader }
    }
}
pub struct ObjB {
    parser: ObjA<Box<dyn Read>>
}

impl ObjB {
    pub fn new<T: AsRef<Path>>(filename: Option<T>) -> Self {
        let reader: Box<dyn Read>  = Box::new(std::fs::File::open(filename.unwrap()).unwrap());
        ObjB { parser: ObjA::new(Box::new(reader)) }
    }
}

fn main() {
    let mut obj: ObjB = ObjB::new(Some("./test_1"));
    let rd = obj.parser;
    /* Etc...
     let iter = rd.iter();
     ... 
   */ 
}

one can compile this and will see that the parser object is copied correctly to rd. But now i want to have multiple readers and call them as i need to. My solution was to put them in a hashmap:

use std::io::Read;
use std::path::Path;
use fxhash::FxHashMap;

pub struct ObjA<R: Read> {
     reader: R,
}

impl<'a, R: 'a + Read> ObjA<R> {
    pub fn new(reader: R) -> ObjA<R> {
        ObjA { reader: reader }
    }
}
pub struct ObjB {
    parser: FxHashMap<String,ObjA<Box<dyn Read>>>
}

impl ObjB {
    pub fn new() -> Self {
        ObjB { parser: FxHashMap::default() }
    }
    pub fn push<T: AsRef<Path>>(&mut self, key: String, filename: Option<T>)-> &mut Self{
        let reader: Box<dyn Read>  = Box::new(std::fs::File::open(filename.unwrap()).unwrap());

        self.parser.insert(key,ObjA::new(Box::new(reader)));
        self
    }
}

fn main() {
    let mut obj: ObjB = ObjB::new();

    obj
        .push("x".to_string(), Some("./test_1"))
        .push("y".to_string(), Some("./test_2"));
    let rd = obj.parser["x"];

}

but now i get that i need to have a Copy trait for Read :

error[E0507]: cannot move out of index of `HashMap<String, ObjA<Box<dyn std::io::Read>>, BuildHasherDefault<FxHasher>>`
  --> src/main.rs:37:15
   |
37 |     let rd = obj.parser["x"];
   |               ^^^^^^^^^^^^^^^
   |               |
   |               move occurs because value has type `ObjA<Box<dyn std::io::Read>>`, which does not implement the `Copy` trait
   |               help: consider borrowing here: `&obj.parser["x"]`


How to resolve this problem. Borrowing is not an option here as it messes with my chi and the downstream code in the process. Any suggestions ? (sorry for trivial questions but Rust, though fun to work with has some concepts i am having difficulty understanding )

Than you :slight_smile:

You shouldn't try to get Copy (or Clone) for the hash map. It's a distraction from the real issue. If you want to use the value while its in the hash map, you have to borrow it (probably with a mutable reference). The alternative is to remove it from the hash map so you can get ownership of it while you use it.

2 Likes

Thnx for the advice :slight_smile: Will try to redesign it . It is just that I has hoping to have random access to different readers as i needed to access them.

In other words, you are trying to write a race condition (mutating the same collection using many simultaneous handles). Rust just prevented you from writing that kind of bug.

Your best bet would probably be to only get temporary references to each reader, by looking them up in the map as needed, and holding the (mutable) reference for the minimum amount of time necessary.

2 Likes

I did not think of it this way but i see it now when u pointed it :slight_smile: Thnx :slight_smile:

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.