Skip to main content

qubit_fs/temp/
persist_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//! Typed temporary persistence failure.
9
10use std::error::Error;
11use std::fmt::Display;
12use std::fmt::Formatter;
13use std::fmt::Result as FmtResult;
14
15use crate::error::FsError;
16use crate::path::Path;
17use crate::temp::PersistFailureState;
18
19/// Persistence error paired with provider-confirmed partial progress.
20///
21/// # Examples
22///
23/// ```rust
24/// use qubit_fs::error::{FsError, FsErrorKind, FsOperation};
25/// use qubit_fs::temp::{PersistFailure, PersistFailureState};
26///
27/// let failure = PersistFailure::new(
28///     FsError::new(FsErrorKind::Io, FsOperation::PersistTemp, "failed"),
29///     PersistFailureState::NotPublished,
30/// );
31/// assert_eq!(PersistFailureState::NotPublished, failure.state());
32/// ```
33#[derive(Debug)]
34pub struct PersistFailure {
35    /// Contextual filesystem error that interrupted persistence.
36    error: FsError,
37    /// Provider-confirmed source and destination progress.
38    state: PersistFailureState,
39    /// Destination path retained when publication reached a known target.
40    publication_target: Option<Path>,
41}
42
43impl PersistFailure {
44    /// Creates a typed persistence failure.
45    ///
46    /// # Parameters
47    /// - `error`: Underlying filesystem failure.
48    /// - `state`: Confirmed source and target progress.
49    ///
50    /// # Returns
51    /// A failure preserving both the cause and recovery contract.
52    #[inline]
53    #[must_use]
54    pub fn new(error: FsError, state: PersistFailureState) -> Self {
55        Self {
56            error,
57            state,
58            publication_target: None,
59        }
60    }
61
62    /// Retains the destination associated with a known publication attempt.
63    pub(crate) fn with_publication_target(mut self, target: Option<&Path>) -> Self {
64        self.publication_target = target.cloned();
65        self
66    }
67
68    /// Returns provider-confirmed partial progress.
69    ///
70    /// # Returns
71    /// The recovery state for this persist attempt.
72    #[inline]
73    #[must_use]
74    pub const fn state(&self) -> PersistFailureState {
75        self.state
76    }
77
78    /// Returns the underlying filesystem error.
79    ///
80    /// # Returns
81    /// The error with operation, path, provider, and source context.
82    #[inline]
83    #[must_use]
84    pub const fn error(&self) -> &FsError {
85        &self.error
86    }
87
88    /// Returns the target associated with the retained recovery fact.
89    #[inline]
90    #[must_use]
91    pub fn publication_target(&self) -> Option<&Path> {
92        self.publication_target.as_ref()
93    }
94
95    /// Consumes this failure and returns the underlying filesystem error.
96    ///
97    /// # Returns
98    /// The owned filesystem error.
99    #[inline]
100    #[must_use]
101    pub fn into_error(self) -> FsError {
102        self.error
103    }
104
105    /// Splits this facade failure into its causal error and state.
106    #[inline]
107    #[must_use]
108    pub fn into_parts(self) -> (FsError, PersistFailureState) {
109        (self.error, self.state)
110    }
111
112    /// Consumes the failure and returns its complete recovery snapshot.
113    #[inline]
114    #[must_use]
115    pub fn into_recovery_parts(self) -> (FsError, PersistFailureState, Option<Path>) {
116        (self.error, self.state, self.publication_target)
117    }
118}
119
120impl Display for PersistFailure {
121    #[inline]
122    fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult {
123        write!(formatter, "persist {:?}: {}", self.state, self.error)
124    }
125}
126
127impl Error for PersistFailure {
128    #[inline]
129    fn source(&self) -> Option<&(dyn Error + 'static)> {
130        Some(&self.error)
131    }
132}