Skip to main content

scientific_workflow/
configuration.rs

1//! Standard JSON configuration for scientific projects and parameter sweeps.
2//!
3//! This module separates immutable project configuration from simulation state,
4//! analysis series, persistent state recording, and later task execution. Its
5//! standard on-disk layout is:
6//!
7//! ```text
8//! project-root/
9//! └── config/
10//!     ├── fixed.json
11//!     ├── sweep.json
12//!     └── paths.json
13//! ```
14//!
15//! - `fixed.json` is an object of parameter values shared by every generated
16//!   task.
17//! - `sweep.json` is a tagged Cartesian-axis or explicit-case definition.
18//! - `paths.json` is an object of named project-wide path strings.
19//!
20//! [`ProjectConfig`] loads all three files and lazily produces cheap owned
21//! [`TaskConfig`] handles that combine one fixed-plus-sweep selection with the
22//! shared path table. [`ParameterSpace`] and [`TaskParameters`] remain the
23//! lower-level parameter-only API. [`ProjectPaths`] resolves named relative
24//! paths against the project root without canonicalization or existence checks.
25//!
26//! # Basic workflow
27//!
28//! ```no_run
29//! use scientific_workflow::configuration::ProjectConfig;
30//!
31//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
32//! let project = ProjectConfig::load("scientific-project")?;
33//! for task in project.task_configs() {
34//!     let temperature = task.decode_value::<f64>("temperature")?;
35//!     let seed = task.decode_value::<u64>("seed")?;
36//!     let output_root = task.resolve_path("output_root")?;
37//!     println!(
38//!         "task={} temperature={temperature} seed={seed} output={}",
39//!         task.task_ordinal(),
40//!         output_root.display()
41//!     );
42//! }
43//! # Ok(())
44//! # }
45//! ```
46//!
47//! # Ownership and round trips
48//!
49//! Configuration is immutable after loading. `ParameterSpace`,
50//! `TaskParameters`, `TaskConfig`, their iterators, and `ProjectPaths` retain
51//! shared parsed allocations; task generation does not clone JSON values or
52//! allocate merged maps. Typed decoding is the explicit point at which an
53//! application creates an owned Rust value.
54//!
55//! The three original validated source byte sequences are retained unchanged.
56//! [`ProjectConfig::write_source_config`] can therefore reproduce the complete
57//! input configuration byte for byte. [`TaskParameters::to_json`] instead
58//! emits one deterministic derived fixed-plus-sweep dictionary for provenance
59//! or task metadata.
60//!
61//! # Failure behavior
62//!
63//! [`ConfigurationError`] retains source paths, exact keys, task ordinals, and
64//! underlying IO or Serde errors where applicable. Loaders never publish
65//! partially validated objects. Exact export never overwrites an existing
66//! `config/` directory.
67
68mod error;
69mod parameters;
70mod paths;
71mod project;
72
73pub use error::ConfigurationError;
74pub use parameters::{ParameterSpace, TaskParameters, TaskParametersIter};
75pub use paths::ProjectPaths;
76pub use project::{MatchingTaskConfigIter, ProjectConfig, TaskConfig, TaskConfigIter};