Skip to main content

trueno/brick/patterns/
stream_capacity.rs

1#![allow(missing_docs)]
2//! AWP-04: HTTP/2 Stream Capacity
3
4/// HTTP/2 flow control window state.
5///
6/// Tracks send and receive window sizes for stream-level flow control.
7#[derive(Debug, Clone)]
8pub struct StreamCapacity {
9    /// Connection-level send window
10    connection_send: i32,
11    /// Stream-level send window
12    stream_send: i32,
13    /// Receive window (how much we can receive)
14    receive_window: i32,
15    /// Initial window size
16    initial_window: i32,
17    /// Whether stream is blocked on flow control
18    is_blocked: bool,
19}
20
21impl StreamCapacity {
22    /// Default window size (HTTP/2 spec: 65535).
23    pub const DEFAULT_WINDOW: i32 = 65535;
24
25    /// Create with default windows.
26    pub fn new() -> Self {
27        Self {
28            connection_send: Self::DEFAULT_WINDOW,
29            stream_send: Self::DEFAULT_WINDOW,
30            receive_window: Self::DEFAULT_WINDOW,
31            initial_window: Self::DEFAULT_WINDOW,
32            is_blocked: false,
33        }
34    }
35
36    /// Create with custom initial window.
37    pub fn with_initial_window(initial: i32) -> Self {
38        Self {
39            connection_send: initial,
40            stream_send: initial,
41            receive_window: initial,
42            initial_window: initial,
43            is_blocked: false,
44        }
45    }
46
47    /// Reserve capacity for sending.
48    pub fn reserve_send(&mut self, bytes: i32) -> Result<(), FlowControlError> {
49        if bytes < 0 {
50            return Err(FlowControlError::NegativeReservation);
51        }
52
53        let available = self.available_send();
54        if bytes > available {
55            self.is_blocked = true;
56            return Err(FlowControlError::InsufficientCapacity { requested: bytes, available });
57        }
58
59        self.stream_send -= bytes;
60        self.connection_send -= bytes;
61        self.is_blocked = false;
62        Ok(())
63    }
64
65    /// Release send capacity (after WINDOW_UPDATE).
66    pub fn release_send(&mut self, bytes: i32) {
67        self.stream_send += bytes;
68        self.connection_send += bytes;
69        if self.available_send() > 0 {
70            self.is_blocked = false;
71        }
72    }
73
74    /// Consume receive window (data received).
75    pub fn consume_receive(&mut self, bytes: i32) {
76        self.receive_window -= bytes;
77    }
78
79    /// Replenish receive window (sending WINDOW_UPDATE).
80    pub fn replenish_receive(&mut self, bytes: i32) {
81        self.receive_window += bytes;
82    }
83
84    /// Get available send capacity.
85    #[must_use]
86    pub fn available_send(&self) -> i32 {
87        self.stream_send.min(self.connection_send).max(0)
88    }
89
90    /// Get available receive capacity.
91    #[must_use]
92    pub fn available_receive(&self) -> i32 {
93        self.receive_window.max(0)
94    }
95
96    /// Check if stream is blocked on flow control.
97    #[must_use]
98    pub fn is_blocked(&self) -> bool {
99        self.is_blocked
100    }
101
102    /// Check if receive window needs replenishment.
103    #[must_use]
104    pub fn needs_window_update(&self) -> bool {
105        self.receive_window < self.initial_window / 2
106    }
107}
108
109impl Default for StreamCapacity {
110    fn default() -> Self {
111        Self::new()
112    }
113}
114
115/// Flow control errors.
116#[derive(Debug, Clone, PartialEq, Eq)]
117pub enum FlowControlError {
118    /// Tried to reserve negative bytes
119    NegativeReservation,
120    /// Not enough capacity
121    InsufficientCapacity { requested: i32, available: i32 },
122}