Skip to main content

qubit_redact/policy/
policy_error.rs

1// =============================================================================
2//    Copyright (c) 2025 - 2026 Haixing Hu.
3//
4//    SPDX-License-Identifier: Apache-2.0
5//
6//    Licensed under the Apache License, Version 2.0.
7// =============================================================================
8//! Errors reported while building a redaction policy.
9
10use std::error::Error;
11use std::fmt;
12
13use super::PolicyLocation;
14use super::Sensitivity;
15
16/// Error returned when a redaction policy contains an invalid rule.
17///
18/// # Examples
19///
20/// ```
21/// use qubit_redact::{PolicyError, RedactionPolicy, Sensitivity};
22///
23/// let error = RedactionPolicy::builder()
24///     .fields(|fields| {
25///         fields.raise("", Sensitivity::Secret);
26///     })
27///     .expect_err("an empty field name is invalid");
28/// assert!(matches!(error, PolicyError::EmptyFieldName { .. }));
29/// ```
30#[non_exhaustive]
31#[derive(Debug, Clone, PartialEq, Eq)]
32#[must_use]
33pub enum PolicyError {
34    /// A supplied field name is empty after canonicalization.
35    EmptyFieldName {
36        /// Location where the invalid field was configured.
37        location: PolicyLocation,
38    },
39    /// A fixed mask has an empty replacement at the indicated level.
40    EmptyFixedReplacement {
41        /// Location where the fixed mask was configured.
42        location: PolicyLocation,
43        /// Sensitivity level containing the invalid fixed mask.
44        level: Sensitivity,
45    },
46    /// The configured output ceiling cannot be represented by Rust's
47    /// collection allocators on this platform.
48    OutputLimitTooLarge {
49        /// Rejected configured output limit.
50        maximum: usize,
51    },
52    /// The logical Serde payload ceiling exceeds addressable capacity.
53    #[cfg(feature = "serde")]
54    SerdePayloadLimitTooLarge {
55        /// Rejected configured scalar payload limit.
56        maximum: usize,
57    },
58}
59
60impl fmt::Display for PolicyError {
61    /// Formats a concise description of the invalid policy configuration.
62    ///
63    /// # Parameters
64    ///
65    /// * `formatter` - Destination formatting context.
66    ///
67    /// # Returns
68    ///
69    /// The formatter result from writing the error description.
70    ///
71    /// # Errors
72    ///
73    /// Returns [`fmt::Error`] when the destination rejects a write.
74    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
75        match self {
76            Self::EmptyFieldName { location } => {
77                write!(formatter, "field name is empty after canonicalization in {location}",)
78            }
79            Self::EmptyFixedReplacement { location, level } => write!(
80                formatter,
81                "fixed mask replacement for {level:?} sensitivity is empty in {location}",
82            ),
83            #[cfg(feature = "serde")]
84            Self::SerdePayloadLimitTooLarge { maximum } => write!(
85                formatter,
86                "Serde payload limit {maximum} exceeds this platform's addressable collection capacity",
87            ),
88            Self::OutputLimitTooLarge { maximum } => write!(
89                formatter,
90                "output limit {maximum} exceeds this platform's addressable collection capacity",
91            ),
92        }
93    }
94}
95
96impl Error for PolicyError {}