Skip to main content

qubit_fs/write/
async_write_all_operation_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//! Failure for an owning asynchronous whole-file write.
9use std::error::Error;
10use std::fmt::Display;
11use std::fmt::Formatter;
12
13use crate::error::FsError;
14use crate::write::WriteFailureState;
15/// Error returned by an owning asynchronous whole-file write.
16///
17/// Recovery ownership remains in the operation even when this error is
18/// consumed.
19///
20/// # Examples
21/// ```rust
22/// # mod support { include!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/common/rustdoc_support.rs")); }
23/// # use support::*;
24/// # let (filesystem, _) = async_recording_spi::async_recording_file_system(async_recording_spi::AsyncRecordingConfig {
25/// #     writer_commit_failure: Some(qubit_fs::write::WriteFailureState::NotPublished),
26/// #     ..Default::default()
27/// # });
28/// # poll_support::ready(async {
29/// use qubit_fs::Path;
30/// use qubit_fs::write::WriteOptions;
31/// use qubit_fs::write::AsyncWriterRecovery;
32/// use qubit_fs::write::WriteFailureState;
33/// let mut operation = filesystem.begin_write_all(
34///     Path::parse("/report")?, b"bytes".to_vec(), WriteOptions::default(),
35/// )?;
36/// let failure = operation.execute().await.expect_err("fixture commit failure");
37/// assert_eq!(WriteFailureState::NotPublished, failure.state());
38/// assert_eq!(5, failure.written_bytes());
39/// assert!(operation.has_recovery());
40/// let cleanup = match operation.recovery().expect("retained session") {
41///     AsyncWriterRecovery::Opened(writer) => writer.abort_async().await,
42///     AsyncWriterRecovery::Rejected(writer) => writer.abort_async().await,
43/// };
44/// assert!(cleanup.is_ok());
45/// // Application error handling can retain `failure`, `cleanup`, and `operation`.
46/// # Ok::<(), Box<dyn std::error::Error>>(())
47/// # }).unwrap();
48/// ```
49#[must_use]
50pub struct AsyncWriteAllOperationFailure {
51    /// Original contextual error.
52    error: FsError,
53    /// Publication facts at failure.
54    state: WriteFailureState,
55    /// Bytes acknowledged by completed writes.
56    written_bytes: u64,
57}
58impl AsyncWriteAllOperationFailure {
59    /// Creates a failure with its recovery facts.
60    pub(crate) fn new(error: FsError, state: WriteFailureState, written_bytes: u64) -> Self {
61        Self {
62            error,
63            state,
64            written_bytes,
65        }
66    }
67    /// Returns the contextual filesystem error.
68    #[must_use]
69    pub const fn error(&self) -> &FsError {
70        &self.error
71    }
72    /// Returns the publication facts recorded when execution stopped.
73    #[must_use]
74    pub const fn state(&self) -> WriteFailureState {
75        self.state
76    }
77    /// Returns bytes acknowledged by completed writes before execution stopped.
78    #[must_use]
79    pub const fn written_bytes(&self) -> u64 {
80        self.written_bytes
81    }
82    /// Consumes the failure and returns its filesystem error.
83    ///
84    /// This discards publication state and confirmed byte count. The operation
85    /// still owns any recovery writer; prefer `into_parts` when recovering.
86    #[must_use]
87    pub fn into_error(self) -> FsError {
88        self.error
89    }
90    /// Consumes the failure and returns all recovery facts.
91    #[must_use]
92    pub fn into_parts(self) -> (FsError, WriteFailureState, u64) {
93        (self.error, self.state, self.written_bytes)
94    }
95}
96impl Display for AsyncWriteAllOperationFailure {
97    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
98        self.error.fmt(f)
99    }
100}
101impl std::fmt::Debug for AsyncWriteAllOperationFailure {
102    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
103        f.debug_struct("AsyncWriteAllOperationFailure")
104            .field("error", &self.error)
105            .field("state", &self.state)
106            .field("written_bytes", &self.written_bytes)
107            .finish()
108    }
109}
110impl Error for AsyncWriteAllOperationFailure {
111    fn source(&self) -> Option<&(dyn Error + 'static)> {
112        Some(&self.error)
113    }
114}