2

I want to implement the std::io::Read trait for my custom trait. This is my try:-

use std::io::Read;

trait Bar {
    fn foo(&self);
}

impl<T: Bar> Read for T {
    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        Ok(0)
    }
}

Playground

Error:-

   Compiling playground v0.0.1 (/playground)
error[E0119]: conflicting implementations of trait `std::io::Read` for type `&mut _`:
 --> src/lib.rs:7:1
  |
7 | impl<T: Bar> Read for T {
  | ^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: conflicting implementation in crate `std`:
          - impl<R> std::io::Read for &mut R
            where R: std::io::Read, R: ?Sized;
  = note: downstream crates may implement trait `Bar` for type `&mut _`

error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
 --> src/lib.rs:7:6
  |
7 | impl<T: Bar> Read for T {
  |      ^ type parameter `T` must be used as the type parameter for some local type
  |
  = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local
  = note: only traits defined in the current crate can be implemented for a type parameter

error: aborting due to 2 previous errors
Peter Hall
  • 53,120
  • 14
  • 139
  • 204
  • `impl Read for T` means "implement `Read` _for all_ types `T` for which `T: Bar` holds". Is this what you meant to write? – ForceBru Dec 06 '20 at 13:09
  • Possibly related: https://stackoverflow.com/questions/29256519/i-implemented-a-trait-for-another-trait-but-cannot-call-methods-from-both-traits, https://stackoverflow.com/questions/31082179/is-there-a-way-to-implement-a-trait-on-top-of-another-trait and https://users.rust-lang.org/t/implementing-trait-for-trait/13810 – ForceBru Dec 06 '20 at 13:15

1 Answers1

3

This is currently not allowed, as explained in the note:

= note: downstream crates may implement trait `Bar` for type `&mut _`

You are trying to implement Read for all types that implement Bar, but you can't guarantee that all implementations of Bar (present or future) don't - or won't - implement Read already. For example, a user of your crate might implement Bar for one of their own types.

Another problem is explained in the second error:

= note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local
= note: only traits defined in the current crate can be implemented for a type parameter

You are only allowed to implement a trait if either the trait is defined in your crate (Read is not) or if the type that you are implementing it for is defined in your crate. That means you can't implement Read for T, because T is literally any type, including arbitrary types from other crates.

A workaround for this would be to add a function that exposes a Read implementation from an arbitrary T: Bar:

use std::io::Read;

trait Bar {
    fn foo(&self);
    fn as_reader(&self) -> BarRead<&Self> {
        BarRead(self)
    }
}

pub struct BarRead<T>(T);

impl<T: Bar> Read for BarRead<T> {
    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        Ok(0)
    }
}
Peter Hall
  • 53,120
  • 14
  • 139
  • 204
  • First edition of the answer is not working for test cases. Example:- https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=2a1cfac1f30af10ce90019e28dc221ae . I will look at this approach. Thanks. – Ramesh Kithsiri HettiArachchi Dec 06 '20 at 13:25
  • I think your comment relates to a different answer that was deleted, not this one? – Peter Hall Dec 06 '20 at 13:28
  • @PeterHall Hi Peter, thanks for the answers, may I ask, why we need explict lifetime to implement Read for BarRead? – Sean May 08 '21 at 02:43
  • @Sean the explicit lifetime isn't needed. That hasn't always been the case though, so I probably included it out of habit. – Peter Hall May 08 '21 at 20:40