3

I was writing a network app in Rust and wanted to define a set of functions that, given raw bytes sequence, would convert it into some struct. It seemed that TryFrom trait was a perfect fit; however, I am getting a very uninformative error message when I try to compile even the very basic example code:

#![feature(try_from)]

use std::convert::TryFrom;
use std::io::Read;

#[derive(Debug)]
enum Fruit {
    Apple = 1,
    Orange = 2,
}

impl<T: Read> TryFrom<T> for Fruit {
    type Error = ();

    fn try_from(reader: T) -> Result<Fruit, ()> {
        match reader.bytes().next() {
            Some(x) if x == Fruit::Apple as u8 => Ok(Fruit::Apple),
            Some(x) if x == Fruit::Orange as u8 => Ok(Fruit::Orange),
            _ => Err(())
        }
    }
}

fn main() {
    let bytes = b"\x01";
    let fruit = Fruit::try_from(bytes).unwrap();
    println!("The fruit is: {:?}", fruit);
}

The error is:

Error[E0119]: conflicting implementations of trait `std::convert::TryFrom<_>` for type `Fruit`:
  --> src/main.rs:11:1                                                           
   |                                                                             
11 | impl<T: Read> TryFrom<T> for Fruit {                                        
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^                                          
   |                                                                             
   = note: conflicting implementation in crate `core`:                           
           - impl<T, U> std::convert::TryFrom<U> for T                           
             where T: std::convert::From<U>;

Which is very confusing to me. Could someone explain what's wrong here?

Peter Hall
  • 53,120
  • 14
  • 139
  • 204
kreo
  • 2,613
  • 2
  • 19
  • 31
  • The duplicate explains the same core problem for the `From` trait. TL;DR: What if `Fruit` implemented `Read`? Then it would be ambiguous which implementation to use. – Shepmaster Mar 23 '19 at 21:22
  • 2
    [You can introduce a newtype to avoid the ambiguity](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=a3350d912a4dedd58441c1627221bc83). – Shepmaster Mar 23 '19 at 21:26
  • Do I understand it right that, if I don't implement Read for Fruit in my own module, then no third party module will be able to implement it? Hence theoretically we are safe here as long as I don't implement Read myself? – kreo Mar 24 '19 at 06:33
  • @kreo it's described in this [chapter](https://doc.rust-lang.org/book/ch10-02-traits.html): _One restriction to note with trait implementations is that we can implement a trait on a type only if either the trait or the type is local to our crate. ... This restriction is part of a property of programs called coherence, and more specifically the orphan rule, so named because the parent type is not present. This rule ensures that other people’s code can’t break your code and vice versa._ – zrzka Mar 24 '19 at 18:49

0 Answers0