Skip to main content

qubit_redact/facade/
redaction_inspection.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//! Conclusive sensitivity metadata produced without rendering source values.
9
10use super::RedactionUsage;
11use crate::Sensitivity;
12
13/// Highest sensitivity found by one complete, bounded inspection.
14///
15/// A successful value is conclusive under the selected policy. [`None`] from
16/// [`Self::max_sensitivity`] means no inspected value was declared sensitive;
17/// a disabled policy deliberately bypasses classification, as reported by
18/// [`Self::is_redaction_disabled`]. It does not prove that source data is
19/// inherently nonsensitive. Inconclusive traversal is returned as
20/// [`crate::RedactionInspectionError`] instead of this type.
21///
22/// # Examples
23///
24/// ```
25/// use qubit_redact::Redactor;
26/// use qubit_redact::Sensitivity;
27///
28/// let inspection = Redactor::strict()
29///     .inspect_field("password", "raw-secret")
30///     .expect("the scalar inspection is bounded and valid");
31/// assert_eq!(inspection.max_sensitivity(), Some(Sensitivity::Secret));
32/// ```
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34pub struct RedactionInspection {
35    /// Whether policy evaluation was bypassed for this complete traversal.
36    redaction_disabled: bool,
37    /// Strongest sensitivity observed during the complete traversal.
38    max_sensitivity: Option<Sensitivity>,
39    /// Resource use excluding any output bytes, because inspection does not
40    /// render.
41    usage: RedactionUsage,
42}
43
44impl RedactionInspection {
45    /// Creates a conclusive inspection from runtime-owned metadata.
46    ///
47    /// # Parameters
48    ///
49    /// - `redaction_disabled`: Whether the complete inspection intentionally
50    ///   bypassed policy classification.
51    /// - `max_sensitivity`: Some strongest observed level, or None when the
52    ///   selected policy declared no value sensitive.
53    /// - `usage`: Resource accounting with zero rendered output bytes.
54    ///
55    /// # Returns
56    ///
57    /// A conclusive inspection retaining the supplied metadata.
58    #[must_use]
59    #[inline(always)]
60    pub(crate) const fn new(
61        redaction_disabled: bool,
62        max_sensitivity: Option<Sensitivity>,
63        usage: RedactionUsage,
64    ) -> Self {
65        Self {
66            redaction_disabled,
67            max_sensitivity,
68            usage,
69        }
70    }
71
72    /// Reports whether the complete traversal found sensitive data.
73    ///
74    /// # Returns
75    ///
76    /// True when the complete traversal found at least one sensitive value.
77    #[must_use]
78    #[inline(always)]
79    pub const fn contains_sensitive(&self) -> bool {
80        self.max_sensitivity.is_some()
81    }
82
83    /// Returns whether the selected policy disabled this inspection.
84    ///
85    /// # Returns
86    ///
87    /// True when policy classification was intentionally disabled for this
88    /// inspection.
89    #[must_use]
90    #[inline(always)]
91    pub const fn is_redaction_disabled(&self) -> bool {
92        self.redaction_disabled
93    }
94
95    /// Returns the strongest sensitivity found by the complete traversal.
96    ///
97    /// # Returns
98    ///
99    /// `Some(level)` for declared sensitive data, or `None` when the selected
100    /// policy declared none, including when classification was disabled.
101    #[must_use]
102    #[inline(always)]
103    pub const fn max_sensitivity(&self) -> Option<Sensitivity> {
104        self.max_sensitivity
105    }
106
107    /// Returns resources consumed while classifying the input.
108    ///
109    /// Output bytes are always zero because inspection never renders values.
110    ///
111    /// # Returns
112    ///
113    /// Resources consumed during complete classification, with zero output
114    /// bytes.
115    #[must_use]
116    #[inline(always)]
117    pub const fn usage(&self) -> RedactionUsage {
118        self.usage
119    }
120}