Function which returns a BufReader<R>, R not known at compilation

Hi all,

I want to create a function which returns a BufReader<R>, but R is not known at compile time. More precisely, R could be a File, a GzDecoder<File> or any other compression decoder.

I guess returning an impl Trait won't work. So what should I use ? Trait objects ?

Thanks for your help.

There are two options. The simplest is Box<dyn Read>, but another option would be an enum:

enum MyIOType {
    File(File),
    Gzip(GzDecoder<File>),
}

impl Read for MyIOType {
    ...
}

@alice Thanks for your suggestions. I can see with enum but for the trait object, its not clear to me. Is it just a matter of Box<dyn Read> as the return type from the function ?

Yes, just use Box<dyn Read> instead of R.

Thanks @alice

I can return a Box<syn Read> but I can't figure out how to use it with regular BufReader methods:

#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub enum CompressionScheme {
    Gzip,
    Bzip2,
    Xz,
    NotCompressed,
}

impl CompressionScheme {
    /// True if this matches any of the valid compression scheme
    #[inline(always)]
    pub fn is_compressed(&self) -> bool {
        self != &CompressionScheme::NotCompressed
    }

    fn reader(&self, path: &PathBuf) -> Box<dyn Read> {
        // open target file
        let file = File::open(&path).expect("unable to open file");

        // if file is compressed, we need to call a specific reader
        if self.is_compressed() {
            let decoder = GzDecoder::new(file);
            let reader = BufReader::new(decoder);
            Box::new(reader)
        } else {
            let reader = BufReader::new(file);
            Box::new(reader)
        }
    }
}

Any hint ?

Sorry, I discovered it's really easy to use it a a reader, just replacing Box<dyn Read> by Box<dyn BufRead>.

Anyway, thanks a lot for your help.

Ah, yeah, you would want either BufReader<Box<dyn Read>> or Box<dyn BufRead>.

Hi,

Now I can use my new reader with any of the methods implemented by BufRead. But if I want to implement another trait for this reader, I can do:

trait Foo {
    fn set_offset(&self) -> String;
}

impl Foo for dyn BufRead {
    fn set_offset(&self) -> String {
        "from set_offset()".to_string()
    }
}

but how to specialize this function depending on the underlying type ?

Thanks for your help.

you can use

trait Foo: BufRead {
    fn set_offset(&self) -> String;
}

and then use Box<dyn Foo> instead of Box<dyn BufRead>

@juggle-tux Thanks for your suggestion.

In the meantime, I moved to an enum which keeps track of the BufReader. But I'll try what you suggest.

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.