use std::borrow::Cow;
use std::ops::Range;
use std::sync::{Arc, Mutex};
use std::task::Waker;
use crate::error::WinHttpError;
bitflags::bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct RequestState: u16 {
const Initial = 0b0000_0000_0000_0001;
const HeadersSent = 0b0000_0000_0000_0010;
const WriteComplete = 0b0000_0000_0000_0100;
const HeadersReceived = 0b0000_0000_0000_1000;
const QueryingData = 0b0000_0000_0001_0000;
const DataAvailable = 0b0000_0000_0010_0000;
const Reading = 0b0000_0000_0100_0000;
const Completed = 0b0000_0000_1000_0000;
}
}
pub(crate) struct RequestContextInner {
pub(crate) state: RequestState,
pub(crate) waker: Waker,
pub(crate) error: Option<WinHttpError>,
pub(crate) buffer: Cow<'static, [u8]>,
pub(crate) buffer_range: Range<usize>,
}
pub(crate) struct RequestContext {
pub(crate) inner: Mutex<RequestContextInner>,
}
impl RequestContext {
pub(crate) fn new() -> Arc<Self> {
Arc::new(Self {
inner: Mutex::new(RequestContextInner {
state: RequestState::Initial,
waker: futures_task::noop_waker(), error: None,
buffer: Default::default(),
buffer_range: 0..0,
}),
})
}
#[allow(dead_code)]
pub(crate) fn set_state_no_wake(&self, state: RequestState) {
self.inner.lock().unwrap().state = state;
}
pub(crate) fn transition_state(&self, to: RequestState) {
let mut inner = self.inner.lock().unwrap();
inner.state = to;
inner.waker.wake_by_ref();
}
pub(crate) fn set_send_complete(&self) {
let mut inner = self.inner.lock().unwrap();
inner.buffer = Cow::Borrowed(&[]);
inner.state = RequestState::HeadersSent;
inner.waker.wake_by_ref();
}
pub(crate) fn set_write_complete(&self, bytes_written: usize) {
let mut inner = self.inner.lock().unwrap();
inner.buffer_range.end += bytes_written;
inner.state = RequestState::WriteComplete;
inner.waker.wake_by_ref();
}
pub(crate) unsafe fn set_read_complete(&self, ptr: *const u8, bytes_read: usize) {
let mut inner = self.inner.lock().unwrap();
if bytes_read == 0 {
inner.state = RequestState::Completed
} else {
let new_start = ptr as usize - inner.buffer.as_ptr() as usize;
inner.buffer_range = new_start..(new_start + bytes_read);
inner.state = RequestState::HeadersReceived
}
inner.waker.wake_by_ref();
}
pub(crate) fn set_error(&self, error: WinHttpError) {
let mut inner = self.inner.lock().unwrap();
inner.error = Some(error);
inner.waker.wake_by_ref();
}
pub(crate) fn take_error(&self) -> Option<WinHttpError> {
self.inner.lock().unwrap().error.take()
}
pub(crate) fn set_body(&self, body: Cow<'static, [u8]>) {
self.inner.lock().unwrap().buffer = body;
}
pub(crate) fn set_write_buffer(&self, buffer: Cow<'static, [u8]>) {
let mut inner = self.inner.lock().unwrap();
inner.buffer = buffer;
inner.buffer_range = 0..0;
}
pub(crate) fn prepare_for_writing(&self) -> *const u8 {
let mut inner = self.inner.lock().unwrap();
inner.state = RequestState::HeadersSent;
inner.buffer_range = 0..0;
inner.buffer.as_ptr()
}
pub(crate) fn take_write_buffer(&self) -> Cow<'_, [u8]> {
let mut inner = self.inner.lock().unwrap();
inner.buffer_range = 0..0;
std::mem::take(&mut inner.buffer)
}
pub(crate) fn get_body_ptr(&self) -> (*const u8, usize) {
let inner = self.inner.lock().unwrap();
(inner.buffer.as_ptr(), inner.buffer.len())
}
pub(crate) fn set_bytes_available(&self, bytes: u32) {
self.inner.lock().unwrap().buffer_range = 0..bytes as usize;
}
}