Skip to main content

qubit_redact/policy/
diagnostic_budget.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//! Hard input and output limits for redacted diagnostics.
9// qubit-style: allow type-file-name
10
11use super::DiagnosticBudgetError;
12
13/// Bounds both inspected diagnostic bytes and produced log-safe bytes.
14#[must_use]
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub struct InputOutputLimit {
17    /// Maximum number of source bytes a diagnostic redactor may inspect.
18    max_input_bytes: usize,
19    /// Maximum number of bytes in the final log-safe rendering.
20    max_output_bytes: usize,
21}
22
23impl InputOutputLimit {
24    /// Smallest output limit that can contain the diagnostic-limit marker.
25    pub const MIN_OUTPUT_BYTES: usize =
26        "<redacted: diagnostic limit exceeded>".len();
27
28    /// Creates checked hard limits for diagnostic processing.
29    ///
30    /// # Parameters
31    ///
32    /// * `max_input_bytes` - Maximum source bytes one diagnostic may inspect.
33    /// * `max_output_bytes` - Maximum bytes in the final log-safe rendering.
34    ///
35    /// # Returns
36    ///
37    /// A validated diagnostic budget.
38    ///
39    /// # Errors
40    ///
41    /// Returns [`DiagnosticBudgetError::ZeroInput`] when `max_input_bytes` is
42    /// zero, or [`DiagnosticBudgetError::OutputTooSmall`] when the output limit
43    /// cannot contain the diagnostic-limit marker.
44    #[inline]
45    pub const fn new(
46        max_input_bytes: usize,
47        max_output_bytes: usize,
48    ) -> Result<Self, DiagnosticBudgetError> {
49        if max_input_bytes == 0 {
50            return Err(DiagnosticBudgetError::ZeroInput);
51        }
52        if max_output_bytes < Self::MIN_OUTPUT_BYTES {
53            return Err(DiagnosticBudgetError::OutputTooSmall {
54                minimum: Self::MIN_OUTPUT_BYTES,
55                actual: max_output_bytes,
56            });
57        }
58        Ok(Self {
59            max_input_bytes,
60            max_output_bytes,
61        })
62    }
63
64    /// Returns the maximum number of source bytes a diagnostic may inspect.
65    ///
66    /// # Returns
67    ///
68    /// The configured source-byte limit.
69    #[must_use]
70    #[inline(always)]
71    pub const fn max_input_bytes(self) -> usize {
72        self.max_input_bytes
73    }
74
75    /// Returns the maximum final log-safe diagnostic size.
76    ///
77    /// # Returns
78    ///
79    /// The configured output-byte limit.
80    #[must_use]
81    #[inline(always)]
82    pub const fn max_output_bytes(self) -> usize {
83        self.max_output_bytes
84    }
85}
86
87impl Default for InputOutputLimit {
88    /// Returns conservative 16 KiB input and 64 KiB output limits.
89    ///
90    /// # Returns
91    ///
92    /// A diagnostic budget with the documented conservative limits.
93    #[inline(always)]
94    fn default() -> Self {
95        Self {
96            max_input_bytes: 16 * 1024,
97            max_output_bytes: 64 * 1024,
98        }
99    }
100}