Trait xtra::Actor

source ·
pub trait Actor: 'static + Send + Sized {
    fn started<'life0, 'life1, 'async_trait>(
        &'life0 mut self,
        ctx: &'life1 mut Context<Self>
    ) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
    where
        Self: 'async_trait,
        'life0: 'async_trait,
        'life1: 'async_trait
, { ... } fn stopping<'life0, 'life1, 'async_trait>(
        &'life0 mut self,
        ctx: &'life1 mut Context<Self>
    ) -> Pin<Box<dyn Future<Output = KeepRunning> + Send + 'async_trait>>
    where
        Self: 'async_trait,
        'life0: 'async_trait,
        'life1: 'async_trait
, { ... } fn stopped<'life0, 'async_trait>(
        &'life0 mut self
    ) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
    where
        Self: 'async_trait,
        'life0: 'async_trait
, { ... } fn create(self, message_cap: Option<usize>) -> ActorManager<Self> { ... } }
Expand description

An actor which can handle Messages one at a time. Actors can only be communicated with by sending Messages through their Addresses. They can modify their private state, respond to messages, and spawn other actors. They can also stop themselves through their Context by calling Context::stop. This will result in any attempt to send messages to the actor in future failing.

This is an async_trait, so implementations should be annotated #[async_trait].

Example

struct MyActor;

#[async_trait::async_trait]
impl Actor for MyActor {
    async fn started(&mut self, ctx: &mut Context<Self>) {
        println!("Started!");
    }

    async fn stopping(&mut self, ctx: &mut Context<Self>) -> KeepRunning {
        println!("Decided not to keep running");
        KeepRunning::StopAll
    }

    async fn stopped(&mut self) {
        println!("Finally stopping.");
    }
}

struct Goodbye;

impl Message for Goodbye {
    type Result = ();
}

#[async_trait::async_trait]
impl Handler<Goodbye> for MyActor {
    async fn handle(&mut self, _: Goodbye, ctx: &mut Context<Self>) {
        println!("Goodbye!");
        ctx.stop();
    }
}

// Will print "Started!", "Goodbye!", "Decided not to keep running", and then "Finally stopping."
smol::block_on(async {
    let addr = MyActor.create(None).spawn(&mut Smol::Global);
    addr.send(Goodbye).await;

    Timer::after(Duration::from_secs(1)).await; // Give it time to run
})

For longer examples, see the examples directory.

Provided Methods§

Called as soon as the actor has been started.

Called when the actor calls the Context::stop. This method can prevent the actor from stopping by returning KeepRunning::Yes. If this method returns KeepRunning::StopSelf, this actor will be stopped. If it returns KeepRunning::StopAll, then all actors on the same address as this actor will be stopped. This can take a little bit of time to propagate.

Note: this method will only be called when Context::stop is called from this actor. If the last strong address to the actor is dropped, or Context::stop is called from another actor on the same address, this will not be called. Therefore, Other, general destructor behaviour should be encapsulated in the Actor::stopped method.

Example
async fn stopping(&mut self, ctx: &mut Context<Self>) -> KeepRunning {
    self.is_running.into() // bool can be converted to KeepRunning with Into
}

Called when the actor is in the process of stopping. This could be because KeepRunning::StopAll or KeepRunning::StopSelf was returned from the Actor::stopping method, or because there are no more strong addresses (Address, as opposed to WeakAddress. This should be used for any final cleanup before the actor is dropped.

Returns the actor’s address and manager in a ready-to-start state, given the cap for the actor’s mailbox. If None is passed, it will be of unbounded size. To spawn the actor, the ActorManager::spawn must be called, or the ActorManager::run method must be called and the future it returns spawned onto an executor.

Example
smol::block_on(async {
    let (addr, fut) = MyActor.create(None).run();
    smol::spawn(fut).detach(); // Actually spawn the actor onto an executor
    Timer::after(Duration::from_secs(1)).await; // Give it time to run
})

Implementors§