Search code examples
rusttraits

Can not implement io::Read for a custom trait


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

Solution

  • 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)
        }
    }