rate-guard 0.1.0

Thread-safe rate limiting library with multiple algorithms and Duration-based configuration
Documentation
//! Error types for rate limiting operations with Duration-based retry timing.
//!
//! This module provides error types that convert core verbose errors to
//! Duration-based retry timing for easy integration with async ecosystems.
//! It also includes builder-specific errors for configuration validation.

use std::time::Duration;
use crate::types::{Uint, VerboseRateLimitError};

/// Verbose error type with detailed diagnostic information and Duration-based retry timing.
///
/// This error type provides comprehensive information about rate limiting failures,
/// including current state and retry timing information. The retry timing is
/// provided as a standard Duration for easy integration with async ecosystems.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RateLimitError {
    /// Not enough tokens available to fulfill the request.
    InsufficientCapacity {
        /// Number of tokens requested in the failed operation.
        acquiring: Uint,
        /// Number of tokens currently available in the rate limiter.
        available: Uint,
        /// Duration to wait before retrying the operation.
        retry_after: Duration,
    },

    /// The requested number of tokens exceeds the maximum capacity.
    BeyondCapacity {
        /// Number of tokens requested in the failed operation.
        acquiring: Uint,
        /// Maximum capacity of the rate limiter.
        capacity: Uint,
    },

    /// The provided tick is older than the acceptable minimum.
    ExpiredTick {
        /// Minimum acceptable tick value for the rate limiter.
        min_acceptable_tick: Uint,
    },

    /// Failed to acquire the internal lock due to contention.
    ContentionFailure,
}

/// Error type for builder configuration validation.
///
/// This error occurs when attempting to build a rate limiter with incomplete
/// or invalid configuration. All required parameters must be specified and valid
/// before calling `build()`.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum BuildError {
    /// A required argument is missing.
    MissingArgument(&'static str),
    /// An argument has an invalid value or invalid combination with other arguments.
    InvalidArgument { 
        field: &'static str, 
        reason: &'static str 
    },
}

/// Result type for rate limiting operations with Duration-based retry timing.
pub type RateLimitResult<T = ()> = Result<T, RateLimitError>;

/// Result type for builder operations.
pub type BuildResult<T> = Result<T, BuildError>;

impl RateLimitError {
    /// Creates a RateLimitError from a core verbose error.
    ///
    /// This method converts core verbose errors to high-level errors,
    /// with tick-to-Duration conversion using the provided converter function.
    pub fn from_core_error<F>(
        error: VerboseRateLimitError,
        tick_to_duration: F,
    ) -> Self
    where
        F: FnOnce(Uint) -> Duration,
    {
        match error {
            VerboseRateLimitError::InsufficientCapacity { 
                acquiring, 
                available, 
                retry_after_ticks 
            } => {
                RateLimitError::InsufficientCapacity {
                    acquiring,
                    available,
                    retry_after: tick_to_duration(retry_after_ticks),
                }
            }
            VerboseRateLimitError::BeyondCapacity { acquiring, capacity } => {
                RateLimitError::BeyondCapacity { acquiring, capacity }
            }
            VerboseRateLimitError::ExpiredTick { min_acceptable_tick } => {
                RateLimitError::ExpiredTick { min_acceptable_tick }
            }
            VerboseRateLimitError::ContentionFailure => {
                RateLimitError::ContentionFailure
            }
        }
    }
}

// Display implementations for RateLimitError
impl std::fmt::Display for RateLimitError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            RateLimitError::InsufficientCapacity { acquiring, available, retry_after } => {
                write!(
                    f,
                    "Insufficient capacity: requested {}, available {}, retry after {:?}",
                    acquiring, available, retry_after
                )
            }
            RateLimitError::BeyondCapacity { acquiring, capacity } => {
                write!(
                    f,
                    "Request exceeds capacity: requested {}, maximum {}",
                    acquiring, capacity
                )
            }
            RateLimitError::ExpiredTick { min_acceptable_tick } => {
                write!(
                    f,
                    "Expired tick: minimum acceptable tick is {}",
                    min_acceptable_tick
                )
            }
            RateLimitError::ContentionFailure => {
                write!(f, "Rate limiter lock contention")
            }
        }
    }
}

// Display implementations for BuildError
impl std::fmt::Display for BuildError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            BuildError::MissingArgument(arg) => {
                write!(f, "Missing required argument: {}", arg)
            }
            BuildError::InvalidArgument { field, reason } => {
                write!(f, "Invalid argument '{}': {}", field, reason)
            }
        }
    }
}

// Error trait implementations
impl std::error::Error for RateLimitError {}
impl std::error::Error for BuildError {}