1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// =============================================================================
// Copyright (c) 2026 Haixing Hu.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0.
// =============================================================================
//! Unpublished format-rendering outcomes consumed by the transaction runtime.
use crate::RedactionCompletion;
use crate::RedactionReasons;
/// Carries rendered text and degradation provenance without constructing a
/// publishable output or transaction summary inside a format adapter.
pub(crate) struct RenderedOperation {
/// Log-safe unpublished text produced by one adapter.
text: String,
/// Completion state produced by bounded rendering.
completion: RedactionCompletion,
/// Machine-readable degradation provenance.
reasons: RedactionReasons,
/// Whether actual output rejection prevents later work.
output_closed: bool,
}
impl RenderedOperation {
/// Creates an unpublished operation from the runtime sink's final state.
///
/// # Parameters
///
/// - `text`: Already escaped and bounded output.
/// - `completion`: Rendering completion, independent of later admission.
/// - `reasons`: Accumulated observed failure facts.
/// - `output_closed`: Whether an actual output rejection forbids later
/// work.
///
/// # Returns
///
/// The unpublished operation without publishing its text.
///
/// # Panics
///
/// In debug builds, panics if `Exhausted` lacks `OutputLimitReached`.
#[must_use]
pub(super) const fn from_parts(
text: String,
completion: RedactionCompletion,
reasons: RedactionReasons,
output_closed: bool,
) -> Self {
debug_assert!(
!matches!(completion, RedactionCompletion::Exhausted)
|| reasons.contains(crate::RedactionReason::OutputLimitReached)
);
Self {
text,
completion,
reasons,
output_closed,
}
}
/// Reports whether the output sink rejected further payload.
///
/// # Returns
///
/// Whether an actual output rejection closed further admission.
#[must_use]
#[inline(always)]
pub(crate) const fn output_closed(&self) -> bool {
self.output_closed
}
/// Borrows the unpublished rendered text.
///
/// # Returns
///
/// The retained escaped text, still unpublished.
#[must_use]
#[inline(always)]
pub(crate) fn text(&self) -> &str {
&self.text
}
/// Returns the renderer's completion state.
///
/// # Returns
///
/// The rendering completion of this operation.
#[must_use = "the completion state describes whether the output is complete"]
#[inline(always)]
pub(crate) const fn completion(&self) -> RedactionCompletion {
self.completion
}
/// Returns the renderer's accumulated provenance.
///
/// # Returns
///
/// All observed provenance for this operation.
#[must_use]
#[inline(always)]
pub(crate) const fn reasons(&self) -> RedactionReasons {
self.reasons
}
/// Adds observed provenance while preserving the sink's completion facts.
///
/// # Parameters
///
/// - `reason`: Additional observed provenance.
///
/// # Returns
///
/// This operation with the reason unioned into its existing set.
#[cfg(feature = "http")]
#[must_use]
#[inline(always)]
pub(crate) fn with_reason(mut self, reason: crate::RedactionReason) -> Self {
self.reasons = self.reasons.with(reason);
self
}
/// Combines two independently rendered parts into one unpublished result.
///
/// # Parameters
///
/// - `other`: Following independently bounded part, admitted under the
/// shared allowance.
///
/// # Returns
///
/// The concatenated parts with strongest completion, unioned reasons, and
/// output closure if either part rejected output.
#[must_use]
pub(crate) fn merge(mut self, other: Self) -> Self {
self.text.push_str(other.text());
self.completion = match (self.completion, other.completion()) {
(RedactionCompletion::Exhausted, _) | (_, RedactionCompletion::Exhausted) => RedactionCompletion::Exhausted,
(RedactionCompletion::Truncated, _) | (_, RedactionCompletion::Truncated) => RedactionCompletion::Truncated,
_ => RedactionCompletion::Complete,
};
self.reasons = self.reasons.union(other.reasons());
self.output_closed |= other.output_closed;
self
}
/// Consumes this unpublished outcome into its runtime-owned parts.
///
/// # Returns
///
/// Owned text, completion, and provenance, in that order. The caller must
/// read `output_closed` before consuming this value when combining
/// operations.
#[must_use = "the rendered parts contain the operation result and provenance"]
#[inline(always)]
pub(crate) fn into_parts(self) -> (String, RedactionCompletion, RedactionReasons) {
(self.text, self.completion, self.reasons)
}
}