application/
application.rs

1use hydra::Application;
2use hydra::ExitReason;
3use hydra::From;
4use hydra::GenServer;
5use hydra::GenServerOptions;
6use hydra::Pid;
7
8use serde::Deserialize;
9use serde::Serialize;
10
11#[derive(Debug, Serialize, Deserialize)]
12enum StackMessage {
13    Pop,
14    PopResult(String),
15    Push(String),
16}
17
18struct Stack {
19    stack: Vec<String>,
20}
21
22impl Stack {
23    pub fn with_entries(entries: Vec<&'static str>) -> Self {
24        Self {
25            stack: Vec::from_iter(entries.into_iter().map(Into::into)),
26        }
27    }
28}
29
30impl GenServer for Stack {
31    type Message = StackMessage;
32
33    async fn init(&mut self) -> Result<(), ExitReason> {
34        Ok(())
35    }
36
37    async fn handle_call(
38        &mut self,
39        message: Self::Message,
40        _from: From,
41    ) -> Result<Option<Self::Message>, ExitReason> {
42        match message {
43            StackMessage::Pop => Ok(Some(StackMessage::PopResult(self.stack.remove(0)))),
44            _ => unreachable!(),
45        }
46    }
47
48    async fn handle_cast(&mut self, message: Self::Message) -> Result<(), ExitReason> {
49        match message {
50            StackMessage::Push(value) => self.stack.insert(0, value),
51            _ => unreachable!(),
52        }
53        Ok(())
54    }
55}
56
57struct StackApplication;
58
59impl Application for StackApplication {
60    // Here, we must link a process for the application to monitor, usually, a Supervisor, but it can be any process.
61    async fn start(&self) -> Result<Pid, ExitReason> {
62        let pid = Stack::with_entries(vec!["hello", "world"])
63            .start_link(GenServerOptions::new())
64            .await
65            .expect("Failed to start stack!");
66
67        let result = Stack::call(pid, StackMessage::Pop, None)
68            .await
69            .expect("Stack call failed!");
70
71        tracing::info!("{:?}", result);
72
73        Stack::cast(pid, StackMessage::Push(String::from("rust")));
74
75        let result = Stack::call(pid, StackMessage::Pop, None)
76            .await
77            .expect("Stack call failed!");
78
79        tracing::info!("{:?}", result);
80
81        // Otherwise, the application will run forever waiting for Stack to terminate.
82        Stack::stop(pid, ExitReason::Normal, None).await?;
83
84        Ok(pid)
85    }
86}
87
88fn main() {
89    // This method will return once the linked Process in StackApplication::start has terminated.
90    Application::run(StackApplication)
91}