1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
#![no_std]
extern crate alloc;
use alloc::sync::Arc;
pub mod actor;
pub use actor::{
Actor, ActorHandle, Message, MessageSender
};
use actor::ActorRef;
pub struct Slacktor {
/// The underying slab that stores actors.
slab: slab::Slab<Arc<dyn ActorRef>>,
}
impl Slacktor {
/// # [`Slacktor::new`]
/// Creates a new [`Slacktor`] instance
pub const fn new() -> Self {
Self {
slab: slab::Slab::new(),
}
}
/// # [`Slacktor::next_id`]
/// Returns what the id of the next actor will be
pub fn next_id(&self) -> u64 {
self.slab.vacant_key() as u64
}
/// # [`Slacktor::spawn`]
/// Create a new actor and return it's id.
pub fn spawn<A: Actor>(&mut self, actor: A) -> usize {
self.slab.insert(Arc::new(ActorHandle::new(actor)))
}
/// # [`Slacktor::kill`]
/// Remove's the Slacktor instance's reference to a given actor and calls the actor's `kill` function.
/// This will cause the actor to be destroyed after every existing handle is dropped,
/// which may or may not happen. Generally an actor will deinitialize itself, and then respond with an error
/// to every additional message.
#[cfg(not(feature = "async"))]
pub fn kill(&mut self, id: usize) {
// If the actor does not exist, exit early
if !self.slab.contains(id) {
return;
}
// Remove the actor from the slab
let a = self.slab.remove(id);
// Kill it
a.kill();
}
/// # [`Slacktor::kill`]
/// Remove's the Slacktor instance's reference to a given actor and calls the actor's `kill` function.
/// This will cause the actor to be destroyed after every existing handle is dropped,
/// which may or may not happen. Generally an actor will deinitialize itself, and then respond with an error
/// to every additional message. Returns [`None`] if the actor did not exist
#[cfg(feature = "async")]
pub async fn kill<A: Actor>(&mut self, id: usize) -> Option<()> {
// If the actor does not exist, exit early
if !self.slab.contains(id) {
return None;
}
// Remove the actor from the slab
let a = self.slab.remove(id);
let a = a.as_any().downcast_ref::<ActorHandle<A>>()?;
// Kill it
a.kill().await;
Some(())
}
/// # [`Slacktor::get`]
/// Get an actor handle given its id.
/// Return's [`None`] if the given actor does not exist.
pub fn get<A: Actor>(&self, id: usize) -> Option<&ActorHandle<A>> {
self.slab.get(id)
.and_then(|actor| actor.as_any().downcast_ref())
}
/// # [`Slacktor::shutdown`]
/// Kills every actor on the system and deallocates the slab.
/// The system is returned to the same state as when it was first initialized.
#[cfg(feature = "async")]
pub async fn shutdown(&mut self) {
for a in self.slab.drain() {
a.kill().await;
}
self.slab.shrink_to_fit();
}
/// # [`Slacktor::shutdown`]
/// Kills every actor on the system and deallocates the slab.
/// The system is returned to the same state as when it was first initialized.
#[cfg(not(feature = "async"))]
pub fn shutdown(&mut self) {
for a in self.slab.drain() {
a.kill();
}
self.slab.shrink_to_fit();
}
/// # [`Slacktor::shrink`]
/// Unallocates as much unused memory from the end of the slab as possible.
pub fn shrink(&mut self) {
self.slab.shrink_to_fit();
}
}