crate_seq_ledger/io.rs
1//! TOML file load and atomic save for `.crate-seq.toml`.
2
3use std::path::Path;
4
5use crate::{CrateSeqLedger, Error};
6
7/// Reads a ledger from `path`, deserializing TOML into [`CrateSeqLedger`].
8///
9/// # Errors
10///
11/// Returns [`Error::Io`] if the file cannot be read, or [`Error::Deserialize`]
12/// if the content is not valid ledger TOML.
13pub fn load(path: &Path) -> Result<CrateSeqLedger, Error> {
14 let content = std::fs::read_to_string(path)?;
15 let ledger = toml_edit::de::from_str::<CrateSeqLedger>(&content)?;
16 Ok(ledger)
17}
18
19/// Serializes `ledger` to TOML and writes it to `path` atomically.
20///
21/// Writes to a `.tmp` sibling first, then renames to avoid partial writes.
22/// Removes the `.tmp` file if the rename fails.
23///
24/// # Errors
25///
26/// Returns [`Error::Serialize`] if serialization fails, or [`Error::Io`] if
27/// the write or rename fails.
28pub fn save(path: &Path, ledger: &CrateSeqLedger) -> Result<(), Error> {
29 let serialized = toml_edit::ser::to_string_pretty(ledger)?;
30 let tmp = path.with_extension("tmp");
31 std::fs::write(&tmp, &serialized)?;
32 if let Err(rename_err) = std::fs::rename(&tmp, path) {
33 // Best-effort cleanup; ignore secondary error.
34 let _ = std::fs::remove_file(&tmp);
35 return Err(Error::Io(rename_err));
36 }
37 Ok(())
38}