use fastly_sys::fastly_http_req::SendErrorDetail;
use super::PendingRequest;
use crate::abi;
use crate::handle::{BodyHandle, ResponseHandle};
use crate::http::request::SendErrorCause;
#[derive(Debug, Eq, Hash, PartialEq)]
#[repr(transparent)]
pub struct PendingRequestHandle {
handle: u32,
}
impl From<PendingRequest> for PendingRequestHandle {
fn from(pr: PendingRequest) -> Self {
pr.handle
}
}
impl PendingRequestHandle {
pub(crate) const INVALID: Self = Self {
handle: fastly_shared::INVALID_PENDING_REQUEST_HANDLE,
};
pub(crate) fn is_invalid(&self) -> bool {
self == &Self::INVALID
}
#[doc(hidden)]
pub fn from_u32(handle: u32) -> Self {
Self { handle }
}
#[cfg_attr(
not(target_env = "p1"),
deprecated(
since = "0.11.6",
note = "This code will need to be updated for wasip2."
)
)]
pub fn as_u32(&self) -> u32 {
self.handle
}
pub(crate) fn copy(&self) -> Self {
Self {
handle: self.handle,
}
}
pub(crate) fn as_u32_mut(&mut self) -> &mut u32 {
&mut self.handle
}
pub fn poll(self) -> PollHandleResult {
let mut is_done = -1;
let mut resp_handle = ResponseHandle::INVALID;
let mut body_handle = BodyHandle::INVALID;
let mut error_detail = SendErrorDetail::uninitialized_all();
let status = unsafe {
abi::fastly_http_req::pending_req_poll_v2(
self.as_u32(),
&mut error_detail,
&mut is_done,
resp_handle.as_u32_mut(),
body_handle.as_u32_mut(),
)
};
if status.is_err() {
return PollHandleResult::Done(Err(SendErrorCause::detail_and_status(
error_detail,
Some(status),
)
.expect_err("status.is_err()")));
}
if is_done < 0 || is_done > 1 {
panic!("fastly_http_req_pending_req_poll internal error");
}
let is_done = is_done != 0;
if !is_done {
return PollHandleResult::Pending(self);
}
if is_done && (resp_handle.is_invalid() || body_handle.is_invalid()) {
panic!("fastly_http_req_pending_req_poll internal error");
} else {
PollHandleResult::Done(Ok((resp_handle, body_handle)))
}
}
pub fn wait(self) -> Result<(ResponseHandle, BodyHandle), SendErrorCause> {
let mut resp_handle = ResponseHandle::INVALID;
let mut body_handle = BodyHandle::INVALID;
let mut error_detail = SendErrorDetail::uninitialized_all();
let status = unsafe {
abi::fastly_http_req::pending_req_wait_v2(
self.as_u32(),
&mut error_detail,
resp_handle.as_u32_mut(),
body_handle.as_u32_mut(),
)
};
SendErrorCause::detail_and_status(error_detail, Some(status))?;
if resp_handle.is_invalid() || body_handle.is_invalid() {
panic!("fastly_http_req::pending_req_wait returned invalid handles");
}
Ok((resp_handle, body_handle))
}
}
pub enum PollHandleResult {
Pending(PendingRequestHandle),
Done(Result<(ResponseHandle, BodyHandle), SendErrorCause>),
}
pub fn select_handles<I>(
pending_reqs: I,
) -> (
Result<(ResponseHandle, BodyHandle), SendErrorCause>,
usize,
Vec<PendingRequestHandle>,
)
where
I: IntoIterator<Item = PendingRequestHandle>,
{
let mut prs = pending_reqs
.into_iter()
.map(|pr| pr.as_u32())
.collect::<Vec<u32>>();
if prs.is_empty() || prs.len() > fastly_shared::MAX_PENDING_REQS as usize {
panic!(
"the number of selected handles must be at least 1, and less than {}",
fastly_shared::MAX_PENDING_REQS
);
}
let mut done_index = -1;
let mut resp_handle = ResponseHandle::INVALID;
let mut body_handle = BodyHandle::INVALID;
let mut error_detail = SendErrorDetail::uninitialized_all();
let status = unsafe {
abi::fastly_http_req::pending_req_select_v2(
prs.as_ptr(),
prs.len(),
&mut error_detail,
&mut done_index,
resp_handle.as_u32_mut(),
body_handle.as_u32_mut(),
)
};
if status.is_err() || done_index < 0 {
panic!("fastly_http_req_pending_req_select internal error: {error_detail:?}");
}
let done_index = done_index
.try_into()
.expect("fastly_http_req_pending_req_select returned an invalid index");
prs.swap_remove(done_index);
let res = if resp_handle.is_invalid() || body_handle.is_invalid() {
Err(SendErrorCause::detail_and_status(error_detail, None)
.expect_err("invalid handles but valid status"))
} else {
Ok((resp_handle, body_handle))
};
(
res,
done_index,
prs.into_iter()
.map(PendingRequestHandle::from_u32)
.collect(),
)
}