Skip to main content

palladium/async_runtime/
mod.rs

1// Async runtime for Palladium
2// "Orchestrating concurrent legends"
3
4use std::collections::VecDeque;
5use std::sync::{Arc, Mutex};
6use std::thread;
7use std::time::Duration;
8
9/// Future trait for asynchronous computations
10pub trait Future {
11    type Output;
12
13    /// Poll the future to check if it's ready
14    fn poll(&mut self) -> Poll<Self::Output>;
15}
16
17/// Result of polling a future
18pub enum Poll<T> {
19    /// Future is ready with a value
20    Ready(T),
21    /// Future is not ready, should be polled again later
22    Pending,
23}
24
25/// Task represents an asynchronous computation
26pub struct Task {
27    id: usize,
28    poll_fn: Box<dyn FnMut() -> Poll<()> + Send>,
29}
30
31/// Runtime for executing async tasks
32pub struct AsyncRuntime {
33    /// Queue of tasks ready to be polled
34    ready_queue: Arc<Mutex<VecDeque<Task>>>,
35    /// Number of worker threads
36    num_workers: usize,
37    /// Whether the runtime is running
38    running: Arc<Mutex<bool>>,
39}
40
41impl AsyncRuntime {
42    /// Create a new async runtime
43    pub fn new(num_workers: usize) -> Self {
44        Self {
45            ready_queue: Arc::new(Mutex::new(VecDeque::new())),
46            num_workers,
47            running: Arc::new(Mutex::new(false)),
48        }
49    }
50
51    /// Spawn a new async task
52    pub fn spawn<F>(&self, mut future: F) -> TaskHandle
53    where
54        F: Future<Output = ()> + Send + 'static,
55    {
56        static TASK_ID_COUNTER: std::sync::atomic::AtomicUsize =
57            std::sync::atomic::AtomicUsize::new(0);
58        let id = TASK_ID_COUNTER.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
59
60        let task = Task {
61            id,
62            poll_fn: Box::new(move || future.poll()),
63        };
64
65        self.ready_queue.lock().unwrap().push_back(task);
66
67        TaskHandle { id }
68    }
69
70    /// Run the async runtime
71    pub fn run(&self) {
72        *self.running.lock().unwrap() = true;
73
74        let mut workers = Vec::new();
75
76        for worker_id in 0..self.num_workers {
77            let ready_queue = Arc::clone(&self.ready_queue);
78            let running = Arc::clone(&self.running);
79
80            let handle = thread::spawn(move || {
81                worker_loop(worker_id, ready_queue, running);
82            });
83
84            workers.push(handle);
85        }
86
87        // Wait for all workers to finish
88        for worker in workers {
89            worker.join().unwrap();
90        }
91    }
92
93    /// Stop the runtime
94    pub fn stop(&self) {
95        *self.running.lock().unwrap() = false;
96    }
97}
98
99/// Worker loop for processing tasks
100fn worker_loop(
101    worker_id: usize,
102    ready_queue: Arc<Mutex<VecDeque<Task>>>,
103    running: Arc<Mutex<bool>>,
104) {
105    loop {
106        // Check if we should stop
107        if !*running.lock().unwrap() {
108            break;
109        }
110
111        // Try to get a task from the queue
112        let task = {
113            let mut queue = ready_queue.lock().unwrap();
114            queue.pop_front()
115        };
116
117        if let Some(mut task) = task {
118            // Poll the task
119            match (task.poll_fn)() {
120                Poll::Ready(()) => {
121                    // Task completed
122                    println!("Worker {}: Task {} completed", worker_id, task.id);
123                }
124                Poll::Pending => {
125                    // Task not ready, put it back in the queue
126                    ready_queue.lock().unwrap().push_back(task);
127                }
128            }
129        } else {
130            // No tasks available, sleep briefly
131            thread::sleep(Duration::from_millis(10));
132        }
133    }
134}
135
136/// Handle to a spawned task
137pub struct TaskHandle {
138    #[allow(dead_code)]
139    id: usize,
140}
141
142/// Simple implementation of an async sleep
143pub struct Sleep {
144    deadline: std::time::Instant,
145}
146
147impl Sleep {
148    pub fn new(duration: Duration) -> Self {
149        Self {
150            deadline: std::time::Instant::now() + duration,
151        }
152    }
153}
154
155impl Future for Sleep {
156    type Output = ();
157
158    fn poll(&mut self) -> Poll<Self::Output> {
159        if std::time::Instant::now() >= self.deadline {
160            Poll::Ready(())
161        } else {
162            Poll::Pending
163        }
164    }
165}
166
167/// Channel for async communication
168pub struct Channel<T> {
169    queue: Arc<Mutex<VecDeque<T>>>,
170}
171
172impl<T> Default for Channel<T> {
173    fn default() -> Self {
174        Self {
175            queue: Arc::new(Mutex::new(VecDeque::new())),
176        }
177    }
178}
179
180impl<T> Channel<T> {
181    pub fn new() -> Self {
182        Self::default()
183    }
184
185    pub fn sender(&self) -> Sender<T> {
186        Sender {
187            queue: Arc::clone(&self.queue),
188        }
189    }
190
191    pub fn receiver(&self) -> Receiver<T> {
192        Receiver {
193            queue: Arc::clone(&self.queue),
194        }
195    }
196}
197
198/// Sender end of a channel
199pub struct Sender<T> {
200    queue: Arc<Mutex<VecDeque<T>>>,
201}
202
203impl<T> Sender<T> {
204    pub fn send(&self, value: T) {
205        self.queue.lock().unwrap().push_back(value);
206    }
207}
208
209/// Receiver end of a channel
210pub struct Receiver<T> {
211    queue: Arc<Mutex<VecDeque<T>>>,
212}
213
214impl<T> Receiver<T> {
215    pub fn try_recv(&self) -> Option<T> {
216        self.queue.lock().unwrap().pop_front()
217    }
218}
219
220/// Future for receiving from a channel
221pub struct RecvFuture<T> {
222    receiver: Receiver<T>,
223}
224
225impl<T> RecvFuture<T> {
226    pub fn new(receiver: Receiver<T>) -> Self {
227        Self { receiver }
228    }
229}
230
231impl<T> Future for RecvFuture<T> {
232    type Output = Option<T>;
233
234    fn poll(&mut self) -> Poll<Self::Output> {
235        if let Some(value) = self.receiver.try_recv() {
236            Poll::Ready(Some(value))
237        } else {
238            Poll::Pending
239        }
240    }
241}
242
243/// Async I/O operations
244pub mod io {
245    use super::*;
246    use std::fs;
247    use std::io;
248    use std::path::Path;
249
250    /// Async file read
251    pub struct ReadFile {
252        path: String,
253        state: ReadFileState,
254    }
255
256    enum ReadFileState {
257        NotStarted,
258        Reading,
259        Done(io::Result<String>),
260    }
261
262    impl ReadFile {
263        pub fn new(path: impl AsRef<Path>) -> Self {
264            Self {
265                path: path.as_ref().to_str().unwrap().to_string(),
266                state: ReadFileState::NotStarted,
267            }
268        }
269    }
270
271    impl Future for ReadFile {
272        type Output = io::Result<String>;
273
274        fn poll(&mut self) -> Poll<Self::Output> {
275            match &mut self.state {
276                ReadFileState::NotStarted => {
277                    // Start reading in a background thread
278                    let path = self.path.clone();
279                    thread::spawn(move || fs::read_to_string(path));
280                    self.state = ReadFileState::Reading;
281                    Poll::Pending
282                }
283                ReadFileState::Reading => {
284                    // In a real implementation, we'd check if the thread is done
285                    // For now, we'll do a blocking read
286                    let result = fs::read_to_string(&self.path);
287                    self.state = ReadFileState::Done(result);
288                    Poll::Pending
289                }
290                ReadFileState::Done(result) => {
291                    // Clone the result to return it
292                    match result {
293                        Ok(content) => Poll::Ready(Ok(content.clone())),
294                        Err(e) => Poll::Ready(Err(io::Error::new(e.kind(), e.to_string()))),
295                    }
296                }
297            }
298        }
299    }
300
301    /// Async file write
302    pub struct WriteFile {
303        path: String,
304        content: String,
305        state: WriteFileState,
306    }
307
308    enum WriteFileState {
309        NotStarted,
310        #[allow(dead_code)]
311        Writing,
312        Done(io::Result<()>),
313    }
314
315    impl WriteFile {
316        pub fn new(path: impl AsRef<Path>, content: String) -> Self {
317            Self {
318                path: path.as_ref().to_str().unwrap().to_string(),
319                content,
320                state: WriteFileState::NotStarted,
321            }
322        }
323    }
324
325    impl Future for WriteFile {
326        type Output = io::Result<()>;
327
328        fn poll(&mut self) -> Poll<Self::Output> {
329            match &mut self.state {
330                WriteFileState::NotStarted => {
331                    // In a real implementation, this would be async
332                    let result = fs::write(&self.path, &self.content);
333                    self.state = WriteFileState::Done(result);
334                    Poll::Pending
335                }
336                WriteFileState::Writing => Poll::Pending,
337                WriteFileState::Done(result) => match result {
338                    Ok(()) => Poll::Ready(Ok(())),
339                    Err(e) => Poll::Ready(Err(io::Error::new(e.kind(), e.to_string()))),
340                },
341            }
342        }
343    }
344}
345
346/// Combinators for futures
347pub mod combinators {
348    use super::*;
349
350    /// Map combinator
351    pub struct Map<F, U, G> {
352        future: F,
353        mapper: Option<G>,
354        _phantom: std::marker::PhantomData<U>,
355    }
356
357    impl<F, U, G> Map<F, U, G>
358    where
359        F: Future,
360        G: FnOnce(F::Output) -> U,
361    {
362        pub fn new(future: F, mapper: G) -> Self {
363            Self {
364                future,
365                mapper: Some(mapper),
366                _phantom: std::marker::PhantomData,
367            }
368        }
369    }
370
371    impl<F, U, G> Future for Map<F, U, G>
372    where
373        F: Future,
374        G: FnOnce(F::Output) -> U,
375    {
376        type Output = U;
377
378        fn poll(&mut self) -> Poll<Self::Output> {
379            match self.future.poll() {
380                Poll::Ready(value) => {
381                    let mapper = self.mapper.take().expect("Map polled after completion");
382                    Poll::Ready(mapper(value))
383                }
384                Poll::Pending => Poll::Pending,
385            }
386        }
387    }
388
389    /// Join two futures
390    pub struct Join<F1, F2, O1, O2>
391    where
392        F1: Future<Output = O1>,
393        F2: Future<Output = O2>,
394    {
395        future1: Option<F1>,
396        future2: Option<F2>,
397        output1: Option<O1>,
398        output2: Option<O2>,
399    }
400
401    impl<F1, F2, O1, O2> Join<F1, F2, O1, O2>
402    where
403        F1: Future<Output = O1>,
404        F2: Future<Output = O2>,
405    {
406        pub fn new(future1: F1, future2: F2) -> Self {
407            Self {
408                future1: Some(future1),
409                future2: Some(future2),
410                output1: None,
411                output2: None,
412            }
413        }
414    }
415
416    impl<F1, F2, O1, O2> Future for Join<F1, F2, O1, O2>
417    where
418        F1: Future<Output = O1>,
419        F2: Future<Output = O2>,
420    {
421        type Output = (O1, O2);
422
423        fn poll(&mut self) -> Poll<Self::Output> {
424            // Poll first future if not complete
425            if self.output1.is_none() {
426                if let Some(ref mut f1) = self.future1 {
427                    if let Poll::Ready(value) = f1.poll() {
428                        self.output1 = Some(value);
429                        self.future1 = None;
430                    }
431                }
432            }
433
434            // Poll second future if not complete
435            if self.output2.is_none() {
436                if let Some(ref mut f2) = self.future2 {
437                    if let Poll::Ready(value) = f2.poll() {
438                        self.output2 = Some(value);
439                        self.future2 = None;
440                    }
441                }
442            }
443
444            // Check if both are complete
445            if let (Some(v1), Some(v2)) = (self.output1.take(), self.output2.take()) {
446                Poll::Ready((v1, v2))
447            } else {
448                // Restore values if we took them
449                if let Some(v1) = self.output1.take() {
450                    self.output1 = Some(v1);
451                }
452                if let Some(v2) = self.output2.take() {
453                    self.output2 = Some(v2);
454                }
455                Poll::Pending
456            }
457        }
458    }
459}
460
461#[cfg(test)]
462mod tests {
463    use super::*;
464
465    #[test]
466    fn test_sleep_future() {
467        let mut sleep = Sleep::new(Duration::from_millis(100));
468
469        // Should be pending initially
470        match sleep.poll() {
471            Poll::Pending => {}
472            Poll::Ready(()) => panic!("Sleep should not be ready immediately"),
473        }
474
475        // Wait and poll again
476        thread::sleep(Duration::from_millis(150));
477        match sleep.poll() {
478            Poll::Ready(()) => {}
479            Poll::Pending => panic!("Sleep should be ready after deadline"),
480        }
481    }
482
483    #[test]
484    fn test_channel() {
485        let channel = Channel::<i32>::new();
486        let sender = channel.sender();
487        let receiver = channel.receiver();
488
489        // Send some values
490        sender.send(42);
491        sender.send(100);
492
493        // Receive values
494        assert_eq!(receiver.try_recv(), Some(42));
495        assert_eq!(receiver.try_recv(), Some(100));
496        assert_eq!(receiver.try_recv(), None);
497    }
498}