use crate::{
collection::ArrayVectorU8,
http::{HttpRecvParams, u31::U31},
http2::{
Http2Error, Http2ErrorCode, http_send_params::HttpSendParams,
window_update_frame::WindowUpdateFrame,
},
};
#[derive(Clone, Copy, Debug)]
pub struct Window {
available: i32,
}
impl Window {
pub(crate) const fn new(available: i32) -> Self {
Self { available }
}
pub(crate) const fn available(self) -> i32 {
self.available
}
pub(crate) const fn deposit(&mut self, stream_id: Option<U31>, value: i32) -> crate::Result<()> {
'block: {
let Some(added) = self.available.checked_add(value) else {
break 'block;
};
if added > U31::MAX.i32() {
break 'block;
}
self.available = added;
return Ok(());
};
if let Some(elem) = stream_id {
Err(crate::Error::Http2FlowControlError(Http2Error::InvalidWindowUpdateSize, elem.u32()))
} else {
Err(crate::Error::Http2ErrorGoAway(
Http2ErrorCode::FlowControlError,
Http2Error::InvalidWindowUpdateSize,
))
}
}
pub(crate) const fn withdrawn(
&mut self,
stream_id: Option<U31>,
value: i32,
) -> crate::Result<()> {
let Some(diff) = self.available.checked_sub(value) else {
return if let Some(elem) = stream_id {
Err(crate::Error::Http2FlowControlError(Http2Error::InvalidWindowUpdateSize, elem.u32()))
} else {
Err(crate::Error::Http2ErrorGoAway(
Http2ErrorCode::FlowControlError,
Http2Error::InvalidWindowUpdateSize,
))
};
};
self.available = diff;
Ok(())
}
const fn is_invalid(self) -> bool {
self.available <= 0
}
}
#[derive(Clone, Copy, Debug)]
pub struct Windows {
recv: Window,
send: Window,
}
impl Windows {
pub(crate) const fn initial(hp: &HttpRecvParams, hps: &HttpSendParams) -> Self {
Self {
recv: Window::new(U31::from_u32(hp.initial_window_len()).i32()),
send: Window::new(hps.initial_window_len.i32()),
}
}
pub(crate) const fn new() -> Self {
Self { recv: Window::new(0), send: Window::new(0) }
}
pub const fn recv(&self) -> Window {
self.recv
}
pub const fn send(&self) -> Window {
self.send
}
pub(crate) const fn send_mut(&mut self) -> &mut Window {
&mut self.send
}
}
#[derive(Debug)]
pub(crate) struct WindowsPair<'any> {
pub(crate) conn: &'any mut Windows,
pub(crate) stream: &'any mut Windows,
}
impl<'any> WindowsPair<'any> {
pub(crate) const fn new(conn: &'any mut Windows, stream: &'any mut Windows) -> Self {
Self { conn, stream }
}
pub(crate) const fn available_send(&self) -> i32 {
self.stream.send.available()
}
pub(crate) fn withdrawn_recv(
&mut self,
hp: &HttpRecvParams,
stream_id: U31,
value: U31,
) -> crate::Result<ArrayVectorU8<u8, 26>> {
let iwl = U31::from_u32(hp.initial_window_len()).i32();
self.conn.recv.withdrawn(None, value.i32())?;
self.stream.recv.withdrawn(Some(stream_id), value.i32())?;
let mut frame = ArrayVectorU8::new();
match (self.conn.recv.is_invalid(), self.stream.recv.is_invalid()) {
(false, false) => {}
(false, true) => {
let stream_value = self.stream.recv.available().abs().wrapping_add(iwl);
self.stream.recv.deposit(Some(stream_id), stream_value)?;
let wuf = WindowUpdateFrame::new(U31::from_i32(stream_value), stream_id)?;
let _rslt = frame.extend_from_copyable_slice(&wuf.bytes());
}
(true, false) => {
let conn_value = self.conn.recv.available().abs().wrapping_add(iwl);
self.conn.recv.deposit(Some(stream_id), conn_value)?;
let wuf = WindowUpdateFrame::new(U31::from_i32(conn_value), U31::ZERO)?;
let _rslt = frame.extend_from_copyable_slice(&wuf.bytes());
}
(true, true) => {
let conn_value = self.conn.recv.available().abs().wrapping_add(iwl);
let stream_value = self.stream.recv.available().abs().wrapping_add(iwl);
self.conn.recv.deposit(Some(stream_id), conn_value)?;
self.stream.recv.deposit(Some(stream_id), stream_value)?;
let array0 = WindowUpdateFrame::new(U31::from_i32(conn_value), U31::ZERO)?.bytes();
let array1 = WindowUpdateFrame::new(U31::from_i32(stream_value), stream_id)?.bytes();
let [b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12] = array0;
let [b13, b14, b15, b16, b17, b18, b19, b20, b21, b22, b23, b24, b25] = array1;
frame.extend_from_copyable_slice(&[
b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16, b17, b18, b19,
b20, b21, b22, b23, b24, b25,
])?;
}
}
Ok(frame)
}
pub(crate) fn withdrawn_send(&mut self, stream_id: Option<U31>, value: U31) -> crate::Result<()> {
self.conn.send.withdrawn(None, value.i32())?;
self.stream.send.withdrawn(stream_id, value.i32())?;
Ok(())
}
}