#Associative types with TryFrom

19 messages · Page 1 of 1 (latest)

fair jasper
#

Hello,

I want to define a trait with two associative types where I Implemented TryFrom<A> to B however, I can't seem to get rust to accept syntax, it complains about needing From<A> to B whilst that's not what is available due to possible conversion errors... Any tips?

pub trait MiddlewareType {
    type ProtoType: Message + Default where Self::ProtoType: TryFrom<Self::RustType>, <Self::ProtoType as TryFrom<Self::RustType>>::Error: std::fmt::Debug;
    type RustType: Clone; 

    fn into_proto(value: Self::RustType) -> Result<Self::ProtoType, Box<dyn std::error::Error>> {
        Self::ProtoType::try_from(value).map_err(|e| e.into())
    }
}
the trait bound `<Self as MiddlewareType>::ProtoType: From<<Self as MiddlewareType>::RustType>` is not satisfied
required for `<Self as MiddlewareType>::RustType` to implement `Into<<Self as MiddlewareType>::ProtoType>`
required for `<Self as MiddlewareType>::ProtoType` to implement `TryFrom<<Self as MiddlewareType>::RustType>`rustc
mw.rs(71, 96): consider further restricting the associated type: ` where <Self as MiddlewareType>::ProtoType: From<<Self as MiddlewareType>::RustType>`

(adding the suggested restriction also doesn't solve the issue)

visual apex
#

-errors

frigid falconBOT
#

Run cargo check in a terminal

Note: If using rust analyzer you can click the "click for full compiler diagnostic" link in your editor.

Please post the full output of the above command, including the error title and any help or notes. An example of how this looks is:

error[E0308]: mismatched types
 --> src/main.rs:3:17
  |
3 | let foo: &i32 = bar;
  |          ----   ^^^ expected `&i32`, found integer
  |          |
  |          expected due to this
  |
help: consider borrowing here
  |
3 | let foo: &i32 = &bar;
  |                 +

When posting the error put it in a code block so it has nice formatting:

```rust
// error from cargo check here
```

Please do not post a screenshot. If the output is too long then use a paste tool like https://paste.rs/web

fair jasper
#
error[E0277]: the trait bound `<Self as MiddlewareType>::ProtoType: From<<Self as MiddlewareType>::RustType>` is not satisfied
  --> middleware_common/src/mw.rs:71:52
   |
71 |     fn into_proto(value: Self::RustType) -> Result<Self::ProtoType, Box<dyn std::error::Error>> {
   |                                                    ^^^^^^^^^^^^^^^ the trait `From<<Self as MiddlewareType>::RustType>` is not implemented for `<Self as MiddlewareType>::ProtoType`
   |
   = note: required for `<Self as MiddlewareType>::RustType` to implement `Into<<Self as MiddlewareType>::ProtoType>`
   = note: required for `<Self as MiddlewareType>::ProtoType` to implement `TryFrom<<Self as MiddlewareType>::RustType>`
help: consider further restricting the associated type
   |
71 |     fn into_proto(value: Self::RustType) -> Result<Self::ProtoType, Box<dyn std::error::Error>> where <Self as MiddlewareType>::ProtoType: From<<Self as MiddlewareType>::RustType> {
   |                                                                                                 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#

Ah, I now notice the restriction is on the function, not on the type. But still the problem remains, that I can't do infallible conversions, so From is not possible, but TryFrom is...

visual apex
#

Wierd. This'll work, though:

#

pub trait MiddlewareType {
    type ProtoType: Message + Default + TryFrom<Self::RustType>;
    type RustType: Clone;

    fn into_proto<'err_lifetime>(
        value: Self::RustType,
    ) -> Result<Self::ProtoType, Box<dyn std::error::Error + 'err_lifetime>>
    where
        <Self::ProtoType as TryFrom<Self::RustType>>::Error: std::error::Error + 'err_lifetime,
    {
        Self::ProtoType::try_from(value).map_err(|e| e.into())
    }
}
#

Can even move the TryFrom bound to the function

#

I think the bulk of your initial error was that Box<dyn Error> needs a type that impls Error to implement From<E>

#

But you only had a Debug bound on the error.

#

That and Box<dyn T> has a 'static bound on T by default that was messing things up

fair jasper
#

Right, ok, thx, that make sense, let me see how that fits

#

Is there anyway the where clause of the function can be enforced on the associative type? Everywhere I attempt to use the into_proto function, it will demand that extra where clauses on the MiddlewareType trait which I would like to avoid...

error[E0277]: the trait bound `<<MT as MiddlewareType>::ProtoType as TryFrom<<MT as MiddlewareType>::RustType>>::Error: std::error::Error` is not satisfied
   --> middleware_common/src/publisher.rs:226:23
    |
226 |             let msg = MT::into_proto(cur)?;
    |                       ^^ the trait `std::error::Error` is not implemented for `<<MT as MiddlewareType>::ProtoType as TryFrom<<MT as MiddlewareType>::RustType>>::Error`
    |
note: required by a bound in `MiddlewareType::into_proto`
   --> middleware_common/src/mw.rs:79:62
    |
75  |     fn into_proto<'err_lifetime>(
    |        ---------- required by a bound in this associated function
...
79  |         <Self::ProtoType as TryFrom<Self::RustType>>::Error: std::error::Error + 'err_lifetime,
    |                                                              ^^^^^^^^^^^^^^^^^ required by this bound in `MiddlewareType::into_proto`
help: consider further restricting the associated type
    |
224 |     fn handle_channel(&self) -> Result<(), Box<dyn std::error::Error>> where <<MT as MiddlewareType>::ProtoType as TryFrom<<MT as MiddlewareType>::RustType>>::Error: std::error::Error {
    |                                                                        ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
visual apex
#

I'm definitely missing something but this works until you find something better XD:

pub trait MiddlewareType {
    type ProtoType<'err_lifetime>: Default + TryFrom<Self::RustType>
    where
        <Self::ProtoType<'err_lifetime> as TryFrom<Self::RustType>>::Error:
            std::error::Error + 'err_lifetime;
    type RustType: Clone;

    fn into_proto<'err_lifetime>(
        value: Self::RustType,
    ) -> Result<Self::ProtoType<'err_lifetime>, Box<dyn std::error::Error + 'err_lifetime>>
    where
        <Self::ProtoType<'err_lifetime> as TryFrom<Self::RustType>>::Error:
            std::error::Error + 'err_lifetime,
    {
        Self::ProtoType::try_from(value).map_err(|e| e.into())
    }
}
thick pine
#

?play

pub trait MiddlewareType {
    type ProtoType<'err_lifetime>: Default + TryFrom<Self::RustType, Error: std::error::Error + 'err_lifetime>
    where Self: 'err_lifetime;
    type RustType: Clone;

    fn into_proto<'err_lifetime>(
        value: Self::RustType,
    ) -> Result<Self::ProtoType<'err_lifetime>, Box<dyn std::error::Error + 'err_lifetime>>
    {
        Self::ProtoType::try_from(value).map_err(|e| e.into())
    }
}
zinc juncoBOT
thick pine
#

Here you go

#

The issue is where clauses aren't automatically propagated to usage sites but inherent bounds are