pace_rs/
application.rs

1//! Pace Abscissa Application
2
3use std::path::{Path, PathBuf};
4
5use crate::commands::EntryPoint;
6use abscissa_core::{
7    application::{self, AppCell},
8    config::{self, CfgCell},
9    trace, Application, Configurable, FrameworkError, StandardPaths,
10};
11
12use pace_core::prelude::PaceConfig;
13
14/// Application state
15pub static PACE_APP: AppCell<PaceApp> = AppCell::new();
16
17/// Pace Application
18#[derive(Debug)]
19pub struct PaceApp {
20    /// Application configuration.
21    config: CfgCell<PaceConfig>,
22
23    /// Application state.
24    state: application::State<Self>,
25
26    /// Config file path
27    config_path: PathBuf,
28}
29
30/// Initialize a new application instance.
31///
32/// By default no configuration is loaded, and the framework state is
33/// initialized to a default, empty state (no components, threads, etc).
34impl Default for PaceApp {
35    fn default() -> Self {
36        Self {
37            config: CfgCell::default(),
38            state: application::State::default(),
39            config_path: PathBuf::default(),
40        }
41    }
42}
43
44impl Application for PaceApp {
45    /// Entrypoint command for this application.
46    type Cmd = EntryPoint;
47
48    /// Application configuration.
49    type Cfg = PaceConfig;
50
51    /// Paths to resources within the application.
52    type Paths = StandardPaths;
53
54    /// Accessor for application configuration.
55    fn config(&self) -> config::Reader<PaceConfig> {
56        self.config.read()
57    }
58
59    /// Borrow the application state immutably.
60    fn state(&self) -> &application::State<Self> {
61        &self.state
62    }
63
64    /// Register all components used by this application.
65    ///
66    /// If you would like to add additional components to your application
67    /// beyond the default ones provided by the framework, this is the place
68    /// to do so.
69    fn register_components(&mut self, command: &Self::Cmd) -> Result<(), FrameworkError> {
70        let framework_components = self.framework_components(command)?;
71        let mut app_components = self.state.components_mut();
72        app_components.register(framework_components)
73    }
74
75    /// Post-configuration lifecycle callback.
76    ///
77    /// Called regardless of whether config is loaded to indicate this is the
78    /// time in app lifecycle when configuration would be loaded if
79    /// possible.
80    fn after_config(&mut self, config: Self::Cfg) -> Result<(), FrameworkError> {
81        // Configure components
82        let mut components = self.state.components_mut();
83        components.after_config(&config)?;
84        self.config.set_once(config);
85        Ok(())
86    }
87
88    /// Get tracing configuration from command-line options
89    fn tracing_config(&self, command: &EntryPoint) -> trace::Config {
90        if command.verbose {
91            trace::Config::verbose()
92        } else {
93            trace::Config::default()
94        }
95    }
96
97    fn init(&mut self, command: &Self::Cmd) -> Result<(), FrameworkError> {
98        // Create and register components with the application.
99        // We do this first to calculate a proper dependency ordering before
100        // application configuration is processed
101        self.register_components(command)?;
102
103        // Load configuration
104        let config = command
105            .config_path()
106            .map(|path| self.load_config(&path))
107            .transpose()?
108            .unwrap_or_default();
109
110        // Set the config file path that was used to load the config
111        // in the current application state
112        self.set_config_path(command.config_path().unwrap_or_default());
113
114        // Fire callback regardless of whether any config was loaded to
115        // in order to signal state in the application lifecycle
116        self.after_config(command.process_config(config)?)?;
117
118        Ok(())
119    }
120}
121
122impl PaceApp {
123    /// Get the config file path
124    pub fn config_path(&self) -> &Path {
125        &self.config_path
126    }
127
128    /// Set the config file path
129    pub fn set_config_path(&mut self, config_path: PathBuf) {
130        self.config_path = config_path;
131    }
132}