What I'm trying to do is to basically write a tool that can take any thing that implements Read
and based on its name wrap it in decompressor that also implements Read
. This is simplified code:
trait Read {}
struct ExternalDecompressor1;
impl ExternalDecompressor1 { fn new<T: Read>(_r : T) -> ExternalDecompressor1 { ExternalDecompressor1 } }
impl Read for ExternalDecompressor1 {}
struct ExternalDecompressor2;
impl ExternalDecompressor2 { fn new<T: Read>(_r : T) -> ExternalDecompressor2 { ExternalDecompressor2 } }
impl Read for ExternalDecompressor2 {}
trait MyTrait {
fn can_wrap(&self, x: &str) -> bool;
fn wrap(&self, r: &Read) -> Box<Read>;
}
struct MyTraitImpl1;
impl MyTrait for MyTraitImpl1 {
fn can_wrap(&self, x: &str) -> bool { x.ends_with(".gz") }
fn wrap(&self, r: &Read) -> Box<Read> { unimplemented!() /* Box::new(ExternalDecompressor1::new(r)) */ }
}
struct MyTraitImpl2;
impl MyTrait for MyTraitImpl2 {
fn can_wrap(&self, x: &str) -> bool { x.ends_with(".xz") }
fn wrap(&self, r: &Read) -> Box<Read> { unimplemented!() /* Box::new(ExternalDecompressor2::new(r)) */ }
}
struct MyDynamicTraitUser {
traits: Vec<Box<MyTrait>>,
}
impl MyDynamicTraitUser {
fn new() -> MyDynamicTraitUser {
MyDynamicTraitUser{ traits: vec![Box::new(MyTraitImpl1), Box::new(MyTraitImpl2)] }
}
fn usage(&self, s: &str, r: &Read) -> Box<Read> {
self.traits.iter().find(|&u| u.can_wrap(s)).map(|ref u| u.wrap(r)).unwrap()
}
}
fn main() {
}
I don't have control over Extrnal Decompressors. I wan't to have collection of possible handlers for different compression formats so I store them as boxed MyTrait
s. Finally r
in MyTrait::wrap
can't be passed by value since it's a trait and its size is not known. Which leads to my problem - on the one hand MyTrait
s get reference to Read but on the other ExtrnalDecompressor
s expect concrete implementation of Read
passed by value.
I can maybe imagine that I can write additional struct that takes &Read
and implements Read
but would that be even possible? And if so would it be idiomatic?