user12513149
user12513149

Reputation:

Implementing optional trait requirement

I am trying to find a way to group different traits so that the generic variable can hold these traits.

For example, I am trying to have T such it's with the traits io::Read + io::Write + io::Seek . Now, that can be easily done in rust using the following code:

pub trait RWS:  io::Read + io::Write + io::Seek{}
impl<T> RWS for T where T: io::Read + io::Write  + io::Seek{}

However, the problem comes when trying to have a function that takes in BufReader, because BufReader doesn't implement io::Write.

Therefore, is there a possibility to implement something that looks like the following for a general type that can be either one?

pub trait RWS:  io::Read || io::Write || io::Seek{}
impl<T> RWS for T where T: io::Read || io::Write  || io::Seek{}

Upvotes: 0

Views: 400

Answers (1)

AlphaModder
AlphaModder

Reputation: 3386

If you just need a field that can store anything implementing one of these three traits at a time, I would suggest using a simple enum:

enum RWS<'a> { // The lifetime parameter can be omitted if you will only be storing fields of `'static` type.
    Read(Box<dyn Read + 'a>),
    Write(Box<dyn Write + 'a>),
    Seek(Box<dyn Seek + 'a>),
}

You could add from_read, from_write, from_seek constructors to this enum for convenience, and match on it in your struct's methods.

However, there are some limitations to this approach. Since it takes ownership of the value and erases its concrete type, you cannot do something like the following:

let bufreader: std::io::BufReader = /* ... */;
self.rws = RWS::Read(Box::new(bufreader));
// later...
if let self.rws = RWS::Read(val) {
    self.rws = RWS::Seek(val); // compile error, even though `BufReader` impls `Seek`
} 

Upvotes: 0

Related Questions