Add codegen support for rpc_service declarations#362
Open
FredrikNoren wants to merge 4 commits into
Open
Conversation
Each rpc_service now generates a transport-agnostic Rust trait with one method per (unary) rpc method, taking the zero-copy Ref type as request and returning the owned type. Streaming methods and non-table argument/return types are rejected with proper errors instead of the previous blanket "not supported" error. The dot backend renders services as nodes with edges to their argument/return tables. Closes planus-org#56 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Each service now additionally generates a GreeterAsync-style trait using native async-fn-in-trait (MSRV 1.88 > 1.75), so the service can be implemented in async code without any extra dependencies. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Each service now also generates a GreeterMethod-style enum where every method gets a numeric id from its zero-based declaration index, plus name()/id()/TryFrom<u32> conversions and an ENUM_VALUES list, so transports can route and relay messages without hardcoding ids. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The service name was only reachable through the traits' associated NAME const, which requires an implementing type — consumers that just relay or route messages had to write a dummy probe impl to read it. Generate a free `GREETER_NAME`-style constant as the canonical source, reference it from the traits' NAME defaults, and expose it on the method enum as SERVICE_NAME. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #56
What
rpc_servicedeclarations are now supported instead of being rejected with "Rpc services are not currently supported". Each service generates a module-level name constant, transport-agnostic Rust traits — a sync one and an async one — plus a method enum with numeric ids for routing:Requests are received as the zero-copy
Reftypes and responses are returned as the owned types, so the traits work as server-side handler interfaces over any transport. Schema docstrings are carried through, andidempotentmethods get a doc note. The async trait uses native async-fn-in-trait (stable since 1.75, below the 1.88 MSRV), so there are no new dependencies; the#[allow(async_fn_in_trait)]leaves theSend-bound decision to implementors. The method enum gives transports a stable numeric handle for dispatching/relaying messages without hardcoding ids; ids follow declaration order (documented on the type), mirroring the conventions of the schema-enum codegen (ENUM_VALUES,TryFrom, serde derives). The free name constant exists because an associated const on a trait cannot be read without an implementing type — clients and relays that never implement the handler traits would otherwise need a dummy probe impl just to learn the service name.Since flatc has no Rust RPC output to stay compatible with, this deliberately starts with the smallest useful surface (no generated client/server stubs, no dependency on any specific RPC framework). Happy to adjust the design based on feedback — that's also why streaming is rejected rather than given a made-up signature.
Changes by layer
translate_rpc_servicenow actually translates methods (it previously returned an empty map),intermediate::RpcMethodgainsidempotent+ docstrings. Argument/return types are validated to be tables (same rule as flatc).streaming: "none"andidempotentare accepted;streaming: "client"/"server"/"bidi"get a dedicated "not currently supported" error.generate_rpc_service/generate_rpc_methodto theBackendtrait and replaced the threetodo!()s inbackend_translation.rs, so services flow through the same pipeline as the other declarations.rpc_serviceremoved from the unsupported list (with a note that streaming methods are still unsupported).Tests
test/rust-test-20xx/api_files/rpc_service.{fbs,rs}: implements both generated traits and does a full serialize → read-as-ref → handle → assert round-trip; the async future is driven viaWaker::noop()so no executor dependency is needed; the name constants and the method enum's ids, names,ENUM_VALUESandTryFromconversions are asserted.test/files/valid/rpc_service.fbs: accepted-schema fixture (namespaces, docstrings,idempotent,streaming: "none").test/files/invalid/rpc_bad_types.{fbs,stderr}andrpc_streaming.{fbs,stderr}: golden stderr for non-table method types and for all streaming variants + an invalid streaming value.rpc_service_as_type.stderranddefined_twice.stderr, whose expected output changed.🤖 Generated with Claude Code