qubit-retry 0.3.1

Retry module, providing a feature-complete, type-safe retry management system with support for multiple delay strategies and event listeners
Documentation
/*******************************************************************************
 *
 *    Copyright (c) 2025 - 2026.
 *    Haixing Hu, Qubit Co. Ltd.
 *
 *    All rights reserved.
 *
 ******************************************************************************/
//! Attempt-level failure values.
//!
//! This module distinguishes application errors returned by user operations
//! from timeout failures generated by the retry runtime itself.

use std::fmt;
use std::time::Duration;

/// Failure produced by a single attempt.
///
/// The generic parameter `E` is the caller's original application error type.
/// Timeout failures do not contain an `E` value because they are produced by
/// the retry executor while waiting for an asynchronous attempt.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AttemptFailure<E> {
    /// The operation returned an application error.
    Error(E),

    /// An async attempt exceeded the timeout passed to
    /// [`crate::RetryExecutor::run_async_with_timeout`].
    AttemptTimeout {
        /// Time observed by the retry executor for this attempt.
        elapsed: Duration,
        /// Configured timeout for one attempt.
        timeout: Duration,
    },
}

impl<E> AttemptFailure<E> {
    /// Returns the application error when this failure wraps one.
    ///
    /// # Parameters
    /// This method has no parameters.
    ///
    /// # Returns
    /// `Some(&E)` for [`AttemptFailure::Error`], or `None` for
    /// [`AttemptFailure::AttemptTimeout`].
    ///
    /// # Errors
    /// This method does not return errors.
    #[inline]
    pub fn as_error(&self) -> Option<&E> {
        match self {
            Self::Error(error) => Some(error),
            Self::AttemptTimeout { .. } => None,
        }
    }

    /// Consumes the failure and returns the application error when present.
    ///
    /// # Parameters
    /// This method has no parameters.
    ///
    /// # Returns
    /// `Some(E)` for [`AttemptFailure::Error`], or `None` for
    /// [`AttemptFailure::AttemptTimeout`].
    ///
    /// # Errors
    /// This method does not return errors.
    #[inline]
    pub fn into_error(self) -> Option<E> {
        match self {
            Self::Error(error) => Some(error),
            Self::AttemptTimeout { .. } => None,
        }
    }
}

impl<E> fmt::Display for AttemptFailure<E>
where
    E: fmt::Display,
{
    /// Formats the failure for diagnostics.
    ///
    /// # Parameters
    /// - `f`: Formatter provided by the standard formatting machinery.
    ///
    /// # Returns
    /// `fmt::Result` from the formatter.
    ///
    /// # Errors
    /// Returns a formatting error if the underlying formatter fails.
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Error(error) => write!(f, "{error}"),
            Self::AttemptTimeout { elapsed, timeout } => {
                write!(
                    f,
                    "attempt timed out after {elapsed:?}; timeout was {timeout:?}"
                )
            }
        }
    }
}