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 {}