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