Skip to main content

queue_file/
error.rs

1//! Error types and utilities for [`QueueFile`] operations.
2//!
3//! This module provides the [`Error`] enum which represents all possible errors
4//! that can occur during queue file operations, along with the [`Result`] type
5//! alias and helper macros.
6//!
7//! # Error Categories
8//!
9//! - **I/O Errors**: File system and read/write failures
10//! - **Validation Errors**: Corrupted files, invalid data, sequence mismatches
11//! - **Capacity Errors**: Element too big, too many elements
12//! - **Format Errors**: Unsupported versions, magic mismatches
13
14use std::io;
15
16use thiserror::Error;
17
18/// The error type for [`QueueFile`] operations.
19///
20/// Each variant represents a distinct category of failure that can occur
21/// when working with queue files.
22#[derive(Debug, Error)]
23pub enum Error {
24    /// An I/O error occurred while reading or writing the queue file.
25    #[error(transparent)]
26    Io {
27        #[from]
28        source: io::Error,
29    },
30
31    /// The queue contains more than `i32::MAX` elements.
32    ///
33    /// This is a limitation of the on-disk format.
34    #[error("too many elements")]
35    TooManyElements,
36
37    /// An individual element exceeds the maximum allowed size.
38    ///
39    /// Elements are limited to `i32::MAX` bytes.
40    #[error("element too big")]
41    ElementTooBig,
42
43    /// The queue file contains corrupted data.
44    ///
45    /// This can indicate a hardware failure, incomplete write, or
46    /// manual tampering with the file.
47    #[error("corrupted file: {msg}")]
48    CorruptedFile { msg: String },
49
50    /// The file header magic bytes don't match the expected format.
51    #[error("magic mismatch: expected {expected:#010x}, found {found:#010x}")]
52    MagicMismatch { expected: u32, found: u32 },
53
54    /// A CRC-32 checksum verification failed.
55    ///
56    /// This indicates data corruption in the element header or payload.
57    #[error("checksum mismatch: expected {expected:#010x}, found {found:#010x}")]
58    ChecksumMismatch { expected: u32, found: u32 },
59
60    /// A value in the queue file is invalid or out of expected range.
61    #[error("invalid value: {msg}")]
62    InvalidValue { msg: String },
63
64    /// A calculated position is outside the valid file bounds.
65    #[error("out of bounds: {msg}")]
66    OutOfBounds { msg: String },
67
68    /// Element sequence numbers are not in the expected order.
69    ///
70    /// This indicates a corrupted queue or recovery failure in v2 format.
71    #[error("sequence mismatch: expected {expected}, found {found}")]
72    SequenceMismatch { expected: u64, found: u64 },
73
74    /// The queue file format version is not supported.
75    #[error("unsupported version {detected}. supported versions is {supported} and legacy")]
76    UnsupportedVersion { detected: u32, supported: u32 },
77}
78
79/// A specialized [`Result`] type for [`QueueFile`] operations.
80/// The result type for queue file operations, with [`Error`] as the default error type.
81pub type Result<T, E = Error> = std::result::Result<T, E>;
82
83/// Ensures that a condition is true, returning an error if it is not.
84///
85/// This macro provides a convenient way to validate preconditions
86/// and invariants within [`QueueFile`] methods.
87///
88/// # Variants
89///
90/// - `ensure!(condition, VariantName { field: value })` - creates error with fields
91/// - `ensure!(condition, VariantName)` - creates error with no fields
92/// - `ensure!(condition, expression)` - uses the provided expression as error
93#[macro_export]
94macro_rules! ensure {
95    ($cond:expr, $variant:ident { $($field:ident : $val:expr),* $(,)? }) => {
96        if !($cond) {
97            return Err($crate::Error::$variant { $($field : $val),* });
98        }
99    };
100    ($cond:expr, $variant:ident) => {
101        if !($cond) {
102            return Err($crate::Error::$variant);
103        }
104    };
105    ($cond:expr, $err:expr) => {
106        if !($cond) {
107            return Err($err);
108        }
109    };
110}
111
112/// Injects a test failure at the given failpoint if the environment variable is set.
113///
114/// This function is used for testing crash recovery and atomicity guarantees.
115/// When `QUEUE_FILE_FAILPOINT` environment variable matches the failpoint name,
116/// the function returns an error, simulating a crash at that point.
117///
118/// This is only available in test builds for safety reasons.
119#[inline]
120pub fn maybe_inject_failpoint(name: &str) -> Result<()> {
121    if std::env::var("QUEUE_FILE_FAILPOINT").ok().as_deref() == Some(name) {
122        return Err(Error::CorruptedFile { msg: format!("injected failpoint: {name}") });
123    }
124
125    Ok(())
126}