feat(compiler): Add grpc support for Swift#3776
Draft
yash-agarwa-l wants to merge 16 commits into
Draft
Conversation
Schemas with services now emit a <Service>Grpc.swift companion beside the Swift model. Each service gets Fory-backed async and NIO providers plus an async client; request and response bytes ride a private GRPCPayload wrapper that serializes through the schema module's Fory instance.
Before writing Swift output, check that no two schemas or services claim the same file path or top-level symbol. A service named after a generated type, or a duplicate service, now fails fast with a clear message instead of emitting Swift that will not compile.
Exercise the Swift companion across the four streaming shapes, keyword-escaped methods, imported request and response types, the default package, both IDL frontends, and the collision preflight, so the emitter and its symbol names stay pinned.
Generate a two-package schema, then swift build and run a SwiftPM package on grpc-swift and local Fory that hosts the generated provider and round-trips all four streaming shapes across the import boundary. Skipped when swift is absent.
Wire Swift into the shared gRPC generation step so the interop schemas emit Swift companions alongside the other targets.
Add a Swift gRPC guide covering dependencies, server and client usage, streaming, and troubleshooting, link it from the Swift guide index, and note the Swift companion in the compiler guide and agent rules.
Break the streaming handler closures across lines so generated companions stay under the swiftlint line-length limit even with long package-qualified names.
Put handler braces on the declaration line, give each async parameter its own aligned line, name the unwrapped stream value, and scope a type_name disable around the package-prefixed symbols so swiftlint reports no violations.
Schemas that share a top-level package component make the model generator emit a duplicate root enum, which the Swift compiler rejects in one module. Pin it with a strict xfail fixture and a docs note pointing at disjoint packages.
The Swift Fory instance is single-threaded, but gRPC drives the marshaller from many threads at once, so sharing one instance races. Build one Fory per thread from the module config and registrations, and fire 200 parallel calls in the fixture to exercise it.
Record that the generated client is async only and that interceptors are not emitted, both because grpc-swift types them on the internal Fory wrapper, and describe the per-thread marshalling.
Name the wire wrapper per service so it is reachable, then drive it from 2000 parallel threads under ThreadSanitizer, asserting no data race and that the per-thread Fory stays wire-compatible with the module's shared instance. Against a shared instance TSan flags a race in the type resolver.
The ThreadSanitizer build adds about three minutes and is environment sensitive, so keep it opt-in for a sanitizer or nightly job while the functional fixtures still run on every swift-capable run.
An rpc whose Swift name is handle, serviceName, channel, or defaultCallOptions would clash with a member the generated provider or client inherits, so fail codegen with a clear message. Cover the reserved names and nested plus imported request and response payloads.
# Conflicts: # compiler/fory_compiler/tests/test_service_codegen.py # docs/compiler/compiler-guide.md # integration_tests/grpc_tests/generate_grpc.py
Collaborator
|
@yash-agarwa-l Please git merge apache/main first to address the conflicts |
Contributor
Author
|
I already did that, so I'm not sure why it's still showing up. Let me mark it as ready for review and double-check. |
The SwiftPM build-and-run round-trip and the ThreadSanitizer marshaller test need the Swift toolchain, so move them out of the compiler pytest suite (where they only skipped) into a SwiftPM package under integration_tests/grpc_tests/swift. The common-root package limitation stays pinned as a build-free generation check.
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.
Why?
Swift users can generate Fory model types today, but schemas that define services
do not produce Swift gRPC companions. This leaves Swift out of the existing
--grpcworkflow used by the other supported service-generation targets.
What does this PR do?
metadata descriptors, an
EventLoopFutureprovider, an async/await provider, anasync client, and Fory-backed request/response stream adapters, targeting grpc-swift 1.x.
internal
GRPCPayloadwrapper. Because the SwiftForyruntime is single-threaded,the wrapper builds one
Foryper thread from the schema module's own configurationand registrations, so concurrent RPCs are race-free (verified under ThreadSanitizer).
EventLoopFutureclient and interceptor hooks areomitted because their generated types would expose the internal wrapper.
collisions, and reserves inherited provider/client member names (
handle,serviceName,channel,defaultCallOptions) so a clashing rpc fails codegenwith a clear message.
identifier escaping, imported and nested service types, the default package, the
protobuf and FlatBuffers frontends, collision handling, a SwiftPM build-and-run
fixture, and a marshaller concurrency test under ThreadSanitizer (gated behind
FORY_SWIFT_TSAN).shared-top-level-package limitation, troubleshooting, and compiler guide updates.
Draft: Java<->Swift cross-language interop tests (all four modes, all three IDL
frontends) are in progress and will be added before this PR is marked ready for review.
Related issues
#3266
#3370
AI Contribution Checklist
yesyes, I included a completed AI Contribution Checklist in this PR description and the requiredAI Usage Disclosure.yes, my PR description includes the requiredai_reviewsummary and screenshot evidence of the final clean AI review results from both fresh reviewers on the current PR diff or current HEAD after the latest code changes.Does this PR introduce any user-facing change?
foryc --swift_out=... --grpcis used.change the Fory binary protocol.
Benchmark
Not applicable.