use std::fmt;
use std::path::{Path, PathBuf};
use serde::Serialize;
use thiserror::Error;
use crate::configuration::{
ConfigurationError, MatchingTaskConfigIter, ParameterSpace, ProjectConfig, ProjectPaths,
TaskConfig, TaskConfigIter,
};
use crate::system_state::{StateError, SystemStateSchema};
const STATE_SCHEMA_FILE: &str = "state.json";
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum ScientificProjectError {
#[error(transparent)]
Configuration(#[from] ConfigurationError),
#[error(transparent)]
State(#[from] StateError),
}
#[derive(Clone)]
pub struct ScientificProject {
configuration: ProjectConfig,
state_schema: SystemStateSchema,
}
impl ScientificProject {
pub fn load(project_root: impl Into<PathBuf>) -> Result<Self, ScientificProjectError> {
let project_root = project_root.into();
let configuration = ProjectConfig::load(&project_root)?;
let state_schema = SystemStateSchema::load_json_template(
configuration
.configuration_directory()
.join(STATE_SCHEMA_FILE),
)?;
Ok(Self {
configuration,
state_schema,
})
}
pub fn project_root(&self) -> &Path {
self.configuration.project_root()
}
pub fn configuration_directory(&self) -> &Path {
self.configuration.configuration_directory()
}
pub fn parameters(&self) -> &ParameterSpace {
self.configuration.parameters()
}
pub fn paths(&self) -> &ProjectPaths {
self.configuration.paths()
}
pub fn resolve_path(&self, key: &str) -> Result<PathBuf, ConfigurationError> {
self.configuration.paths().resolve_path(key)
}
pub fn task_count(&self) -> u64 {
self.configuration.task_count()
}
pub fn task_config(&self, ordinal: u64) -> Result<TaskConfig, ConfigurationError> {
self.configuration.task_config(ordinal)
}
pub fn task_configs(&self) -> TaskConfigIter {
self.configuration.task_configs()
}
pub fn task_configs_matching<V>(
&self,
key: impl Into<String>,
value: V,
) -> Result<MatchingTaskConfigIter, ConfigurationError>
where
V: Serialize,
{
self.configuration.task_configs_matching(key, value)
}
pub fn unique_task_config_matching<V>(
&self,
key: impl Into<String>,
value: V,
) -> Result<TaskConfig, ConfigurationError>
where
V: Serialize,
{
self.configuration.unique_task_config_matching(key, value)
}
pub fn state_schema(&self) -> &SystemStateSchema {
&self.state_schema
}
pub fn configuration(&self) -> &ProjectConfig {
&self.configuration
}
pub fn into_parts(self) -> (ProjectConfig, SystemStateSchema) {
(self.configuration, self.state_schema)
}
}
impl fmt::Debug for ScientificProject {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("ScientificProject")
.field("project_root", &self.project_root())
.field("parameters", &self.parameters().parameter_count())
.field("tasks", &self.task_count())
.field("paths", &self.paths().len())
.field("state_fields", &self.state_schema().len())
.finish()
}
}