Skip to main content

qubit_fs/spi/
spi_copy_failure.rs

1// =============================================================================
2//    Copyright (c) 2026 Haixing Hu.
3//
4//    SPDX-License-Identifier: Apache-2.0
5//
6//    Licensed under the Apache License, Version 2.0.
7// =============================================================================
8// facade.
9//! Provider copy failure facts.
10
11use crate::copy::CopyFailureState;
12use crate::copy::CopyStats;
13use crate::error::FsError;
14
15/// Typed provider copy failure reserved for copy orchestration.
16///
17/// # Examples
18///
19/// ```rust
20/// use qubit_fs::copy::CopyFailureState;
21/// use qubit_fs::copy::CopyStats;
22/// use qubit_fs::error::{FsError, FsErrorKind, FsOperation};
23/// use qubit_fs::spi::SpiCopyFailure;
24///
25/// let failure = SpiCopyFailure::new(
26///     FsError::new(FsErrorKind::Io, FsOperation::Copy, "failed"),
27///     CopyFailureState::Unchanged,
28///     CopyStats::default(),
29/// );
30/// assert_eq!(CopyFailureState::Unchanged, failure.state());
31/// ```
32pub struct SpiCopyFailure {
33    /// Provider failure with filesystem context.
34    error: Box<FsError>,
35    /// Provider-confirmed destination publication state.
36    state: CopyFailureState,
37    /// Transfer progress confirmed before failure.
38    partial_stats: CopyStats,
39}
40
41impl SpiCopyFailure {
42    /// Creates a typed provider copy failure.
43    ///
44    /// # Parameters
45    /// - `error`: Provider failure with filesystem context.
46    /// - `state`: Provider-confirmed publication state.
47    /// - `partial_stats`: Transfer progress confirmed before failure.
48    ///
49    /// # Returns
50    /// A failure containing all provider-confirmed facts.
51    #[inline]
52    #[must_use]
53    pub fn new(error: FsError, state: CopyFailureState, partial_stats: CopyStats) -> Self {
54        Self {
55            error: Box::new(error),
56            state,
57            partial_stats,
58        }
59    }
60
61    /// Returns the provider error without exposing a recovery writer.
62    ///
63    /// # Returns
64    /// The provider failure with filesystem context.
65    #[inline]
66    #[must_use]
67    pub fn error(&self) -> &FsError {
68        &self.error
69    }
70
71    /// Returns the typed publication state.
72    ///
73    /// # Returns
74    /// The provider-confirmed publication state.
75    #[inline]
76    #[must_use]
77    pub const fn state(&self) -> CopyFailureState {
78        self.state
79    }
80
81    /// Splits this failure into its typed facts.
82    ///
83    /// # Returns
84    /// The provider error, publication state, and partial transfer statistics.
85    #[inline]
86    #[must_use]
87    pub fn into_parts(self) -> (FsError, CopyFailureState, CopyStats) {
88        (*self.error, self.state, self.partial_stats)
89    }
90}
91
92#[cfg(test)]
93mod tests {
94    use super::SpiCopyFailure;
95    use crate::copy::CopyFailureState;
96    use crate::copy::CopyStats;
97    use crate::error::FsError;
98    use crate::error::FsErrorKind;
99    use crate::error::FsOperation;
100
101    #[test]
102    fn failure_facts_are_executed_at_runtime() {
103        let failure = SpiCopyFailure::new(
104            FsError::new(FsErrorKind::NotFound, FsOperation::Copy, "missing source"),
105            CopyFailureState::PartiallyPublished,
106            CopyStats {
107                bytes: 4,
108                ..CopyStats::default()
109            },
110        );
111        assert_eq!(failure.error().kind(), FsErrorKind::NotFound);
112        assert_eq!(failure.state(), CopyFailureState::PartiallyPublished);
113
114        let (error, state, stats) = failure.into_parts();
115        assert_eq!(error.kind(), FsErrorKind::NotFound);
116        assert_eq!(state, CopyFailureState::PartiallyPublished);
117        assert_eq!(stats.bytes, 4);
118    }
119}