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?
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>>>;