Skip to main content

castep_cell_io/param/general/
write_checkpoint.rs

1/// !!! Use with caution. This thing is poorly designed and documented by `CASTEP` IMO.
2/// Not guaranteed to be able to handle all cases.
3use castep_cell_fmt::{Cell, CellValue, ToCell, ToCellValue, CResult};
4use castep_cell_fmt::parse::FromKeyValue;
5use castep_cell_fmt::query::value_as_str;
6use castep_cell_fmt::Error;
7
8/// Specifies whether or not to write checkpoint files and controls the level of detail.
9///
10/// Keyword type: String
11///
12/// Default: WriteCheckpoint { action: WriteCheckpointAction::All, option: None }
13///
14/// Example:
15/// WRITE_CHECKPOINT : SUCCESS=BOTH
16/// WRITE_CHECKPOINT : MINIMAL
17#[derive(Debug, Clone, PartialEq, Eq)]
18pub struct WriteCheckpoint {
19    /// The main action/specifier.
20    pub action: WriteCheckpointAction,
21    /// Optional fine control for success, failure, or backup.
22    pub option: Option<WriteCheckpointOption>,
23}
24
25/// The main action or specifier for WRITE_CHECKPOINT.
26#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
27pub enum WriteCheckpointAction {
28    /// Do not write checkpoint files.
29    None,
30    /// Write minimal checkpoint files (alias for Both).
31    Minimal,
32    /// Write both .check and .castep_bin files (alias for Minimal).
33    Both,
34    /// Write all available checkpoint data (alias for Full).
35    All,
36    /// Write all available checkpoint data (alias for All).
37    Full,
38}
39
40/// Options for fine control (SUCCESS=, FAILURE=, BACKUP=).
41#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
42pub enum WriteCheckpointOption {
43    /// Optional fine control for success termination.
44    Success(WriteCheckpointAction),
45    /// Optional fine control for failure termination.
46    Failure(WriteCheckpointAction),
47    /// Optional fine control for periodic backup.
48    Backup(WriteCheckpointAction),
49}
50
51impl Default for WriteCheckpoint {
52    fn default() -> Self {
53        Self {
54            action: WriteCheckpointAction::All, // Default is ALL
55            option: None,
56        }
57    }
58}
59
60impl FromKeyValue for WriteCheckpoint {
61    const KEY_NAME: &'static str = "WRITE_CHECKPOINT";
62
63    fn from_cell_value_kv(value: &CellValue<'_>) -> CResult<Self> {
64        let s = value_as_str(value)?;
65
66        if let Some((option_type, option_value)) = s.split_once('=') {
67            let action = parse_action(option_value.trim())?;
68            let option = match option_type.trim().to_ascii_uppercase().as_str() {
69                "SUCCESS" => Some(WriteCheckpointOption::Success(action)),
70                "FAILURE" => Some(WriteCheckpointOption::Failure(action)),
71                "BACKUP" => Some(WriteCheckpointOption::Backup(action)),
72                other => return Err(Error::Message(format!("unknown WriteCheckpoint option: {other}"))),
73            };
74            Ok(Self {
75                action: WriteCheckpointAction::All,
76                option,
77            })
78        } else {
79            let action = parse_action(s)?;
80            Ok(Self {
81                action,
82                option: None,
83            })
84        }
85    }
86}
87
88fn parse_action(s: &str) -> CResult<WriteCheckpointAction> {
89    match s.to_ascii_uppercase().as_str() {
90        "NONE" => Ok(WriteCheckpointAction::None),
91        "MINIMAL" => Ok(WriteCheckpointAction::Minimal),
92        "BOTH" => Ok(WriteCheckpointAction::Both),
93        "ALL" => Ok(WriteCheckpointAction::All),
94        "FULL" => Ok(WriteCheckpointAction::Full),
95        other => Err(Error::Message(format!("unknown WriteCheckpointAction: {other}"))),
96    }
97}
98
99impl ToCell for WriteCheckpoint {
100    fn to_cell(&self) -> Cell<'_> {
101        // Construct the string value based on the struct fields.
102        let action_str = match self.action {
103            WriteCheckpointAction::None => "NONE",
104            WriteCheckpointAction::Minimal => "MINIMAL",
105            WriteCheckpointAction::Both => "BOTH",
106            WriteCheckpointAction::All => "ALL",
107            WriteCheckpointAction::Full => "FULL",
108        };
109
110        if let Some(option) = &self.option {
111            let (option_prefix, option_action) = match option {
112                WriteCheckpointOption::Success(a) => ("SUCCESS", a),
113                WriteCheckpointOption::Failure(a) => ("FAILURE", a),
114                WriteCheckpointOption::Backup(a) => ("BACKUP", a),
115            };
116            let option_action_str = match option_action {
117                WriteCheckpointAction::None => "NONE",
118                WriteCheckpointAction::Minimal => "MINIMAL",
119                WriteCheckpointAction::Both => "BOTH",
120                WriteCheckpointAction::All => "ALL",
121                WriteCheckpointAction::Full => "FULL",
122            };
123            let full_value = format!("{option_prefix}={option_action_str}");
124            Cell::KeyValue("WRITE_CHECKPOINT", CellValue::String(full_value))
125        } else {
126            // If no option, just serialize the action
127            Cell::KeyValue(
128                "WRITE_CHECKPOINT",
129                CellValue::String(action_str.to_string()),
130            )
131        }
132    }
133}
134
135impl ToCellValue for WriteCheckpoint {
136    fn to_cell_value(&self) -> CellValue<'_> {
137        let action_str = match self.action {
138            WriteCheckpointAction::None => "NONE",
139            WriteCheckpointAction::Minimal => "MINIMAL",
140            WriteCheckpointAction::Both => "BOTH",
141            WriteCheckpointAction::All => "ALL",
142            WriteCheckpointAction::Full => "FULL",
143        };
144
145        if let Some(option) = &self.option {
146            let (option_prefix, option_action) = match option {
147                WriteCheckpointOption::Success(a) => ("SUCCESS", a),
148                WriteCheckpointOption::Failure(a) => ("FAILURE", a),
149                WriteCheckpointOption::Backup(a) => ("BACKUP", a),
150            };
151            let option_action_str = match option_action {
152                WriteCheckpointAction::None => "NONE",
153                WriteCheckpointAction::Minimal => "MINIMAL",
154                WriteCheckpointAction::Both => "BOTH",
155                WriteCheckpointAction::All => "ALL",
156                WriteCheckpointAction::Full => "FULL",
157            };
158            CellValue::String(format!("{option_prefix}={option_action_str}"))
159        } else {
160            CellValue::String(action_str.to_string())
161        }
162    }
163}
164