Hello, tellus
Create an actor system with a single actor that handles one message and stops.
In this tutorial you build a small temperature monitor: devices record readings, a group manages its devices, and you can ask the group for the average temperature. Each step is a complete program that compiles and runs. You need nothing but tellus and Tokio.
Set up a project
Create a new binary crate and add tellus together with Tokio and anyhow:
cargo new hello-tellus
cd hello-tellus
cargo add anyhow
cargo add tokio --features macros,rt-multi-thread
cargo add tellusYour first actor
Replace src/main.rs with this program:
use anyhow::Context;
use std::convert::Infallible;
use tellus::{Actor, ActorContext, ActorSystem, Control, Incoming};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let system = ActorSystem::new(Greeter);
system.root().tell(Greet("Tellus".to_string()));
system
.terminated()
.await
.context("awaiting actor system termination")
}
struct Greeter;
impl Actor for Greeter {
type Message = Greet;
type State = ();
type Error = Infallible;
fn init(&self, _: &ActorContext<Self::Message>) -> Result<Self::State, Self::Error> {
Ok(())
}
fn receive(
&self,
_: &ActorContext<Self::Message>,
incoming: Incoming<Self::Message>,
_: Self::State,
) -> Result<Control<Self::State>, Self::Error> {
if let Incoming::Message(Greet(name)) = incoming {
println!("Hello, {name}!");
}
Ok(Control::Stop)
}
}
struct Greet(String);Run it with cargo run --quiet and it prints Hello, Tellus!.
What happens here
An actor is a value whose type implements the Actor trait. The trait has three associated types:
Messageis the type of the messages the actor receives, hereGreet.Stateis the actor's state. The greeter needs none, so it is().Erroris the type of the actor's failures. The greeter cannot fail, so it isInfallible.
init creates the initial state. receive is called for every incoming message. It gets the current state and returns what happens next: Control::Continue with the state for the next message, or Control::Stop to stop the actor. The greeter stops after its first message.
ActorSystem::new spawns the greeter as the root actor of a new actor system. tell sends it a message without waiting for anything. terminated resolves once the root actor has stopped, and then the program ends.
Notice that receive is a plain function, not an async fn. An actor reacts to one message at a time, from start to finish. In the next step you give an actor state that changes with every message.