-
Notifications
You must be signed in to change notification settings - Fork 3
refactor: Add associated types to Service
, use protocol enum as Service
#46
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
3a1b930
to
a12a1e1
Compare
Service
, use protocol enum as Service
targetService
, use protocol enum as Service
That was always possible, since the service struct was nowhere needed by value. But nevertheless, nice simplification. In general I like this. It creates a closer coupling between the service and the enums, so you can no longer have e.g. an enum that claims to handle service Foo and handles all cases required for Foo and some additonal internal messages. But I guess in tokio actors the best way to handle internal messages is via a second channel anyway, so it might be OK. |
Currently giving this a spin in a new repo. One thing I noticed - the docs are not yet updated, still have the many type parameters.
|
So the first parameter of the macro is the "full" enum containing each case with channels and span? Is the service trait implemented for the serializable message enum or for the full enum? I am playing around with this in a separate repo, and am a bit confused. I got it to work, like this: #[rpc_requests(TestMessage, alias = "Msg")]
#[derive(Debug, Serialize, Deserialize)]
enum TestProtocol {
#[rpc(tx = oneshot::Sender<String>)]
Put(PutRequest),
#[rpc(tx = mpsc::Sender<String>)]
Get(GetRequest),
} But I can't see the type aliases for the full cases: fn foo(msg: PutRequestMsg) -> String { // does not compile!
format!("Received Put request with key: {}, value: {}", msg.key, msg.value)
} And if I point the macro to an explicit service, I get an error as well: #[rpc_requests(TestMessage, service = TestService, alias = "Msg")]
#[derive(Debug, Serialize, Deserialize)]
enum TestProtocol {
#[rpc(tx = oneshot::Sender<String>)]
Put(PutRequest),
#[rpc(tx = mpsc::Sender<String>)]
Get(GetRequest),
} =>
So Service must always be implemented for the Protocol enum? Then what is the service parameter for? |
irpc-derive/src/lib.rs
Outdated
@@ -382,8 +415,8 @@ impl Parse for MacroArgs { | |||
input.parse::<Token![=]>()?; | |||
|
|||
match param_name.to_string().as_str() { | |||
"message" => { | |||
message_enum_name = Some(input.parse()?); | |||
"service" => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Docs for the rpc_requests macro are out of date.
Yeah, docs are not updated yet - will do this once we decide to go forward with this to not do it multiple times.
Yes.
It is implemented for the serializable message enum (i.e. the enum people usually write themselves and which has the macro on it).
It works but the alias is called This work for me: Type aliasesuse irpc::{
channel::{mpsc, oneshot},
rpc_requests,
};
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
struct PutRequest {
key: String,
value: String,
}
#[derive(Debug, Serialize, Deserialize)]
struct GetRequest {
key: String,
}
#[rpc_requests(TestMessage, alias = "Msg")]
#[derive(Debug, Serialize, Deserialize)]
enum TestProtocol {
#[rpc(tx = oneshot::Sender<String>)]
Put(PutRequest),
#[rpc(tx = mpsc::Sender<String>)]
Get(GetRequest),
}
fn foo(msg: PutMsg) -> String {
// does not compile!
format!(
"Received Put request with key: {}, value: {}",
msg.inner.key, msg.inner.value
)
}
Right, there was a bug, this is now fixed. This gist works: Custom serviceuse irpc::{
channel::{mpsc, oneshot},
rpc_requests, Service,
};
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
struct PutRequest {
key: String,
value: String,
}
#[derive(Debug, Serialize, Deserialize)]
struct GetRequest {
key: String,
}
#[derive(Debug)]
struct TestService;
impl Service for TestService {
type Message = TestMessage;
type WireMessage = TestProtocol;
}
#[rpc_requests(TestMessage, alias = "Msg", service = TestService)]
#[derive(Debug, Serialize, Deserialize)]
enum TestProtocol {
#[rpc(tx = oneshot::Sender<String>)]
Put(PutRequest),
#[rpc(tx = mpsc::Sender<String>)]
Get(GetRequest),
}
fn foo(msg: PutMsg) -> String {
// does not compile!
format!(
"Received Put request with key: {}, value: {}",
msg.inner.key, msg.inner.value
)
}
fn main() {}
It doesn't have to be implemented on the Protocol enum. The default is that the rpc_requests macros adds an impl of Service for the Protocol enum. But you could provide your own with a service parameter. Maybe this is not needed though, I can't really think of situations where you'd want to use the macro but set it to a different service. Not sure? |
I can't think of a concrete downside of "protocol enum is service", other than some abstract things that are probably best handled at a higher level anyway. So I would vote for just making this the default. Then you would not need any arg on the macro for standard use. It just builds you the second enum and a bunch of from conversions and the like. |
Yes, the latest commit impls that. |
Thanks, will give it another test drive today. |
Replying to #51 (comment) which is more fitting here:
If
Correct. This is the only part of the generated code that depends on the
I don't think the macro has any effect on that. The generated code only does |
I added a commit that improves the docs further. I think this is ready to go from my side. Maybe it's better to make the |
I still got a few bikesheds, mostly about naming. Is rpc_requests still the right name for the macro? Are no_rpc and no_spans good names? E.g. I was a bit confused that no_spans does not mean that you don't have spans, just that it does not generate the associated code using spans. But we can do this in a subsequent PR. The macro docs are very good now. |
## Description This bumps irpc to the main version, adapting for the breaking changes introduced in n0-computer/irpc#46. ## Breaking Changes - `iroh_blobs::api::proto::StoreService` is removed, `Request` now implements `irpc::Service` - `iroh_blobs::api::downloader::DownloaderService` is removed, `SwarmProtocol` now implements `irpc::Service` ## Notes & open questions <!-- Any notes, remarks or open questions you have to make about the PR. --> ## Change checklist - [ ] Self-review. - [ ] Documentation updates following the [style guide](https://rust-lang.github.io/rfcs/1574-more-api-documentation-conventions.html#appendix-a-full-conventions-text), if relevant. - [ ] Tests if relevant. - [ ] All breaking changes documented. --------- Co-authored-by: Ruediger Klaehn <[email protected]>
Based on #47 (can rebase on main if needed)
Alternative to #41
Fixes #39
This PR simplifies working with
irpc
:Instead of defining a separate
FooService
struct, theService
trait is implemented on the protocol enum. One type less to create.Added an associated types to the
Service
trait to point to the extended message enum (the one where the variants contain theWithChannels
structs). By doing this, we can reduce the generics on theClient
from 3 to 1, and on theLocalSender
from 2 to 1. I think this is a net benefit for all users.The service trait is now implemented by the proc macro if the
message
argument is provided.A new trait
RemoteService: Service
has a required method to create a aService::Message
from the protocol enum, and a provided method to create aHandler
for use with the listen function. TheRemoteService
impl is generated by the proc macro. This saves the tedious manual impl of mapping frommsg, rx, tx
to the message enum (see the diff in the examples).Added
no_rpc
andno_spans
arguments to the macro to omit generating code that depends on therpc
orspans
features ofirpc
Expanded and improved the documentation of the
rpc_requests
macro. Also moved it fromirpc_derive
toirpc
to be able to add doc links to items fromirpc
.First and foremost, have a look at the diff to the examples.