ic-backup 0.63.0

Host-side snapshot backup and same-release recovery for Internet Computer canisters
Documentation
//! Exact original Applied receipt admission; callers keep domain work before recording.

use crate::{
    model::attempt_journal::{MutationOutcomeRecord, MutationReceiptRequest},
    ops::persistence::{AttemptJournalError, AttemptJournalGuard},
};

// Domain preparation runs after exact receipt matching and before recording.
// Download uses it to append bytes; restore uses it to re-admit source custody.
pub(super) fn record_applied<T, E: From<AttemptJournalError>>(
    journal: &mut AttemptJournalGuard<'_>,
    receipt: MutationReceiptRequest,
    expected_attempt: u32,
    expected_request: &str,
    mismatch: E,
    prepare: impl FnOnce() -> Result<T, E>,
) -> Result<T, E> {
    if receipt.outcome != MutationOutcomeRecord::Applied
        || receipt.attempt != expected_attempt
        || receipt.request.hash() != expected_request
    {
        return Err(mismatch);
    }
    let result = prepare()?;
    journal.record_mutation(receipt)?;
    Ok(result)
}

// Keep the bounded returned reply available on every post-reply rejection.
pub(super) fn retain_reply<R, T, E, X>(
    reply: R,
    result: Result<T, E>,
    reject: impl FnOnce(E, Box<R>) -> X,
) -> Result<(R, T), X> {
    match result {
        Ok(value) => Ok((reply, value)),
        Err(source) => Err(reject(source, Box::new(reply))),
    }
}

#[cfg(all(test, unix))]
mod tests;