The synchronous ChunkSource (flare.http.body) is a pull: each next returns the next chunk or None for EOF. That is exactly right for an in-process FIFO (e.g. SseChannel) but it can never wait -- it has no way to say "nothing yet, the bytes are coming on another fd." A streaming proxy whose chunks arrive on a UDS / pipe / eventfd needs that third state, or every front re-implements an epoll loop and a hand-rolled fd->client copy.

This module adds the missing state as a small, total API:

  • ChunkPoll -- a tri-state poll result. Exactly one of: a ready chunk, "pending, wake me on this fd", or EOF. The three states are constructed by named factories (ready / pending / eof) and read by predicates, so an illegal combination (a chunk and a wait fd) is unrepresentable.
  • AsyncChunkSource -- the async sibling of ChunkSource: one method, poll(cancel) -> ChunkPoll. Synchronous sources keep using ChunkSource; this is purely additive.
  • UpstreamChunkSource -- the concrete impl a streaming proxy needs: a single framed logical stream over a non-blocking connection. It composes the frame codec (FrameDemux) for parsing and reports pending(fd) on EAGAIN so the reactor parks instead of busy-polling.

Composition with the typed streaming surface

A handler drives an AsyncChunkSource with no bespoke reactor code, no file descriptors, and no per-connection bookkeeping -- attach the source and let the framework pump it::

def on_open(mut self, mut conn: StreamConn) raises:
    conn.attach_upstream(UpstreamChunkSource.connect(self.worker))

def on_upstream(mut self, mut conn: StreamConn) raises:
    conn.relay_upstream()              # drains ready chunks, EOF -> close

