routee_compass/app/compass/
compass_app_config.rs1use std::{path::Path, sync::Arc};
2
3use config::Config;
4use routee_compass_core::{
5 algorithm::search::SearchAlgorithmConfig,
6 config::{ConfigJsonExtensions, OneOrMany},
7 model::{
8 constraint::ConstraintModelService, cost::CostModelConfig, map::MapModelConfig,
9 network::GraphConfig, state::StateVariableConfig, termination::TerminationModel,
10 traversal::TraversalModelService,
11 },
12};
13use serde::{Deserialize, Serialize};
14use serde_json::Value;
15
16use crate::{
17 app::compass::{CompassAppError, CompassAppSystemParameters, CompassBuilderInventory},
18 plugin::PluginConfig,
19};
20
21#[derive(Serialize, Deserialize, Clone, Debug)]
25pub struct CompassAppConfig {
26 pub algorithm: SearchAlgorithmConfig,
27 pub state: Option<Vec<(String, StateVariableConfig)>>,
28 pub cost: CostModelConfig,
29 pub label: Value,
30 pub mapping: MapModelConfig,
31 pub graph: GraphConfig,
32 pub search: OneOrMany<SearchConfig>,
34 pub plugin: PluginConfig,
35 pub termination: TerminationModel,
36 pub system: CompassAppSystemParameters,
37 pub map_matching: Value,
38}
39
40#[derive(Serialize, Deserialize, Clone, Debug)]
43pub struct SearchConfig {
44 pub traversal: Value,
45 pub constraint: Value,
46}
47
48impl CompassAppConfig {
49 pub fn from_str(
51 config: &str,
52 config_path: &str,
53 format: config::FileFormat,
54 ) -> Result<CompassAppConfig, CompassAppError> {
55 let default_config = config::File::from_str(
56 include_str!("config.default.toml"),
57 config::FileFormat::Toml,
58 );
59
60 let user_config = config::File::from_str(config, format);
61
62 let config = Config::builder()
63 .add_source(default_config)
64 .add_source(user_config)
65 .build()?;
66
67 let config_json = config
68 .clone()
69 .try_deserialize::<serde_json::Value>()?
70 .normalize_file_paths(Path::new(config_path), None)?;
71 let compass_config: CompassAppConfig = serde_json::from_value(config_json)?;
72
73 Ok(compass_config)
74 }
75}
76
77impl TryFrom<&Path> for CompassAppConfig {
78 type Error = CompassAppError;
79
80 fn try_from(config_path: &Path) -> Result<Self, Self::Error> {
81 let default_config = config::File::from_str(
82 include_str!("config.default.toml"),
83 config::FileFormat::Toml,
84 );
85
86 let config = Config::builder()
87 .add_source(default_config)
88 .add_source(config::File::from(config_path))
89 .build()?;
90
91 let config_json = config
92 .clone()
93 .try_deserialize::<serde_json::Value>()?
94 .normalize_file_paths(config_path, None)?;
95 let compass_config: CompassAppConfig =
96 serde_json::from_value(config_json).map_err(|e| {
97 let filename = config_path.to_str().unwrap_or("<config path>");
98 CompassAppError::BuildFailure(format!("while reading {filename}: {e}"))
99 })?;
100
101 Ok(compass_config)
102 }
103}
104
105impl CompassAppConfig {
106 pub fn to_pretty_string(&self) -> Result<String, CompassAppError> {
109 serde_json::to_string_pretty(self).map_err(|e| {
110 CompassAppError::BuildFailure(format!("Failed to serialize config: {}", e))
111 })
112 }
113
114 pub fn build_traversal_model_services(
115 &self,
116 builders: &CompassBuilderInventory,
117 ) -> Result<Vec<Arc<dyn TraversalModelService>>, CompassAppError> {
118 let result = self
119 .search
120 .iter()
121 .map(|el| builders.build_traversal_model_service(&el.traversal))
122 .collect::<Result<Vec<_>, _>>()?;
123 Ok(result)
124 }
125
126 pub fn build_constraint_model_services(
127 &self,
128 builders: &CompassBuilderInventory,
129 ) -> Result<Vec<Arc<dyn ConstraintModelService>>, CompassAppError> {
130 let result = self
131 .search
132 .iter()
133 .map(|el| builders.build_constraint_model_service(&el.constraint))
134 .collect::<Result<Vec<_>, _>>()?;
135 Ok(result)
136 }
137}