qubit-fs 0.2.1

Provider-neutral synchronous and asynchronous filesystem abstraction for Rust
Documentation
// =============================================================================
//    Copyright (c) 2026 Haixing Hu.
//
//    SPDX-License-Identifier: Apache-2.0
//
//    Licensed under the Apache License, Version 2.0.
// =============================================================================
// facade tests.
//! Successful temporary resource persistence outcome.

use super::PersistCleanupState;
use crate::metadata::AchievedAtomicity;
use crate::metadata::NonSensitiveMetadata;
use crate::metadata::PublicationMethod;
use crate::metadata::UserMetadata;
use crate::path::Path;

/// Confirmed result of publishing a temporary source to its final target.
///
/// # Examples
///
/// ```rust
/// use qubit_fs::metadata::{AchievedAtomicity, PublicationMethod};
/// use qubit_fs::path::Path;
/// use qubit_fs::temp::PersistOutcome;
///
/// let outcome = PersistOutcome::new(
///     Path::parse("/published")?,
///     AchievedAtomicity::Atomic,
///     PublicationMethod::Direct,
/// );
/// assert_eq!("/published", outcome.target().as_str());
/// # Ok::<(), qubit_fs::FsError>(())
/// ```
#[derive(Clone, Debug, PartialEq)]
pub struct PersistOutcome {
    /// Final provider-local target path.
    target: Path,
    /// Atomicity actually achieved by publication.
    atomicity: AchievedAtomicity,
    /// Concrete publication method used.
    method: PublicationMethod,
    /// Provider-native non-sensitive diagnostics.
    diagnostics: NonSensitiveMetadata,
    /// Cleanup state of the private temporary container.
    cleanup_state: PersistCleanupState,
}

impl PersistOutcome {
    /// Creates a confirmed persistence outcome.
    ///
    /// # Parameters
    /// - `target`: Final target path.
    /// - `atomicity`: Atomicity actually achieved.
    /// - `method`: Method used to publish the target.
    ///
    /// # Returns
    /// An outcome without provider diagnostics.
    #[inline]
    #[must_use]
    pub fn new(target: Path, atomicity: AchievedAtomicity, method: PublicationMethod) -> Self {
        Self {
            target,
            atomicity,
            method,
            diagnostics: NonSensitiveMetadata::new(),
            cleanup_state: PersistCleanupState::Complete,
        }
    }

    /// Returns the final provider-local target path.
    #[inline]
    #[must_use]
    pub const fn target(&self) -> &Path {
        &self.target
    }

    /// Returns the atomicity actually achieved by publication.
    #[inline]
    #[must_use]
    pub const fn atomicity(&self) -> AchievedAtomicity {
        self.atomicity
    }

    /// Returns the concrete publication method used.
    #[inline]
    #[must_use]
    pub const fn method(&self) -> PublicationMethod {
        self.method
    }

    /// Returns provider-native non-sensitive diagnostics.
    #[inline]
    #[must_use]
    pub const fn diagnostics(&self) -> &NonSensitiveMetadata {
        &self.diagnostics
    }

    /// Returns the state of the private temporary container after publication.
    #[inline]
    pub const fn cleanup_state(&self) -> PersistCleanupState {
        self.cleanup_state
    }

    /// Replaces the cleanup state reported by the provider.
    #[inline]
    #[must_use]
    pub fn with_cleanup_state(mut self, cleanup_state: PersistCleanupState) -> Self {
        self.cleanup_state = cleanup_state;
        self
    }

    /// Replaces provider-native diagnostics that have already passed key
    /// validation.
    #[inline]
    #[must_use]
    pub fn with_diagnostics(mut self, diagnostics: UserMetadata) -> Self {
        self.diagnostics = NonSensitiveMetadata::from(diagnostics);
        self
    }
}

#[cfg(test)]
mod tests {
    use super::PersistOutcome;
    use crate::metadata::AchievedAtomicity;
    use crate::metadata::PublicationMethod;
    use crate::metadata::UserMetadata;
    use crate::path::Path;
    use crate::temp::PersistCleanupState;

    #[test]
    fn outcome_accessors_are_executed_at_runtime() {
        let target = Path::parse("/target").expect("valid target path");
        let outcome = PersistOutcome::new(target.clone(), AchievedAtomicity::Atomic, PublicationMethod::Direct)
            .with_cleanup_state(PersistCleanupState::ResidualTemporaryContainer)
            .with_diagnostics(UserMetadata::new());

        assert_eq!(outcome.target(), &target);
        assert_eq!(outcome.atomicity(), AchievedAtomicity::Atomic);
        assert_eq!(outcome.method(), PublicationMethod::Direct);
        assert_eq!(outcome.cleanup_state(), PersistCleanupState::ResidualTemporaryContainer);
        assert!(outcome.diagnostics().is_empty());
    }
}