fastly 0.13.1

Fastly Compute API
Documentation
use fastly_shared::FastlyStatus;
use fastly_sys::fastly_async_io;
use std::time::Duration;

pub(crate) fn is_ready(handle: u32) -> Result<bool, FastlyStatus> {
    let mut ready_out = 0_u32;
    unsafe { fastly_async_io::is_ready(handle, &mut ready_out) }.result()?;
    Ok(ready_out != 0)
}

pub(crate) fn select(handles: &[u32]) -> Result<usize, FastlyStatus> {
    // `None` cannot time out, so the `Ok(None)` arm is unreachable here.
    Ok(select_timeout(handles, None)?.expect("untimed select returned a timeout"))
}

/// Block until one of `handles` is ready for I/O, returning the index of the ready handle.
///
/// If `timeout` is `Some` and elapses before any handle is ready, returns `Ok(None)`. A `timeout`
/// of `None` waits indefinitely.
pub(crate) fn select_timeout(
    handles: &[u32],
    timeout: Option<Duration>,
) -> Result<Option<usize>, FastlyStatus> {
    // The hostcall treats a `timeout_ms` of 0 as "no timeout", and signals an elapsed timeout by
    // returning `u32::MAX` as the index. Saturate the millisecond conversion so a very long
    // `Duration` clamps to the largest expressible timeout rather than wrapping to 0 (no timeout).
    let timeout_ms = match timeout {
        Some(d) => d.as_millis().try_into().unwrap_or(u32::MAX).max(1),
        None => 0,
    };
    let mut done_index = 0_u32;
    let status = unsafe {
        fastly_async_io::select(handles.as_ptr(), handles.len(), timeout_ms, &mut done_index)
    };
    status.result()?;
    if done_index == u32::MAX {
        Ok(None)
    } else {
        Ok(Some(done_index as usize))
    }
}