How to simplify complicated type signatures in a struct?

I have a struct with two members each of which is a pretty complicated type. If I were to write out the types in full it would look something like the following which isn't valid since _ can not be used in this context:

pub struct Device {
    pub requests: Framed<FramedWrite<WriteHalf<TcpStream>, LengthDelimitedCodec>, Request, _, _>,
    pub responses: Framed<FramedRead<ReadHalf<TcpStream>, LengthDelimitedCodec>, Response, _, _>
}

So I thought I could solve this problem by just specifying the trait bounds that I care about on these members, for example:

pub struct Device<Tx, Rx>
    where Tx: futures::Sink<protocol::Request>,
          Rx: futures::Stream<Item = protocol::Response> {
    pub requests: Tx,
    pub responses: Rx,
}

However, this isn't ideal since the struct is now generic over Rx and Tx with respect to the specified bounds which is not the functionality that I wanted and now forces me to specify these types a level up.

Is there a way of defining my struct without writing out the full type signatures but at the same time not being generic over Rx and Tx?

You could use a type alias:

type Requests = Framed<FramedWrite<WriteHalf<TcpStream>, LengthDelimitedCodec>, Request, SomeType1, SomeType2>;
type Responses = Framed<FramedRead<ReadHalf<TcpStream>, LengthDelimitedCodec>, Response, SomeType1, SomeType2>;

pub struct Device {
    pub requests: Requests,
    pub responses: Responses
}

True, but consider if instead I needed to store the result of an async block or function into a struct? How would I do that considering that the type of the returned Future is a hidden compiler generated type?

If the type is not nameable, you cannot use it in a struct directly. You would need something like Pin<Box<dyn Future>>.

2 Likes

Alternatively, you may be able to use the unstable type_alias_impl_trait feature to define a type alias for a closure or Future that's otherwise unnameable.

1 Like

Is there a reason why it isn't possible to do the following:

struct Device {
    requests: impl Sink<Request>,
    responses: impl Stream<Item = Response>,
}

It seems like this would be consistent with the idea of returning types that implement traits.

Actually... correct me if I am wrong here, @2e71828, but the syntax that I propose would be available if the type_alias_impl_trait feature were to be stabilized, right?

More or less, though I think you have to actually make a type alias, but it would have that effect.

2 Likes

Quick question @alice, is it guaranteed that the Pin is necessary in the other solution that you suggested? That is, with the:

Pin<Box<dyn Future>>

You need a Pin around a boxed Future or Stream, yes.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.