Ergonomic announced streams in Swift and Kotlin wrappers#1554
Merged
Conversation
The announced subscription forced an awkward two-step in the wrappers: acquire a handle, then call a separate stream member that stuttered against the handle name (announced.announcements). moq-ffi can't help here. uniffi can't carry a stream across the FFI boundary, so the next()-based handle is the only option and the ergonomics belong in each wrapper. - Swift: MoqAnnounced now conforms to AsyncSequence, so the handle iterates directly (for try await a in announced). - Kotlin: replace the MoqAnnounced.announcements() extension with a fused MoqOriginConsumer.announcements(prefix): Flow that acquires the subscription on collection and cancels it via try/finally. This matches how the other consumers pair a low-level next() with a Flow extension. - Go: add range-over-func iter.Seq2 iterators for the whole stream set (Announcements, Groups, GroupsAsArrived, Frames, Updates); Go previously had no ergonomic layer at all. Bumps go.mod to 1.23 for iter. Docs and per-language READMEs updated to the new call sites; doc/lib/go gains a Subscribe example it was missing.
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.
Summary
The announced subscription was awkward to consume in the language wrappers: you acquired a handle and then called a separate stream member whose name stuttered against the handle (
announced.announcements()/announced.announcements). This reworks the Swift and Kotlin wrappers so each stream reads idiomatically in its own language.moq-ffiis untouched on purpose. uniffi can't carry a stream across the FFI boundary, so the pull-basednext()handle is the only option and the ergonomics belong in the wrappers (Python already does this).MoqAnnouncednow conforms toAsyncSequence, so the handle iterates directly:MoqAnnounced.announcements()extension with a fusedMoqOriginConsumer.announcements(prefix): Flowthat acquires the subscription on first collection and cancels it viatry/finally(forwarding cancellation on every completion path, not justCancellationException):next()with aFlowextension.Docs and per-language READMEs are updated to the new call sites.
Go deferred
Go was dropped from this PR. Its bindings have no ergonomic layer at all (every stream is raw), and bringing it to parity is entangled with a larger open question: whether the compiled-FFI wrappers (Swift/Kotlin/Go) should move to a Python-style hand-written wrapper layer, and whether to drop the
moq.MoqClientstutter. That's a deliberate, separately-scoped refactor rather than a rider on this announced-ergonomics change.Why
devThis is a breaking change to the public Swift/Kotlin wrapper APIs (the old
.announcementsmember is gone), which per the branch-targeting rule belongs ondev. It also builds naturally on the auto-origin session rework already ondev(cs.consumer()etc.), which the updated docs use.Design note for reviewers
Teardown-on-abandon differs slightly between the two, pre-existing and left as-is: Swift cancels on any stream termination; Kotlin cancels on coroutine cancellation (the new fused
announcementsalso cancels the handle it acquired viatry/finally).Test plan
just swiftbuilds + smoke tests pass, no@retroactive/conformance warnings.just kt check.(Written by Claude)