Skip to main content

sprite_core/
pool.rs

1use std::sync::atomic::{AtomicUsize, Ordering};
2use crate::engine::{Engine, Handle};
3use crate::actor::Context;
4use crate::message::Message;
5
6/// A round-robin pool of identical actors.
7pub struct Pool {
8    handles: Vec<Handle>,
9    idx: AtomicUsize,
10}
11
12impl Pool {
13    /// Create a pool of `count` actors, all running the same setup.
14    pub fn new<F>(engine: &Engine, name: &str, count: usize, setup: F) -> Self
15    where
16        F: Fn(&mut Context) + Clone + Send + Sync + 'static,
17    {
18        let mut handles = Vec::with_capacity(count);
19        for i in 0..count {
20            let handle = engine.spawn(&format!("{}-{}", name, i), setup.clone());
21            handles.push(handle);
22        }
23        Self { handles, idx: AtomicUsize::new(0) }
24    }
25
26    /// Send a message to the next actor in round-robin order.
27    pub fn send(&self, msg: Message) {
28        let idx = self.idx.fetch_add(1, Ordering::Relaxed) % self.handles.len();
29        self.handles[idx].send(msg);
30    }
31
32    /// Broadcast a message to every actor in the pool.
33    pub fn broadcast(&self, msg: Message) {
34        for h in &self.handles {
35            h.send(msg.clone());
36        }
37    }
38
39    /// Get a handle by index.
40    pub fn get(&self, idx: usize) -> Option<&Handle> {
41        self.handles.get(idx)
42    }
43
44    pub fn len(&self) -> usize { self.handles.len() }
45    pub fn is_empty(&self) -> bool { self.handles.is_empty() }
46}