refactor(kio)!: delete Consumer::write/produce, add shared Sender/Receiver#2074
Open
kixelated wants to merge 1 commit into
Open
refactor(kio)!: delete Consumer::write/produce, add shared Sender/Receiver#2074kixelated wants to merge 1 commit into
kixelated wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Sorry @kixelated, you have reached your weekly rate limit of 500000 diff characters.
Please try again later or upgrade to continue using Sourcery
3c62431 to
5ea4488
Compare
…h, add shared channel `kio::Consumer` documented itself read-only but exposed `write()` and `produce()`, mutable back-doors that also re-exposed the `Mut::deref_mut`-marks-modified wake footgun to external users. Delete both. `kio::Weak` was the same hole one level down: a single type with `produce`, `write`, and the producer-side `used`/`unused` *and* the consumer-side `consume`/`read`, reachable from `Consumer::weak()`. So `consumer.weak().produce()` bypassed the deletion. Rename it to `ProducerWeak` (only a producer mints one), drop `write` (upgrade via `produce()` instead), and remove the unused `Consumer::weak()`. A reader now has no path to write access, direct or weak. Add `kio::shared`: a two-sided shared-state channel where a `Sender` and `Receiver` both mutate one lock-guarded value by design, with channel-style liveness (a wait resolves to `None` once the opposite side's handles are all gone, rather than blocking forever like a bare condvar). This is the right primitive for a reverse request queue, where the old code reached back through a read handle. Port the three reverse-queue sites in moq-net onto it: - origin `request_broadcast`: the dynamic request queue. - broadcast `Consumer::track`: split into a `Producer<()>`/`Consumer<()>` liveness channel (read-only for consumers) plus a `kio::shared` registry+queue, so the handler's atomic drain-and-register-track is preserved. - track fetch + subscriptions: reverse channels stored inside `TrackState` so no handle threading. Fetch carries a per-request result channel for rejection only (success routes through the cache), deleting `next_fetch`/`fetch_rejections`/the request id. Subscriptions register via a `pending_subs` queue the producer drains into its persistent list. Each site also deletes a manual `dynamic: usize` handler counter and its Clone/Drop bookkeeping (replaced by the `Receiver` count). moq-net's public API is unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
5ea4488 to
4055d3c
Compare
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
kio::Consumerdocuments itself as read-only but exposedwrite()andproduce()â^@^T mutable back-doors that also re-exposed theMut::deref_mut-marks-modified wake footgun (the one behind the wasm consume freeze) to external users. This deletes both, and closes the same hole inWeak.Weak: drop the write pathkio::Weakwas the same hole one level down: a single type carryingproduce,write, the producer-sideused/unused, and the consumer-sideconsume/read— all reachable fromConsumer::weak(). Soconsumer.weak().produce()(or.write()) bypassed the deletion entirely.Rename it to
ProducerWeak(only a producer mints one), dropwrite(upgrade viaproduce()to write), and remove the unusedConsumer::weak(). A consumer can no longer mint a weak at all, so there is no path to write access, direct or through a weak.New:
kio::sharedA two-sided shared-state channel. A
SenderandReceiverboth mutate one lock-guarded value by design (unlike the one-writerProducer/Consumerwatch channel), with channel-style liveness: a wait resolves toNoneonce the opposite side's handles are all gone, rather than blocking forever like a bare condvar. That's exactly the distinction a reverse queue needs (drain ends when senders vanish; enqueue reports when no handler exists).Ported the three reverse-queue sites in moq-net
request_broadcastâ^@^T the dynamic request queue.BroadcastConsumer::trackâ^@^T needed a two-channel split: aProducer<()>/Consumer<()>liveness channel (read-only for consumers, drivesclosed()) plus akio::sharedregistry+queue, so the handler's atomic drain-and-register-track survives.TrackStatewatch channel (the streaming hot path) untouched; moved the reverse bits intokio::sharedchannels stored insideTrackStateso nothing threads through the handle structs. Fetch carries a per-request result channel for rejection only (success routes through the cache), which deletesnext_fetch,fetch_rejections,clear_group_request_rejection, and the requestid. Subscriptions register via apending_subsqueue the producer drains into its persistent list.Each site also deletes a manual
dynamic: usizehandler counter and its Clone/Drop bookkeeping â^@^T that's now theReceivercount.Public API (kio, breaking â^F^R
dev)Consumer::write,Consumer::produce,Consumer::weak, andWeak(renamed toProducerWeak, itswritedropped).shared::{Sender, Receiver};ProducerWeak(replacingWeak);Producer::weak()returns it.moq-net's public surface is unchanged; only internal handle types and private state changed (TrackWeak/TrackDemandnow holdProducerWeak).Behavior note
A
request_broadcastfor an unannounced path with no live handler now resolvesUnroutableinstead ofDropped(no test coveredDropped, and it matches the already-existing pending path, which maps channel-close toUnroutable).Test plan
kio: 12 tests (incl. newsharedunit tests)moq-net: 410 lib + 4 doctests â^@^T all fetch/coalesce/accept-after-handler-dropped/subscription contract tests unchanged and greenhang(18),moq-relay(351),moq-mux(132) greencargo clippyclean;cargo check --workspace --all-targetscleanFollow-up considered, not done
kio's two channel families are now a bit inconsistent (
Producer::write/pollvsSender::lock/Receiver::poll_lock_when; the shared gate-poll uses&T+boolwhere the watch one uses&Ref+Poll<()>). Worth a naming/shape pass, but held out of this PR to keep it reviewable.ð^_¤^V Generated with Claude Code (Written by Claude Opus 4.8)