scientific_workflow/configuration/
settings.rs1use std::fmt;
4use std::path::{Path, PathBuf};
5use std::sync::Arc;
6
7use serde::Deserialize;
8
9use super::error::ConfigurationError;
10use super::source::{invalid, parse_strict_json, read_source};
11
12const STUDY_SETTINGS_FILE: &str = "study.json";
13
14#[derive(Clone)]
20pub struct StudySettings {
21 inner: Arc<StudySettingsInner>,
22}
23
24impl StudySettings {
25 pub fn load(study_root: impl Into<PathBuf>) -> Result<Self, ConfigurationError> {
27 let study_root = study_root.into();
28 let source_path = study_root.join(STUDY_SETTINGS_FILE);
29 let source = read_source(&source_path)?;
30 let document = parse_strict_json(&source_path, &source)?.into_json();
31 let raw: RawStudySettings = serde_json::from_value(document).map_err(|source| {
32 ConfigurationError::InvalidConfigurationDocument {
33 path: source_path.clone(),
34 reason: source.to_string(),
35 }
36 })?;
37 if raw.replicate_settings.replicates == 0 {
38 return invalid(
39 &source_path,
40 "replicate_settings.replicates must be positive",
41 );
42 }
43
44 Ok(Self {
45 inner: Arc::new(StudySettingsInner {
46 study_root,
47 source_path,
48 source: source.into_boxed_slice(),
49 replicate_settings: ReplicateSettings {
50 replicates: raw.replicate_settings.replicates,
51 execution: raw.replicate_settings.execution,
52 failure_policy: raw.replicate_settings.failure_policy,
53 seed: raw.replicate_settings.seed,
54 },
55 }),
56 })
57 }
58
59 pub fn study_root(&self) -> &Path {
61 &self.inner.study_root
62 }
63
64 pub fn source_path(&self) -> &Path {
66 &self.inner.source_path
67 }
68
69 pub fn source_json(&self) -> &[u8] {
71 &self.inner.source
72 }
73
74 pub fn replicate_settings(&self) -> ReplicateSettings {
76 self.inner.replicate_settings
77 }
78}
79
80impl fmt::Debug for StudySettings {
81 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
82 formatter
83 .debug_struct("StudySettings")
84 .field("study_root", &self.study_root())
85 .field("source_path", &self.source_path())
86 .field("replicate_settings", &self.replicate_settings())
87 .finish_non_exhaustive()
88 }
89}
90
91struct StudySettingsInner {
92 study_root: PathBuf,
93 source_path: PathBuf,
94 source: Box<[u8]>,
95 replicate_settings: ReplicateSettings,
96}
97
98#[derive(Clone, Copy, Debug, Eq, PartialEq)]
100pub struct ReplicateSettings {
101 replicates: u64,
102 execution: ReplicateExecutionMode,
103 failure_policy: ReplicateFailurePolicy,
104 seed: u64,
105}
106
107impl ReplicateSettings {
108 pub const fn replicates(self) -> u64 {
110 self.replicates
111 }
112
113 pub const fn execution(self) -> ReplicateExecutionMode {
115 self.execution
116 }
117
118 pub const fn failure_policy(self) -> ReplicateFailurePolicy {
120 self.failure_policy
121 }
122
123 pub const fn seed(self) -> u64 {
125 self.seed
126 }
127}
128
129#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
131#[serde(rename_all = "snake_case")]
132pub enum ReplicateExecutionMode {
133 Sequential,
135 Parallel,
137}
138
139impl ReplicateExecutionMode {
140 pub const fn as_str(self) -> &'static str {
142 match self {
143 Self::Sequential => "sequential",
144 Self::Parallel => "parallel",
145 }
146 }
147}
148
149#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
151#[serde(rename_all = "snake_case")]
152pub enum ReplicateFailurePolicy {
153 FailFast,
155 FinishAll,
157}
158
159impl ReplicateFailurePolicy {
160 pub const fn as_str(self) -> &'static str {
162 match self {
163 Self::FailFast => "fail_fast",
164 Self::FinishAll => "finish_all",
165 }
166 }
167}
168
169#[derive(Deserialize)]
170#[serde(deny_unknown_fields)]
171struct RawStudySettings {
172 replicate_settings: RawReplicateSettings,
173}
174
175#[derive(Deserialize)]
176#[serde(deny_unknown_fields)]
177struct RawReplicateSettings {
178 replicates: u64,
179 execution: ReplicateExecutionMode,
180 failure_policy: ReplicateFailurePolicy,
181 seed: u64,
182}