use bytes::Bytes;
use std::pin::Pin;
use futures::Stream;
#[cfg(not(all(feature = "wasm", target_arch = "wasm32")))]
pub trait WasmCompatSend: Send {}
#[cfg(all(feature = "wasm", target_arch = "wasm32"))]
pub trait WasmCompatSend {}
#[cfg(not(all(feature = "wasm", target_arch = "wasm32")))]
impl<T> WasmCompatSend for T where T: Send {}
#[cfg(all(feature = "wasm", target_arch = "wasm32"))]
impl<T> WasmCompatSend for T {}
#[cfg(not(all(feature = "wasm", target_arch = "wasm32")))]
pub trait WasmCompatSendStream:
Stream<Item = Result<Bytes, crate::http_client::Error>> + Send
{
type InnerItem: Send;
}
#[cfg(all(feature = "wasm", target_arch = "wasm32"))]
pub trait WasmCompatSendStream: Stream<Item = Result<Bytes, crate::http_client::Error>> {
type InnerItem;
}
#[cfg(not(all(feature = "wasm", target_arch = "wasm32")))]
impl<T> WasmCompatSendStream for T
where
T: Stream<Item = Result<Bytes, crate::http_client::Error>> + Send,
{
type InnerItem = Result<Bytes, crate::http_client::Error>;
}
#[cfg(all(feature = "wasm", target_arch = "wasm32"))]
impl<T> WasmCompatSendStream for T
where
T: Stream<Item = Result<Bytes, crate::http_client::Error>>,
{
type InnerItem = Result<Bytes, crate::http_client::Error>;
}
#[cfg(not(all(feature = "wasm", target_arch = "wasm32")))]
pub trait WasmCompatSync: Sync {}
#[cfg(all(feature = "wasm", target_arch = "wasm32"))]
pub trait WasmCompatSync {}
#[cfg(not(all(feature = "wasm", target_arch = "wasm32")))]
impl<T> WasmCompatSync for T where T: Sync {}
#[cfg(all(feature = "wasm", target_arch = "wasm32"))]
impl<T> WasmCompatSync for T {}
#[cfg(not(all(feature = "wasm", target_arch = "wasm32")))]
pub type WasmBoxedFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
#[cfg(all(feature = "wasm", target_arch = "wasm32"))]
pub type WasmBoxedFuture<'a, T> = Pin<Box<dyn Future<Output = T> + 'a>>;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Elapsed;
impl std::fmt::Display for Elapsed {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("future timed out")
}
}
impl std::error::Error for Elapsed {}
pub async fn timeout<F>(duration: std::time::Duration, future: F) -> Result<F::Output, Elapsed>
where
F: Future,
{
use futures::future::{Either, select};
let delay = futures_timer::Delay::new(duration);
futures::pin_mut!(future);
futures::pin_mut!(delay);
match select(future, delay).await {
Either::Left((output, _)) => Ok(output),
Either::Right(((), _)) => Err(Elapsed),
}
}
#[macro_export]
macro_rules! if_wasm {
($($tokens:tt)*) => {
#[cfg(all(feature = "wasm", target_arch = "wasm32"))]
$($tokens)*
};
}
#[macro_export]
macro_rules! if_not_wasm {
($($tokens:tt)*) => {
#[cfg(not(all(feature = "wasm", target_arch = "wasm32")))]
$($tokens)*
};
}
#[cfg(test)]
mod tests {
use super::{Elapsed, timeout};
use std::time::Duration;
#[tokio::test]
async fn timeout_returns_ok_for_a_future_that_completes_in_time() {
let result = timeout(Duration::from_secs(5), async { 42 }).await;
assert_eq!(result, Ok(42));
}
#[tokio::test]
async fn timeout_returns_elapsed_for_a_future_that_never_completes() {
let result = timeout(Duration::from_millis(20), std::future::pending::<()>()).await;
assert_eq!(result, Err(Elapsed));
}
#[tokio::test]
async fn timeout_zero_duration_still_polls_a_ready_future_once() {
let result = timeout(Duration::ZERO, async { 7 }).await;
assert_eq!(result, Ok(7));
}
}