use std::{ cell::Cell, future::Future, io, mem, pin::Pin, task::{Context, Poll}, thread, }; use event_iterator::EventIterator; use whisk::Channel; /// An event iterator, for reading from stdin #[derive(Default)] pub struct Stdin { sender: Channel>, recver: Cell>>>, buffer: Cell>, send: Cell + Send>>>>, } impl EventIterator for Stdin { type Event<'me> = Buffer<'me>; fn poll_next( self: Pin<&Self>, cx: &mut Context<'_>, ) -> Poll>> { let this = self.get_ref(); if let Some(buffer) = this.buffer.take() { let sender = this.sender.clone(); this.send.set(Some(Box::pin(async move { sender.send(Some(buffer)).await }))); } if let Some(mut future) = this.send.take() { if future.as_mut().poll(cx).is_pending() { this.send.set(Some(future)); return Poll::Pending; } } let mut recver = this.recver.take().unwrap(); let poll = match Pin::new(&mut recver).poll(cx) { Poll::Ready(Some(buffer)) => { this.buffer.set(Some(buffer)); Poll::Ready(Some(Buffer(&this.buffer))) } Poll::Ready(None) => Poll::Ready(None), Poll::Pending => Poll::Pending, }; this.recver.set(Some(recver)); poll } } pub struct Buffer<'a>(&'a Cell>); impl Buffer<'_> { pub fn with(&self, f: impl FnOnce(&str)) { self.0.set(self.0.take().map(|buf| { f(&buf); buf })); } } async fn stdin_thread( recver: Channel>, sender: Channel>, ) { let stdin = io::stdin(); let mut buffer = String::new(); while stdin.read_line(&mut buffer).is_ok() { // Remove trailing newline buffer.pop(); if buffer.is_empty() { break; } sender.send(Some(mem::take(&mut buffer))).await; buffer = recver.recv().await.unwrap_or_default(); buffer.clear(); } sender.send(None).await; } #[async_main::async_main] async fn main(_spawner: async_main::LocalSpawner) { // Init stdin let stdin = Stdin::default(); let recver = stdin.sender.clone(); let sender = Channel::new(); stdin.recver.set(Some(sender.clone())); thread::spawn(move || { pasts::Executor::default().block_on(stdin_thread(recver, sender)) }); // Check messages while let Some(buffer) = stdin.next_unpinned().await { buffer.with(|message| { println!("Echo: {message}"); }); } }