attach_upstream takes the source (it reads the fd to watch internally and owns the source for the connection's lifetime, closing it on teardown), and relay_upstream is the standard drain loop: pull ready chunks into the client with backpressure, request close on EOF, park on pending. A front that needs custom per-chunk handling can still drive the source directly via conn.upstream().poll(...).

The reactor calls on_upstream only when the attached fd is readable, so the pending branch is a genuine park, not a poll loop (no busy-poll between gaps). Watermark backpressure additionally gates the upstream read interest when the client is write-blocked.

Structs

struct ChunkPoll The result of one ``AsyncChunkSource.poll`` -- a total tri-state.
struct UpstreamChunkSource One framed logical stream over a non-blocking connection.

Traits

trait AsyncChunkSource A byte-chunk source whose chunks may arrive on a registered fd.
Detail Documentation

Structs

struct ChunkPoll §

struct ChunkPoll

The result of one ``AsyncChunkSource.poll`` -- a total tri-state.

Exactly one state holds:

  • ready: a chunk is available now (is_ready(); take it with take_chunk()).
  • pending: nothing yet; the caller should wait until wait_fd() is readable and poll again (is_pending()). No busy-poll.
  • eof: the stream is complete; no more chunks (is_eof()).

Built only through ready / pending / eof so a chunk can never coexist with a wait fd.

Methods

fn __init__ Internal: prefer the ``ready`` / ``pending`` / ``eof`` factories.
fn ready A chunk is available now.
fn pending Nothing yet; wake and re-poll when ``fd`` is readable.
fn eof The stream is complete.
fn is_ready True if a chunk is available now.
fn is_pending True if the source is waiting on ``wait_fd()``.
fn is_eof True if the stream is complete.
fn wait_fd The fd to wait on (valid only when ``is_pending()``; ``-1`` otherwise).
fn take_chunk Move the ready chunk out (valid only when ``is_ready()``; leaves the poll holding an empty chunk).
fn consume Collapse the ready/eof split into one move-out.

fn __init__ static §

def __init__(out self, _state: Int, var chunk: List[UInt8], fd: Int32)

Internal: prefer the ``ready`` / ``pending`` / ``eof`` factories.

Args
_state Int
chunk var List[UInt8]
fd Int32
self out Self
Returns
Self

fn ready static §

def ready(var chunk: List[UInt8]) -> Self

A chunk is available now.

Args
chunk var List[UInt8]
Returns
Self

fn pending static §

def pending(fd: Int32) -> Self

Nothing yet; wake and re-poll when ``fd`` is readable.

Args
fd Int32
Returns
Self

fn eof static §

def eof() -> Self

The stream is complete.

Returns
Self

fn is_ready §

def is_ready(self) -> Bool

True if a chunk is available now.

Args
self Self
Returns
Bool

fn is_pending §

def is_pending(self) -> Bool

True if the source is waiting on ``wait_fd()``.

Args
self Self
Returns
Bool

fn is_eof §

def is_eof(self) -> Bool

True if the stream is complete.

Args
self Self
Returns
Bool

fn wait_fd §

def wait_fd(self) -> c_int

The fd to wait on (valid only when ``is_pending()``; ``-1`` otherwise).

Args
self Self
Returns
c_int

fn take_chunk §

def take_chunk(mut self) -> List[UInt8]

Move the ready chunk out (valid only when ``is_ready()``; leaves the poll holding an empty chunk).

Args
self mut Self
Returns
List[UInt8]

fn consume §

def consume(mut self) -> Optional[List[UInt8]]

Collapse the ready/eof split into one move-out.

Returns Some(chunk) when a chunk is ready (moved out, as take_chunk) and None on EOF. Raises on pending: a pending poll must be parked on wait_fd() and re-polled, never consumed. This is the one-call form for callers that drain to EOF and have already handled the pending branch (the reactor only delivers an upstream edge when the fd is readable, so a relay loop sees only ready / eof).

Args
self mut Self
Returns
Optional[List[UInt8]]
Raises

May raise an exception.

struct UpstreamChunkSource §

One framed logical stream over a non-blocking connection.

Owns a UnixStream to a worker and reads frames for a single request_id off it. poll drains any buffered CHUNK frame, else does one non-blocking read: a completed CHUNK -> ready; a DONE / connection EOF -> eof; EAGAIN -> pending(fd) so the reactor waits on the fd instead of spinning; ERROR raises.

The frame parsing is the same FrameDemux the multiplexed FrameMux uses, so a worker can speak one wire shape to both the single-stream and multiplexed fronts.

ponytail: one source owns one connection (a dedicated framed link). The many-streams-over-one-connection case is the handler owning a FrameMux as shared state and driving it directly; a future FrameMux.open returning a lightweight per-stream handle is the multiplexed evolution (it needs a shared-mux reference the fixed trait method cannot carry in the current Mojo).

Fields

conn UnixStream The owned framed upstream connection (set non-blocking at init).
demux FrameDemux Frame reassembly for the inbound byte stream.
request_id UInt64 The single logical stream this source reads.

Methods

fn __init__ Adopt ``conn`` (switched to non-blocking) for ``request_id``.
fn connect Open a dedicated framed upstream over the UDS at ``path``.
fn fd The upstream fd to register / wait on (for ``attach_upstream``).
fn send_cancel Emit a CANCEL frame for this ``request_id`` upstream.
fn poll Drain a ready frame, else one non-blocking read; never blocks.

fn __init__ static §

def __init__(out self, var conn: UnixStream, request_id: UInt64 = UInt64(1))

Adopt ``conn`` (switched to non-blocking) for ``request_id``.

request_id defaults to 1 -- a dedicated single-stream link carries one logical stream, so the id is meaningful only when a front multiplexes several streams over one connection.

Args
conn var UnixStream
request_id UInt64 Default: UInt64(1)
self out Self
Returns
Self
Raises

May raise an exception.

fn connect static §

def connect(path: String, request_id: UInt64 = UInt64(1)) -> Self

Open a dedicated framed upstream over the UDS at ``path``.

The one-call convenience: dials the worker and adopts the connection, so a front never assembles a UnixStream by hand just to feed it here. Mirrors UnixStream.connect / TcpStream.connect.

var src = UpstreamChunkSource.connect("/run/backend.sock")
Args
path String
request_id UInt64 Default: UInt64(1)
Returns
Self
Raises

May raise an exception.

fn fd §

def fd(self) -> c_int

The upstream fd to register / wait on (for ``attach_upstream``).

Args
self Self
Returns
c_int

fn send_cancel §

def send_cancel(mut self)

Emit a CANCEL frame for this ``request_id`` upstream.

Tells the backend to stop producing tokens nobody will read -- e.g. the client disconnected mid-generation. Idempotent and best-effort framed (a 13-byte CANCEL fits one write); after this the source is EOF. Call it from a front's on_close when the connection's cancel is set, and poll calls it too when it observes cancellation on an upstream edge.

Args
self mut Self
Raises

May raise an exception.

fn poll §

def poll(mut self, cancel: Cancel) -> ChunkPoll

Drain a ready frame, else one non-blocking read; never blocks.

Args
self mut Self
cancel Cancel
Returns
ChunkPoll
Raises

May raise an exception.

Traits

trait AsyncChunkSource §

A byte-chunk source whose chunks may arrive on a registered fd.

The async sibling of ChunkSource: instead of a blocking pull, poll returns immediately with one of the three ChunkPoll states. A source that has data returns ready; a source still waiting for bytes on its fd returns pending(fd) (the caller parks the response on that fd); a finished source returns eof.

Implementors must not block in poll -- that is the whole point. The cancel token lets a source short-circuit on client FIN / deadline / drain.

Required Methods

fn __init__ Create a new instance of the value by moving the value of another.
fn poll Return the next chunk, a pending-on-fd signal, or EOF.

fn __init__ static §

def __init__(out self: _Self, *, deinit move: _Self)

Create a new instance of the value by moving the value of another.

Args
move deinit _Self

The value to move.

self out _Self
Returns
_Self

fn poll §

def poll(mut self: _Self, cancel: Cancel) -> ChunkPoll

Return the next chunk, a pending-on-fd signal, or EOF.

Args
self mut _Self
cancel Cancel

Per-request cancel token; poll it to abort early.

Returns
ChunkPoll

A ChunkPoll: ready / pending / eof.

Raises

Error: On an unrecoverable source error; the reactor closes the connection.