n0-computer / quic-rpc

A streaming rpc system based on quic
Other
94 stars 12 forks source link

Add macro crate to allow placing rpc interation patterns directly on the request enum. #90

Closed rklaehn closed 3 months ago

rklaehn commented 3 months ago

The way the interaction patterns are specified is very flexible and does a very good job explaining it to the compiler.

However, a downside is that it is pretty verbose and that you don't have a single place to grasp how a service works.

This PR adds an additional macro crate that allows annotating the request enum with the interaction pattern for each request type. It does not require any changes to quic-rpc itself, just basically derives the various quic-rpc message traits.

Example syntax:

  #[rpc_requests(Service)]
  #[derive(Debug, Serialize, Deserialize, derive_more::From, derive_more::TryInto)]
  enum Request {
      #[rpc(response=u32)]
      Rpc(RpcRequest),
      #[server_streaming(response=())]
      ServerStreaming(ServerStreamingRequest),
      #[bidi_streaming(update=(), response = ())]
      BidiStreaming(BidiStreamingRequest),
      #[client_streaming(update = (), response = ())]
      ClientStreaming(ClientStreamingRequest),
      // an update, you will never get this as the first message
      GenericUpdate(()),
  }

Enforced rules:

Rules are checked using trybuild.

The service type itself still has to be defined manually, since we want to leave the possibility open that the service enum is a nested enum that works for multiple subsystems.

We might do a macro to do the service definition itself, but it is not much code either way.

    impl quic_rpc::Service for Service {
        type Req = Request;
        type Res = Response;
    }
Frando commented 3 months ago

Cool, this simplifies defining the RPC interface quite a bit.

Can we derive the response as well from the Request enum? Seems superflous to write out manually now that we're in proc macro land anyway? (or maybe that is not easily possible, didn't think it through) - maybe it is nicer also though to have the Respones enum spelled out in code instead of being generated by a macro. So let's leave that for later maybe.

rklaehn commented 3 months ago

Cool, this simplifies defining the RPC interface quite a bit.

Can we derive the response as well from the Request enum? Seems superflous to write out manually now that we're in proc macro land anyway? (or maybe that is not easily possible, didn't think it through) - maybe it is nicer also though to have the Respones enum spelled out in code instead of being generated by a macro. So let's leave that for later maybe.

I am somewhat hesitant to do it because the way this works you still have the option to do things manually. E.g. you have a case for which you want to use an interaction pattern that is not yet supported by the macro. Or you want to build the response in a non-standard way. Just writing it out does not seem extremely bad, so if we do this it would have to be an optional feature.

dignifiedquire commented 3 months ago

ci seems quite sad

rklaehn commented 3 months ago

ci seems quite sad

Has nothing to do with the code. It is just derive_more producing code that the beta compiler finds objectionable. Not sure what to do about it. Use my own enum from derive crate? I would prefer to use something else. 🤷