use std::any::Any;
use std::cell::RefCell;
use std::collections::VecDeque;
use std::pin::Pin;
use std::sync::Arc;
use ahash::{HashMap, HashMapExt};
use parking_lot::Mutex;
use tokio::sync::oneshot;
use std::future::Future;
use std::rc::Rc;
pub type BoxFuture<T> = Pin<Box<dyn Future<Output = T> + Send>>;
pub type AnyResult = Arc<dyn Any + Send + Sync>;
type ResultReceiver = oneshot::Receiver<AnyResult>;
pub type FutureStorage = Arc<Mutex<VecDeque<(FutureHandle, BoxFuture<()>)>>>;
pub type Throwable<T> = Rc<RefCell<T>>;
#[derive(Clone, Debug)]
pub enum FutureStatus {
NotPolled,
CurrentlyPolling,
Completed,
}
#[derive(Default, Copy, Clone, Eq, Hash, PartialEq, Debug)]
pub struct FutureHandle {
pub id: u64,
}
struct HandleEntry {
receiver: Option<ResultReceiver>,
status: FutureStatus,
cached_result: Option<AnyResult>,
}
pub struct FutureQueue {
queued: FutureStorage,
handle_registry: Arc<Mutex<HashMap<FutureHandle, HandleEntry>>>,
next_id: Arc<Mutex<u64>>,
}
impl FutureQueue {
pub fn new() -> Self {
Self {
queued: Arc::new(Mutex::new(VecDeque::new())),
handle_registry: Arc::new(Mutex::new(HashMap::new())),
next_id: Arc::new(Mutex::new(0)),
}
}
pub fn push<F, T>(&self, future: F) -> FutureHandle
where
F: Future<Output = T> + Send + 'static,
T: Send + Sync + 'static,
{
let mut next_id = self.next_id.lock();
let id = *next_id;
*next_id += 1;
let id = FutureHandle { id };
let (sender, receiver) = oneshot::channel::<AnyResult>();
let entry = HandleEntry {
receiver: Some(receiver),
status: FutureStatus::NotPolled,
cached_result: None,
};
self.handle_registry.lock().insert(id, entry);
let wrapped_future: Pin<Box<dyn Future<Output = ()> + Send>> = Box::pin(async move {
log("Starting future execution");
let result = future.await;
let boxed_result: AnyResult = Arc::new(result);
log("Future completed, sending result");
let _ = sender.send(boxed_result);
log("Result sent via channel");
});
self.queued.lock().push_back((id, wrapped_future));
id
}
pub fn poll(&self) {
let mut queue = self.queued.lock();
log("Locked queue for polling");
if queue.is_empty() {
log("Queue is empty, nothing to poll");
return;
}
let mut futures_to_spawn = Vec::new();
while let Some((id, future)) = queue.pop_front() {
log(format!("Processing future with id: {:?}", id));
{
let mut registry = self.handle_registry.lock();
if let Some(entry) = registry.get_mut(&id) {
entry.status = FutureStatus::CurrentlyPolling;
log("Updated status to CurrentlyPolling");
}
}
futures_to_spawn.push(future);
}
drop(queue);
for future in futures_to_spawn {
log("Spawning future with tokio");
tokio::spawn(future);
}
}
pub fn exchange(&self, handle: &FutureHandle) -> Option<AnyResult> {
let mut registry = self.handle_registry.lock();
if let Some(entry) = registry.get_mut(handle) {
match &entry.status {
FutureStatus::Completed => {
log("FutureStatus::Completed - returning cached result");
entry.cached_result.clone()
}
_ => {
log("Future not completed yet, checking receiver");
if let Some(receiver) = entry.receiver.as_mut() {
match receiver.try_recv() {
Ok(result) => {
log("Received result from channel");
entry.status = FutureStatus::Completed;
entry.cached_result = Some(result.clone());
entry.receiver = None; Some(result)
}
Err(oneshot::error::TryRecvError::Empty) => {
log("Channel is empty - future still running");
None
}
Err(oneshot::error::TryRecvError::Closed) => {
log("Channel is closed - future may have panicked");
None
}
}
} else {
log("No receiver available");
None
}
}
}
} else {
log("Handle not found in registry");
None
}
}
pub fn exchange_owned(&self, handle: &FutureHandle) -> Option<AnyResult> {
let mut registry = self.handle_registry.lock();
if let Some(entry) = registry.get_mut(handle) {
match &entry.status {
FutureStatus::Completed => {
log("FutureStatus::Completed - taking ownership of cached result");
entry.cached_result.take()
}
_ => {
log("Future not completed yet, checking receiver");
if let Some(receiver) = entry.receiver.as_mut() {
match receiver.try_recv() {
Ok(result) => {
log("Received result from channel");
entry.status = FutureStatus::Completed;
entry.receiver = None; Some(result)
}
Err(oneshot::error::TryRecvError::Empty) => {
log("Channel is empty - future still running");
None
}
Err(oneshot::error::TryRecvError::Closed) => {
log("Channel is closed - future may have panicked");
None
}
}
} else {
log("No receiver available");
None
}
}
}
} else {
log("Handle not found in registry");
None
}
}
pub fn exchange_as<T: Any + Send + Sync + 'static>(&self, handle: &FutureHandle) -> Option<T> {
self.exchange(handle)?
.downcast::<T>()
.ok()
.and_then(|arc| Arc::try_unwrap(arc).ok())
}
pub fn exchange_owned_as<T: Any + Send + Sync + 'static>(&self, handle: &FutureHandle) -> Option<T> {
self.exchange_owned(handle)?
.downcast::<T>()
.ok()
.and_then(|arc| Arc::try_unwrap(arc).ok())
}
pub fn get_status(&self, handle: &FutureHandle) -> Option<FutureStatus> {
let registry = self.handle_registry.lock();
registry.get(handle).map(|entry| entry.status.clone())
}
pub fn cleanup(&self) {
let mut registry = self.handle_registry.lock();
let completed_ids: Vec<FutureHandle> = registry
.iter()
.filter_map(|(&id, entry)| {
matches!(entry.status, FutureStatus::Completed).then_some(id)
})
.collect();
for id in completed_ids {
registry.remove(&id);
}
}
}
#[cfg(test)]
fn log(msg: impl ToString) {
use std::io::Write;
let mut file = std::fs::OpenOptions::new().append(true).create(true).open("test.log").unwrap();
file.write_all(format!("{}\n", msg.to_string()).as_bytes()).unwrap();
}
#[cfg(not(test))]
fn log(_msg: impl ToString) {
}
impl Default for FutureQueue {
fn default() -> Self {
Self::new()
}
}
#[test]
fn test_future_queue() {
tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap()
.block_on(async {
let queue = FutureQueue::new();
log("Created new queue");
let handle = queue.push(async move {
log("Inside the pushed future - starting work");
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
log("Inside the pushed future - work completed");
67 + 41
});
log("Created new handle");
queue.poll();
log("Initial poll completed");
let mut attempts = 0;
let max_attempts = 100;
let start_time = std::time::Instant::now();
loop {
attempts += 1;
log(format!("Attempt {}: Checking for result", attempts));
log(format!("Time since start: {} ms", start_time.elapsed().as_millis()));
if let Some(result) = queue.exchange(&handle) {
let result = result.downcast::<i32>().unwrap();
log(format!("Success! 67 + 41 = {}", result));
assert_eq!(*result, 108);
break;
}
if attempts >= max_attempts {
log("Max attempts reached - test failed");
panic!("Future never completed");
}
tokio::time::sleep(tokio::time::Duration::from_millis(1)).await;
}
log("Test completed successfully");
});
}
#[test]
fn test_exchange_owned_as() {
tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap()
.block_on(async {
let queue = FutureQueue::new();
let handle = queue.push(async move {
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
67 + 41
});
queue.poll();
let mut attempts = 0;
let max_attempts = 100;
loop {
attempts += 1;
if let Some(result) = queue.exchange_owned_as::<i32>(&handle) {
assert_eq!(result, 108);
break;
}
if attempts >= max_attempts {
panic!("Future never completed");
}
tokio::time::sleep(tokio::time::Duration::from_millis(1)).await;
}
assert!(queue.exchange_owned_as::<i32>(&handle).is_none());
});
}