maycoon_core/app/
context.rs

1use crate::app::diagnostics::Diagnostics;
2use crate::app::update::{Update, UpdateManager};
3use crate::signal::Signal;
4use crate::signal::eval::EvalSignal;
5use crate::signal::fixed::FixedSignal;
6use crate::signal::listener::Listener;
7use crate::signal::memoized::MemoizedSignal;
8use crate::signal::state::StateSignal;
9
10/// The application context for managing the application lifecycle.
11#[derive(Clone)]
12pub struct AppContext {
13    update: UpdateManager,
14    diagnostics: Diagnostics,
15}
16
17impl AppContext {
18    /// Create a new application context using the given [UpdateManager].
19    #[tracing::instrument(level = "trace", skip_all)]
20    pub fn new(update: UpdateManager, diagnostics: Diagnostics) -> Self {
21        Self {
22            update,
23            diagnostics,
24        }
25    }
26
27    /// Get the [Diagnostics] of the application.
28    pub fn diagnostics(&self) -> Diagnostics {
29        self.diagnostics
30    }
31
32    /// Get the [UpdateManager] of the application.
33    pub fn update(&self) -> UpdateManager {
34        self.update.clone()
35    }
36
37    /// Make the application exit by setting [Update::EXIT].
38    pub fn exit(&self) {
39        self.update.insert(Update::EXIT);
40    }
41
42    /// Hook the given [Signal] to the [UpdateManager] of this application.
43    ///
44    /// This makes the signal reactive, so it will notify the renderer when the inner value changes.
45    #[tracing::instrument(level = "trace", skip_all, fields(signal = std::any::type_name::<T>()))]
46    pub fn hook_signal<T: 'static, S: Signal<T>>(&self, signal: &mut S) {
47        let update = self.update();
48        signal.listen(Listener::new(move |_| update.insert(Update::EVAL)));
49    }
50
51    /// Hook the given [Signal] to the [UpdateManager] of this application and return it.
52    ///
53    /// See [AppContext::hook_signal] for more.
54    pub fn use_signal<T: 'static, S: Signal<T>>(&self, mut signal: S) -> S {
55        self.hook_signal(&mut signal);
56
57        signal
58    }
59
60    /// Shortcut for creating and hooking a [StateSignal] into the application lifecycle.
61    pub fn use_state<T: 'static>(&self, value: T) -> StateSignal<T> {
62        self.use_signal(StateSignal::new(value))
63    }
64
65    /// Shortcut for creating and hooking a [MemoizedSignal] into the application lifecycle.
66    pub fn use_memoized<T: 'static>(&self, value: impl Fn() -> T + 'static) -> MemoizedSignal<T> {
67        self.use_signal(MemoizedSignal::new(value))
68    }
69
70    /// Shortcut for creating and hooking a [FixedSignal] into the application lifecycle.
71    pub fn use_fixed<T: 'static>(&self, value: T) -> FixedSignal<T> {
72        self.use_signal(FixedSignal::new(value))
73    }
74
75    /// Shortcut for creating and hooking an [EvalSignal] into the application lifecycle.
76    pub fn use_eval<T: 'static>(&self, eval: impl Fn() -> T + 'static) -> EvalSignal<T> {
77        self.use_signal(EvalSignal::new(eval))
78    }
79}