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}