1use crate::output::RedactionCompletion;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
15#[non_exhaustive]
16pub enum RedactionReason {
17 InputLimitReached,
19 OutputLimitReached,
21 TraversalLimitReached,
23 DepthLimitReached,
25 SourceTruncated,
27 InvalidJson,
29 InvalidUri,
31 InvalidContentType,
33 UnsupportedContentType,
35 InvalidForm,
37 InvalidMultipart,
39}
40
41impl RedactionReason {
42 const fn bit(self) -> u64 {
44 match self {
45 Self::InputLimitReached => 1 << 0,
46 Self::OutputLimitReached => 1 << 1,
47 Self::TraversalLimitReached => 1 << 2,
48 Self::DepthLimitReached => 1 << 3,
49 Self::SourceTruncated => 1 << 4,
50 Self::InvalidJson => 1 << 5,
51 Self::InvalidUri => 1 << 6,
52 Self::InvalidContentType => 1 << 7,
53 Self::UnsupportedContentType => 1 << 8,
54 Self::InvalidForm => 1 << 9,
55 Self::InvalidMultipart => 1 << 10,
56 }
57 }
58}
59
60#[derive(Debug, Clone, Copy, PartialEq, Eq)]
62pub struct RedactionUsage {
63 presented_input_bytes: usize,
65 inspected_input_bytes: usize,
67 output_bytes: usize,
69 visited_nodes: usize,
71 visited_collection_items: usize,
73 max_depth: usize,
75 omitted_input_bytes: Option<usize>,
77}
78
79impl Default for RedactionUsage {
80 fn default() -> Self {
82 Self::empty()
83 }
84}
85
86impl RedactionUsage {
87 #[must_use]
89 pub const fn empty() -> Self {
90 Self {
91 presented_input_bytes: 0,
92 inspected_input_bytes: 0,
93 output_bytes: 0,
94 visited_nodes: 0,
95 visited_collection_items: 0,
96 max_depth: 0,
97 omitted_input_bytes: Some(0),
98 }
99 }
100
101 #[must_use]
103 #[inline(always)]
104 pub const fn presented_input_bytes(self) -> usize {
105 self.presented_input_bytes
106 }
107
108 #[must_use]
110 #[inline(always)]
111 pub const fn inspected_input_bytes(self) -> usize {
112 self.inspected_input_bytes
113 }
114
115 #[must_use]
117 #[inline(always)]
118 pub const fn output_bytes(self) -> usize {
119 self.output_bytes
120 }
121
122 #[must_use]
124 #[inline(always)]
125 pub const fn visited_nodes(self) -> usize {
126 self.visited_nodes
127 }
128
129 #[must_use]
131 #[inline(always)]
132 pub const fn visited_collection_items(self) -> usize {
133 self.visited_collection_items
134 }
135
136 #[must_use]
139 #[inline(always)]
140 pub const fn max_depth(self) -> usize {
141 self.max_depth
142 }
143
144 #[must_use]
146 #[inline(always)]
147 pub const fn omitted_input_bytes(self) -> Option<usize> {
148 self.omitted_input_bytes
149 }
150
151 #[must_use]
153 pub(crate) const fn with_added_output_bytes(mut self, bytes: usize) -> Self {
154 self.output_bytes = self.output_bytes.saturating_add(bytes);
155 self
156 }
157
158 #[must_use]
160 pub(crate) const fn with_input(mut self, presented: usize, inspected: usize) -> Self {
161 self.presented_input_bytes = self.presented_input_bytes.saturating_add(presented);
162 self.inspected_input_bytes = self.inspected_input_bytes.saturating_add(inspected);
163 self.omitted_input_bytes = match self.omitted_input_bytes {
164 Some(omitted) => Some(omitted.saturating_add(presented.saturating_sub(inspected))),
165 None => None,
166 };
167 self
168 }
169
170 #[cfg(feature = "http")]
172 #[must_use]
173 pub(crate) const fn with_source_input(
174 mut self,
175 presented: usize,
176 inspected: usize,
177 omitted: Option<usize>,
178 ) -> Self {
179 self.presented_input_bytes = self.presented_input_bytes.saturating_add(presented);
180 self.inspected_input_bytes = self.inspected_input_bytes.saturating_add(inspected);
181 self.omitted_input_bytes = match (self.omitted_input_bytes, omitted) {
182 (Some(previous), Some(current)) => Some(previous.saturating_add(current)),
183 _ => None,
184 };
185 self
186 }
187
188 #[must_use]
190 pub(crate) const fn with_domain_node(mut self, depth: usize) -> Self {
191 self.visited_nodes = self.visited_nodes.saturating_add(1);
192 self.max_depth = if self.max_depth > depth { self.max_depth } else { depth };
193 self
194 }
195
196 #[must_use]
198 pub(crate) const fn with_collection_item(mut self) -> Self {
199 self.visited_collection_items = self.visited_collection_items.saturating_add(1);
200 self
201 }
202}
203
204#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
206pub struct RedactionReasons(
207 u64,
209);
210
211impl RedactionReasons {
212 #[must_use]
214 pub const fn empty() -> Self {
215 Self(0)
216 }
217
218 #[must_use]
220 pub const fn with(self, reason: RedactionReason) -> Self {
221 Self(self.0 | reason.bit())
222 }
223
224 #[must_use]
226 pub const fn contains(self, reason: RedactionReason) -> bool {
227 self.0 & reason.bit() != 0
228 }
229
230 #[must_use]
232 pub const fn union(self, other: Self) -> Self {
233 Self(self.0 | other.0)
234 }
235}
236
237#[derive(Debug, Clone, Copy, PartialEq, Eq)]
239pub struct RedactionSummary {
240 redaction_disabled: bool,
242 completion: RedactionCompletion,
244 reasons: RedactionReasons,
246 usage: RedactionUsage,
248}
249
250impl RedactionSummary {
251 #[must_use]
253 pub(crate) const fn from_parts(
254 redaction_disabled: bool,
255 completion: RedactionCompletion,
256 reasons: RedactionReasons,
257 usage: RedactionUsage,
258 ) -> Self {
259 Self {
260 redaction_disabled,
261 completion,
262 reasons,
263 usage,
264 }
265 }
266
267 #[must_use]
269 pub(crate) const fn complete() -> Self {
270 Self {
271 redaction_disabled: false,
272 completion: RedactionCompletion::Complete,
273 reasons: RedactionReasons::empty(),
274 usage: RedactionUsage::empty(),
275 }
276 }
277
278 #[must_use]
280 pub(crate) const fn truncated(reason: RedactionReason) -> Self {
281 Self {
282 redaction_disabled: false,
283 completion: RedactionCompletion::Truncated,
284 reasons: RedactionReasons::empty().with(reason),
285 usage: RedactionUsage::empty(),
286 }
287 }
288
289 #[must_use]
291 #[inline(always)]
292 pub const fn completion(self) -> RedactionCompletion {
293 self.completion
294 }
295
296 #[must_use]
298 #[inline(always)]
299 pub const fn is_redaction_disabled(self) -> bool {
300 self.redaction_disabled
301 }
302
303 #[must_use]
305 #[inline(always)]
306 pub const fn reasons(self) -> RedactionReasons {
307 self.reasons
308 }
309
310 #[must_use]
313 #[inline(always)]
314 pub const fn usage(self) -> RedactionUsage {
315 self.usage
316 }
317
318 #[must_use]
320 pub(crate) const fn exhausted(reason: RedactionReason) -> Self {
321 Self {
322 redaction_disabled: false,
323 completion: RedactionCompletion::Exhausted,
324 reasons: RedactionReasons::empty().with(reason),
325 usage: RedactionUsage::empty(),
326 }
327 }
328}