use std::task::{Context, Poll, Waker};
use std::net::{IpAddr, ToSocketAddrs};
use std::time::{Duration, Instant};
use std::thread::{self, Thread};
use std::sync::{Arc, Mutex};
use std::future::Future;
use std::pin::pin;
use crate::error::{Error, ErrorKind, Result, reason};
use crate::pool;
pub fn block_on_timeout<F: Future>(fut: F, timeout: Duration) -> Result<F::Output> {
struct ThreadWaker(Thread);
impl futures::task::ArcWake for ThreadWaker {
fn wake_by_ref(arc_self: &Arc<Self>) {
arc_self.0.unpark();
}
}
let mut fut = pin!(fut);
let waker = futures::task::waker(Arc::new(ThreadWaker(thread::current())));
let mut cx = Context::from_waker(&waker);
let deadline = Instant::now() + timeout;
loop {
if let Poll::Ready(output) = fut.as_mut().poll(&mut cx) {
return Ok(output);
}
let Some(remaining) = deadline.checked_duration_since(Instant::now()) else {
return Err(Error::new(ErrorKind::TimedOut)
.with_description(format!("Operation timed out after {timeout:?}")));
};
thread::park_timeout(remaining);
}
}
pub async fn resolve(host: &str) -> Result<Vec<IpAddr>> {
if let Ok(ip) = host.parse::<IpAddr>() {
return Ok(vec![ip]);
}
let owned_host = host.to_string();
pool::spawn(move || {
(owned_host.as_str(), 0).to_socket_addrs()
.map(|addrs| addrs.map(|addr| addr.ip()).collect::<Vec<_>>())
.map_err(|err| Error::new(ErrorKind::Reason(reason::API_CantResolveHost))
.with_description(format!("Failed to resolve the IP address of host {owned_host:?}"))
.with_source(Box::new(err)))
}).await
}
pub struct Slot<T> {
inner: Mutex<SlotInner<T>>,
}
struct SlotInner<T> {
pending: Option<T>,
ended: bool,
waker: Option<Waker>,
}
impl<T> Slot<T> {
pub fn new() -> Self {
Self {
inner: Mutex::new(SlotInner {
pending: None,
ended: false,
waker: None,
}),
}
}
pub fn push(&self, value: T) {
let waker = {
let mut inner = self.inner.lock().unwrap();
inner.pending = Some(value);
inner.waker.take()
};
if let Some(waker) = waker {
waker.wake();
}
}
pub fn end(&self) {
let waker = {
let mut inner = self.inner.lock().unwrap();
inner.ended = true;
inner.waker.take()
};
if let Some(waker) = waker {
waker.wake();
}
}
pub fn is_ended(&self) -> bool {
self.inner.lock().unwrap().ended
}
pub fn poll_take(&self, cx: &mut Context<'_>) -> Poll<Option<T>> {
let mut inner = self.inner.lock().unwrap();
match inner.pending.take() {
Some(value) => Poll::Ready(Some(value)),
None if inner.ended => Poll::Ready(None),
None => {
inner.waker = Some(cx.waker().clone());
Poll::Pending
}
}
}
}