use crate::courierust_h2::priority::Priority;
use alloc::collections::BTreeMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StreamState {
Idle,
Open,
HalfClosedLocal,
HalfClosedRemote,
Closed,
ReservedLocal,
ReservedRemote,
}
#[derive(Debug, Clone)]
pub struct Stream {
pub id: u32,
pub state: StreamState,
pub priority: Priority,
pub send_window: i64,
pub recv_window: i64,
pub send_buffered: usize,
pub send_done: bool,
pub recv_ended: bool,
pub recv_unreleased: i64,
pub headers_delivered: bool,
pub content_length: Option<u64>,
pub recv_body_len: u64,
pub body_expected: bool,
}
impl Stream {
pub fn new(id: u32, send_window: i64, recv_window: i64, priority: Priority) -> Self {
Self {
id,
state: StreamState::Idle,
priority,
send_window,
recv_window,
send_buffered: 0,
send_done: false,
recv_ended: false,
recv_unreleased: 0,
headers_delivered: false,
content_length: None,
recv_body_len: 0,
body_expected: true,
}
}
#[inline]
pub fn is_closed(&self) -> bool {
self.state == StreamState::Closed
}
#[inline]
pub fn can_recv(&self) -> bool {
matches!(self.state, StreamState::Open | StreamState::HalfClosedLocal) && !self.recv_ended
}
#[inline]
pub fn can_send(&self) -> bool {
matches!(
self.state,
StreamState::Open | StreamState::HalfClosedRemote
) && !self.send_done
}
}
#[derive(Default)]
pub struct StreamMap {
streams: BTreeMap<u32, Stream>,
next_client_id: u32,
#[allow(dead_code)]
next_server_id: u32,
last_peer_id: u32,
open_count: usize,
}
impl StreamMap {
pub fn new(client: bool) -> Self {
Self {
streams: BTreeMap::new(),
next_client_id: if client { 1 } else { 2 },
next_server_id: if client { 2 } else { 1 },
last_peer_id: 0,
open_count: 0,
}
}
#[inline]
pub fn get(&self, id: &u32) -> Option<&Stream> {
self.streams.get(id)
}
#[inline]
pub fn get_mut(&mut self, id: &u32) -> Option<&mut Stream> {
self.streams.get_mut(id)
}
pub fn insert(&mut self, s: Stream) {
if !s.is_closed() {
self.open_count += 1;
}
self.streams.insert(s.id, s);
}
pub fn remove(&mut self, id: &u32) -> Option<Stream> {
let s = self.streams.remove(id)?;
self.open_count = self.open_count.saturating_sub(1);
Some(s)
}
pub fn allocate_client_id(&mut self) -> Option<u32> {
let id = self.next_client_id;
if id > 0x7fff_ffff {
return None;
}
self.next_client_id = id.wrapping_add(2);
Some(id)
}
pub fn reserve_upgrade_stream(&mut self) {
if self.next_client_id == 1 {
self.next_client_id = 3;
}
}
#[inline]
pub fn peek_client_id(&self) -> u32 {
self.next_client_id
}
pub fn accept_peer_id(&mut self, id: u32) -> bool {
if id & 1 == 0 {
return false;
}
if id <= self.last_peer_id {
return false;
}
self.last_peer_id = id;
true
}
#[inline]
pub fn last_peer_id(&self) -> u32 {
self.last_peer_id
}
#[inline]
pub fn open_count(&self) -> usize {
self.open_count
}
pub fn iter(&self) -> impl Iterator<Item = &Stream> {
self.streams.values()
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Stream> {
self.streams.values_mut()
}
#[inline]
pub fn len(&self) -> usize {
self.streams.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.streams.is_empty()
}
#[inline]
pub fn contains(&self, id: &u32) -> bool {
self.streams.contains_key(id)
}
}