Skip to content

[AsyncStremaing] Introduce a MultiProducerSingleConsumerChannel and a duplex#425

Draft
FranzBusch wants to merge 4 commits into
apple:mainfrom
FranzBusch:fb-async-streaming-mpsc
Draft

[AsyncStremaing] Introduce a MultiProducerSingleConsumerChannel and a duplex#425
FranzBusch wants to merge 4 commits into
apple:mainfrom
FranzBusch:fb-async-streaming-mpsc

Conversation

@FranzBusch
Copy link
Copy Markdown
Member

Motivation

When working with async reader and writer one often needs "root" readers and writers. A multi producer single consumer channel can provide the foundation for such a reader and writer pair. Furthermore, developers often want a connected duplex pair of readers and writers for testing or in-memory purposes.

Modifications

This PR brings over the existing MultiProducerSingleConsumerAsyncChannel with adaptions to handle reader and writer like interfaces and leverage unstable types such as UniqueDeque. Furthermore, this PR also brings a DuplexStream that sets up two connected pairs of MPSC channels.

I intentionally copied and modified the MPSC implementation since I don't want to carry #if conditionals in an existing used implementation. Once we stabilize this module we can evaluate how to best proceed.

Result

Makes it easier for developers to work with readers and writers. In particular, makes testing a lot easier.

## Motivation

Real transports deliver structured data alongside end-of-stream and need to fuse the last write with the close. HTTP trailers and gRPC status are the obvious cases. Neither can be expressed by an empty-buffer terminator, and both lose H2/H3/QUIC's DATA+END_STREAM coalescing without a fused call.

## Modification

Adds `FinalElement: ~Copyable = Void` as a primary associated type on all four protocols. `AsyncReader` delivers it via a `consuming FinalElement?` closure parameter; `CallerAsyncReader` returns it. Both writers gain a consuming `finish` carrying the last chunk and the payload in one call.

`forEachBuffer`, `collect`, and the `pipe` variants thread the payload through. `collect` becomes consuming and gains a `Void`-final overload returning just the result.

Adds an "Alternatives considered" entry covering what would break without
this: HTTP body, gRPC, and fused close on H2/H3/QUIC.

## Result

The four protocols can back HTTP body, gRPC streaming, and similar shapes without giving up the fused close. Default `Void` keeps simple conformers unchanged; `Never` marks infinite streams. Custom and `~Copyable` payloads work end to end.
## Motivation

It is quite common to have one type of writer and wanting to adapt to the other type of writer.

## Modifications

This PR adds two adapters into either direction between the writers to make conversion seamless.

## Result

It is easy to go from one type of writer to the other type.
@FranzBusch FranzBusch force-pushed the fb-async-streaming-mpsc branch from 3b79956 to e02ca0f Compare May 26, 2026 14:06
@FranzBusch FranzBusch force-pushed the fb-async-streaming-mpsc branch from e02ca0f to b793e0e Compare May 27, 2026 14:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant