// The send side of QUIC flow control across a connection (RFC 9000 §4.1): a sender is bounded
// on each stream by two windows at once — the connection-wide limit the peer advertised with
// MAX_DATA, and that stream's limit from MAX_STREAM_DATA — and may send only the smaller of the
// two, debiting both. This composes the per-window `SendFlow` accounting into the connection
// state a sender consults before putting stream data on the wire; it holds only counters.
///|
/// The send-side flow control for a whole connection: the connection-wide window and a window
/// per stream, each created at the peer's initial maximum on first use.
pub struct QuicSendFlow {
connection : SendFlow
streams : Map[UInt64, SendFlow]
initial_max_stream_data : UInt64
}
///|
/// A fresh send-flow state at the peer's initial connection and per-stream maxima.
pub fn QuicSendFlow::new(
initial_max_data : UInt64,
initial_max_stream_data : UInt64,
) -> QuicSendFlow {
{
connection: SendFlow::new(initial_max_data),
streams: Map([]),
initial_max_stream_data,
}
}
///|
/// The send window for stream `id`, created at the initial per-stream maximum on first use.
fn QuicSendFlow::stream_flow(self : QuicSendFlow, id : UInt64) -> SendFlow {
match self.streams.get(id) {
Some(s) => s
None => {
let s = SendFlow::new(self.initial_max_stream_data)
self.streams[id] = s
s
}
}
}
///|
/// The bytes that may be sent on stream `id` right now: the smaller of the connection-wide and
/// the stream's available windows (RFC 9000 §4.1).
pub fn QuicSendFlow::stream_window(self : QuicSendFlow, id : UInt64) -> UInt64 {
let c = self.connection.available()
let s = self.stream_flow(id).available()
if c < s {
c
} else {
s
}
}
///|
/// Account for sending `n` bytes on stream `id`, debiting both the stream and the connection
/// window. Raises if either window would be exceeded — checked before debiting, so neither is
/// left partially charged on failure (RFC 9000 §4.1).
pub fn QuicSendFlow::record_stream_sent(
self : QuicSendFlow,
id : UInt64,
n : UInt64,
) -> Unit raise FlowError {
let s = self.stream_flow(id)
if s.available() < n {
raise FlowError("send would exceed the stream flow-control limit")
}
if self.connection.available() < n {
raise FlowError("send would exceed the connection flow-control limit")
}
s.record_sent(n)
self.connection.record_sent(n)
}
///|
/// Raise the connection-wide limit from a MAX_DATA frame.
pub fn QuicSendFlow::on_max_data(self : QuicSendFlow, new_max : UInt64) -> Unit {
self.connection.update_limit(new_max)
}
///|
/// Raise stream `id`'s limit from a MAX_STREAM_DATA frame.
pub fn QuicSendFlow::on_max_stream_data(
self : QuicSendFlow,
id : UInt64,
new_max : UInt64,
) -> Unit {
self.stream_flow(id).update_limit(new_max)
}
///|
/// The connection-wide bytes still sendable across all streams.
pub fn QuicSendFlow::connection_available(self : QuicSendFlow) -> UInt64 {
self.connection.available()
}