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();
    }
}