2

As you can see, all the types below have the same structure:

type Response = rtsp_types::Response<Body>;

struct PlayResponse(Response);
struct DescribeResponse(Response);
struct SetupResponse(Response);
struct PauseResponse(Response);
struct TeardownResponse(Response);
struct RecordResponse(Response);
struct UnauthorizedResponse(Response);

And I want to do the same implementation for them:

impl From<Response> for PlayResponse {
    fn from(response: Response) -> Self {
        PlayResponse(response)
    }
}

impl From<Response> for DescribeResponse {
    fn from(response: Response) -> Self {
        DescribeResponse(response)
    }
}

//...

but I don't want to be repetitive.

I know that I could do an enum with all of them, but this solution does not apply to my problem for reasons that are too large to put here.

What would be the be best way to implement From for all these structs, just like the example implementation I did? Macros? Isn't there a way to do a generic implementation over T?

Gatonito
  • 1,662
  • 5
  • 26
  • 55
  • There is no way of implementing a Trait for multiple structs at once but maybe this answer can help you: https://stackoverflow.com/questions/45309789/implement-one-trait-for-multiple-structs-at-once – Leo Lamas Apr 11 '21 at 04:58
  • *"Isn't there a way to do a generic implementation over T?"* - not for this, [there's no constraint for newtype structs](https://stackoverflow.com/questions/24831573/automatically-implement-traits-of-enclosed-type-for-rust-newtypes-tuple-structs). Pretty much macros are your only way. – kmdreko Apr 11 '21 at 20:27

2 Answers2

2

You can use the duplicate crate to easily do this:

use duplicate::duplicate;

type Response = rtsp_types::Response<Body>;

duplicate!{
    [
        Name;
        [PlayResponse];
        [DescribeResponse];
        [SetupResponse];
        [PauseResponse];
        [TeardownResponse];
        [RecordResponse];
        [UnauthorizedResponse];
    ]
    struct Name(Response);
    impl From<Response> for Name {
        fn from(response: Response) -> Self {
            Name(response)
        }
    }
}

This will both declare each struct and its implementation, substituting Name for the name of each struct.

Emoun
  • 2,297
  • 1
  • 13
  • 20
2

The traditional way is just to make a declarative macro that implements From for your various types:

type Response = rtsp_types::Response<Body>;

struct PlayResponse(Response);
struct DescribeResponse(Response);
struct SetupResponse(Response);
struct PauseResponse(Response);
struct TeardownResponse(Response);
struct RecordResponse(Response);
struct UnauthorizedResponse(Response);

macro_rules! impl_from_response {
    ($t:ident) => {
        impl From<Response> for $t {
            fn from(response: Response) -> Self {
                $t(response)
            }
        }
    }
}

impl_from_response!(PlayResponse);
impl_from_response!(DescribeResponse);
impl_from_response!(SetupResponse);
impl_from_response!(PauseResponse);
impl_from_response!(TeardownResponse);
impl_from_response!(RecordResponse);
impl_from_response!(UnauthorizedResponse);
kmdreko
  • 42,554
  • 6
  • 57
  • 106