Hello World works
This commit is contained in:
@@ -4,9 +4,9 @@ version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
futures = { version = "0.3.31", default-features = false, features = [
|
||||
"std",
|
||||
"async-await",
|
||||
futures = { version = "0.3.32", default-features = false, features = [
|
||||
"std",
|
||||
"async-await",
|
||||
] }
|
||||
itertools = "0.14.0"
|
||||
task-local = "0.1.0"
|
||||
task-local = "0.1.1"
|
||||
|
||||
@@ -1,61 +1,67 @@
|
||||
use std::cell::RefCell;
|
||||
use std::fmt;
|
||||
use std::pin::Pin;
|
||||
use std::task::Poll;
|
||||
use std::rc::Rc;
|
||||
use std::task::{Poll, Waker};
|
||||
|
||||
use futures::channel::mpsc::{SendError, UnboundedReceiver, UnboundedSender, unbounded};
|
||||
use futures::StreamExt;
|
||||
use futures::future::LocalBoxFuture;
|
||||
use futures::stream::FuturesUnordered;
|
||||
use futures::{SinkExt, StreamExt};
|
||||
|
||||
pub struct LocalSetController<'a, E> {
|
||||
sender: UnboundedSender<LocalBoxFuture<'a, Result<(), E>>>,
|
||||
pub struct SpawnError<T>(T);
|
||||
impl<T> fmt::Debug for SpawnError<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("SpawnError") }
|
||||
}
|
||||
|
||||
pub struct LocalSetState<'a, E> {
|
||||
waker: Waker,
|
||||
futures: FuturesUnordered<LocalBoxFuture<'a, Result<(), E>>>,
|
||||
}
|
||||
|
||||
pub struct LocalSetController<'a, E>(Rc<RefCell<LocalSetState<'a, E>>>);
|
||||
impl<'a, E> LocalSetController<'a, E> {
|
||||
pub async fn spawn<F: Future<Output = Result<(), E>> + 'a>(
|
||||
&mut self,
|
||||
pub fn is_empty(&self) -> bool { self.len() == 0 }
|
||||
pub fn len(&self) -> usize { self.0.borrow().futures.len() }
|
||||
pub fn spawn<F: Future<Output = Result<(), E>> + 'a>(&self, fut: F) {
|
||||
self.try_spawn(fut).unwrap()
|
||||
}
|
||||
pub fn try_spawn<F: Future<Output = Result<(), E>> + 'a>(
|
||||
&self,
|
||||
fut: F,
|
||||
) -> Result<(), SendError> {
|
||||
self.sender.send(Box::pin(fut)).await
|
||||
) -> Result<(), SpawnError<F>> {
|
||||
if Rc::strong_count(&self.0) == 1 {
|
||||
return Err(SpawnError(fut));
|
||||
}
|
||||
let g = self.0.borrow_mut();
|
||||
g.futures.push(Box::pin(fut));
|
||||
g.waker.wake_by_ref();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn local_set<'a, E: 'a>()
|
||||
-> (LocalSetController<'a, E>, impl Future<Output = Result<(), E>> + 'a) {
|
||||
let (sender, receiver) = unbounded();
|
||||
let controller = LocalSetController { sender };
|
||||
let set = LocalSet { receiver, pending: FuturesUnordered::new() };
|
||||
pub fn local_set<'a, E: 'a>() -> (LocalSetController<'a, E>, LocalSet<'a, E>) {
|
||||
let state = Rc::new(RefCell::new(LocalSetState {
|
||||
waker: Waker::noop().clone(),
|
||||
futures: FuturesUnordered::new(),
|
||||
}));
|
||||
let controller = LocalSetController(state.clone());
|
||||
let set = LocalSet(state);
|
||||
(controller, set)
|
||||
}
|
||||
|
||||
struct LocalSet<'a, E> {
|
||||
receiver: UnboundedReceiver<LocalBoxFuture<'a, Result<(), E>>>,
|
||||
pending: FuturesUnordered<LocalBoxFuture<'a, Result<(), E>>>,
|
||||
}
|
||||
pub struct LocalSet<'a, E>(Rc<RefCell<LocalSetState<'a, E>>>);
|
||||
impl<E> Future for LocalSet<'_, E> {
|
||||
type Output = Result<(), E>;
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
|
||||
let this = self.get_mut();
|
||||
let mut any_pending = false;
|
||||
loop {
|
||||
match this.receiver.poll_next_unpin(cx) {
|
||||
Poll::Ready(Some(fut)) => this.pending.push(fut),
|
||||
Poll::Ready(None) => break,
|
||||
Poll::Pending => {
|
||||
any_pending = true;
|
||||
break;
|
||||
},
|
||||
}
|
||||
let ctl_dropped = 1 == Rc::strong_count(&self.0);
|
||||
let mut this = self.0.borrow_mut();
|
||||
if !ctl_dropped {
|
||||
this.waker.clone_from(cx.waker());
|
||||
}
|
||||
loop {
|
||||
match this.pending.poll_next_unpin(cx) {
|
||||
Poll::Ready(Some(Err(e))) => return Poll::Ready(Err(e)),
|
||||
Poll::Ready(Some(Ok(()))) => continue,
|
||||
Poll::Ready(None) => break,
|
||||
Poll::Pending => {
|
||||
any_pending = true;
|
||||
break;
|
||||
},
|
||||
}
|
||||
match this.futures.poll_next_unpin(cx) {
|
||||
Poll::Ready(Some(Err(e))) => Poll::Ready(Err(e)),
|
||||
Poll::Ready(None) if ctl_dropped => Poll::Ready(Ok(())),
|
||||
_ => Poll::Pending,
|
||||
}
|
||||
if any_pending { Poll::Pending } else { Poll::Ready(Ok(())) }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user