use std::collections::hash_map::Entry;
use std::collections::hash_map::OccupiedEntry;
use std::collections::HashMap;
use super::stream::HttpStreamCommand;
use super::stream::HttpStreamCommon;
use super::stream::HttpStreamStateSnapshot;
use super::types::Types;
use crate::common::hash_set_shallow_clone::HashSetShallowClone;
use crate::common::hash_set_shallow_clone::HashSetShallowCloneItems;
use crate::common::init_where::InitWhere;
use crate::common::stream::DroppedData;
use crate::data_or_headers::DataOrHeaders;
use crate::data_or_headers_with_flag::DataOrHeadersWithFlag;
use crate::solicit::session::StreamState;
use crate::solicit::stream_id::StreamId;
use crate::solicit::window_size::WindowSize;
use crate::{error, ErrorCode};
#[derive(Default)]
pub(crate) struct StreamMap<T: Types> {
map: HashMap<StreamId, HttpStreamCommon<T>>,
writable_streams: HashSetShallowClone<StreamId>,
}
pub(crate) struct HttpStreamRef<'m, T: Types + 'm> {
entry: OccupiedEntry<'m, StreamId, HttpStreamCommon<T>>,
writable_streams: &'m mut HashSetShallowClone<StreamId>,
}
impl<T: Types> StreamMap<T> {
pub fn new() -> StreamMap<T> {
StreamMap {
map: HashMap::new(),
writable_streams: HashSetShallowClone::new(),
}
}
pub fn insert(&mut self, id: StreamId, stream: HttpStreamCommon<T>) -> HttpStreamRef<T> {
match self.map.entry(id) {
Entry::Occupied(_) => panic!("stream to insert that already exists: {}", id),
Entry::Vacant(v) => v.insert(stream),
};
let mut stream = self.get_mut(id).unwrap();
stream.sync_writable();
stream
}
pub fn get_mut(&mut self, id: StreamId) -> Option<HttpStreamRef<T>> {
match self.map.entry(id) {
Entry::Occupied(e) => Some(HttpStreamRef {
entry: e,
writable_streams: &mut self.writable_streams,
}),
Entry::Vacant(_) => None,
}
}
pub fn remove_stream(&mut self, id: StreamId) {
if let Some(r) = self.get_mut(id) {
r.remove();
}
}
pub fn get_stream_state(&self, id: StreamId) -> Option<StreamState> {
self.map.get(&id).map(|s| s.state)
}
fn sync_is_writable(&mut self) {
self.writable_streams = self
.map
.iter()
.filter_map(|(&stream_id, stream)| {
if stream.is_writable() {
Some(stream_id)
} else {
None
}
})
.collect()
}
pub fn add_out_window(&mut self, delta: i32) {
for (_, s) in &mut self.map {
s.out_window_size.try_add(delta).unwrap();
s.pump_out_window.increase(delta as isize);
}
self.sync_is_writable();
}
pub fn remove_local_streams_with_id_gt(
&mut self,
id: StreamId,
) -> Vec<(StreamId, HttpStreamCommon<T>)> {
let stream_ids: Vec<StreamId> = self
.map
.keys()
.cloned()
.filter(|&s| s > id && T::init_where(s) == InitWhere::Locally)
.collect();
let mut r = Vec::new();
for r_id in stream_ids {
r.push((r_id, self.map.remove(&r_id).unwrap()))
}
r
}
pub fn is_empty(&self) -> bool {
self.map.is_empty()
}
pub fn _stream_ids(&self) -> Vec<StreamId> {
self.map.keys().cloned().collect()
}
pub fn writable_stream_ids(&mut self) -> HashSetShallowCloneItems<StreamId> {
self.writable_streams.items()
}
pub fn snapshot(&self) -> HashMap<StreamId, HttpStreamStateSnapshot> {
self.map.iter().map(|(&k, s)| (k, s.snapshot())).collect()
}
pub fn conn_died<F>(mut self, error: F)
where
F: Fn() -> error::Error,
{
for (_, s) in self.map.drain() {
s.conn_died(error());
}
}
}
impl<'m, T: Types + 'm> HttpStreamRef<'m, T> {
pub fn stream(&mut self) -> &mut HttpStreamCommon<T> {
self.entry.get_mut()
}
pub fn stream_ref(&self) -> &HttpStreamCommon<T> {
self.entry.get()
}
pub fn id(&self) -> StreamId {
*self.entry.key()
}
pub fn _into_stream(self) -> &'m mut HttpStreamCommon<T> {
self.entry.into_mut()
}
fn remove(self) {
let stream_id = self.id();
debug!("removing stream {}", stream_id);
self.writable_streams.remove(&stream_id);
self.entry.remove();
}
fn is_writable(&self) -> bool {
self.writable_streams.get(&self.id()).is_some()
}
fn check_state(&self) {
debug_assert_eq!(
self.stream_ref().is_writable(),
self.is_writable(),
"for stream {}",
self.id()
);
}
fn mark_writable(&mut self, writable: bool) {
let stream_id = self.id();
if writable {
self.writable_streams.insert(stream_id);
} else {
self.writable_streams.remove(&stream_id);
}
}
fn sync_writable(&mut self) {
let writable = self.stream().is_writable();
self.mark_writable(writable);
}
pub fn remove_if_closed(mut self) -> Option<Self> {
if self.stream().state == StreamState::Closed {
self.remove();
None
} else {
Some(self)
}
}
pub fn pop_outg_maybe_remove(
mut self,
conn_out_window_size: &mut WindowSize,
) -> (Option<HttpStreamCommand>, Option<Self>) {
self.check_state();
let r = self.stream().pop_outg(conn_out_window_size);
self.sync_writable();
let stream = self.remove_if_closed();
(r, stream)
}
pub fn rst_received_remove(mut self, error_code: ErrorCode) -> DroppedData {
let r = self.stream().rst_recvd(error_code);
self.remove();
r
}
pub fn try_increase_window_size(&mut self, increment: u32) -> Result<(), ()> {
let old_window_size = self.stream().out_window_size.size();
self.stream().out_window_size.try_increase(increment)?;
let new_window_size = self.stream().out_window_size.size();
debug!(
"stream {} out window size change: {} -> {}",
self.id(),
old_window_size,
new_window_size
);
self.sync_writable();
Ok(())
}
pub fn push_back(&mut self, frame: DataOrHeaders) {
self.stream().outgoing.push_back(frame);
self.sync_writable();
}
pub fn push_back_part(&mut self, part: DataOrHeadersWithFlag) {
self.stream().outgoing.push_back_part(part);
self.sync_writable();
}
pub fn close_outgoing(&mut self, error_core: ErrorCode) {
self.stream().outgoing.close(error_core);
self.sync_writable();
}
pub fn close_remote(mut self) {
self.stream().close_remote();
self.remove_if_closed();
}
}