Skip to main content

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}