Search code examples
rusttraitsrust-tokio

how to specify ambiguous associated types of supertraits


In a nutshell, I am facing an issue with the following: I am willing to abstract codec implementations from tokio_util::codec. In order to do so, I defined a trait that has Decoder and Encoder<T> as supertraits.

use tokio_util::codec::{Decoder, Encoder};


struct CodecA {}


impl Decoder for CodecA {
    type Item = Vec<u8>;
    type Error = std::io::Error;
...
}

impl Encoder<Vec<u8>> for CodecA {
    type Error = std::io::Error;
...
}

// the synthetic trait based upon Decoder and Encoder
trait Codec<T>: Decoder<> + Encoder<T>  {}

impl Codec<Vec<u8>> for CodecA { }


Later in the code, I try to instantiate a Framed instance, when providing dyn Codec<> as the second argument.

    let stream = ... ;
    let mut lines: Framed<Box<dyn AsyncReadAndWrite>, dyn Codec<Vec<u8>, Error=std::io::Error, Item=Vec<u8>>> ;


    match protocol {
        KindA => lines = Framed::new(stream, CodecA {}),
        KindB => lines = Framed::new(stream, CodecB {}),
    }

That's where I can't seem to satisfy the compiler:

Error[E0222]: ambiguous associated type `Error` in bounds of `codec::Codec<Vec<u8>>`
   --> src/workers.rs:190:74
    |
190 |     let mut lines: Framed<Box<dyn AsyncReadAndWrite>, dyn Codec<Vec<u8>, Error=std::io::Error, Item=Vec<u8>>> ;
    |                                                                          ^^^^^^^^^^^^^^^^^^^^ ambiguous associated type `Error`
    |
    = note: associated type `codec::Codec<Vec<u8>>` could derive from `Encoder<Vec<u8>>`
    = note: associated type `codec::Codec<Vec<u8>>` could derive from `Decoder`

What would be the syntax to tell rustc that Error in the Codec definition applies to both Encode and Decode? What about Item? Finally, is there another approach?


Solution

  • You can change the associated types into generic parameters:

    trait Codec<T, DecoderError, EncoderError>:
        Decoder<Error = DecoderError> + Encoder<T, Error = EncoderError>
    {
    }
    
    impl<U, T: ?Sized + Decoder + Encoder<U>> Codec<U, <T as Decoder>::Error, <T as Encoder<U>>::Error>
        for T
    {
    }
    
    let mut lines: Framed<Box<dyn AsyncReadAndWrite>, dyn Codec<Vec<u8>, std::io::Error, std::io::Error, Item = Vec<u8>>>;