I have the following code (constrained example). There is a serial protocol, modelled with Command
and Responce
enums using enum_dispatch
crate - every variant in enum is represented with a struct. Transport
struct taskes care of serialization, execution and deserialization of Command
s, returning TransportResult
s back with generic Responce
enum(generic impl) or specific struct(templated impl). The generic implementation works just fine, but the templated one fails to compile.
use enum_dispatch::enum_dispatch;
use thiserror::Error;
trait Value{/**/}
trait CommandResponce {type Responce}
#[enum_dipatch(Value)]
enum Command{
Cmd1(Cmd1)
// ...
}
struct Cmd1{}
impl Value for Cmd1{ /**/ }
#[enum_dipatch(Value)]
enum Responce{
Resp1(Resp1)
// ...
}
struct Resp1{}
impl Value for Resp1{/**/}
impl CommandResponce for Cmd1{ type Responce=Resp1 }
#[derive(Error, Debug)]
pub enum ProtocolError{/**/}
type ProtocolResult<T> = Result<T, ProtocolError>;
struct Transport {/**/}
impl Transport {
// generic
pub fn command_generic_with_addr(
&mut self, addr: &mut u8, c: Command
) -> ProtocolResult<Responce>{ /**/ }
// templated
pub fn command_with_addr<T: SerializeCommand + CommandResponce>(
&mut self, addr: &mut u8, c: T) -> ProtocolResult<T::Responce>
where
Command: From<T>, Responce: TryInto<T::Responce, Error=&'static str>,
Responce: TryInto<T::Responce, Error= CommandErrors> {
let resp: Responce = self.command_generic_with_addr(addr, Command::from(c))?;
let ret: T::Responce = resp.try_into()?;
Ok(ret)
}
}
fn main() -> eyre::Result<()>{
let t = Transport::new();
let addr : u8 = 0xFF;
t.command_with_addr(&mut addr, Cmd1{/**/})
}
When I try to compile code, identical to the one above, I get the following error:
error[E0284]: type annotations needed: cannot satisfy `<Responce as TryInto<<T as CommandResponce>::Responce>>::Error == _`
-->
|
85 | let ret: T::Responce = match resp.try_into() {
| ^^^^^^^^ cannot satisfy `<Responce as TryInto<<T as CommandResponce>::Responce>>::Error == _`
I can't understand, what is the error here - I thought I've stated all the neccessary type annotations in the Transport::command_with_addr
member function.
Note, enum_dispatch
uses the following code to generate try_into
conversion, used in the code above:
impl #impl_generics core::convert::TryInto<#variant_type> for #enumname #ty_generics #where_clause {
type Error = &'static str;
fn try_into(self) -> ::core::result::Result<#variant_type, <Self as core::convert::TryInto<#variant_type>>::Error> {
//..
}
}