qubit_redact/facade/redacted_text_composer.rs
1// =============================================================================
2// Copyright (c) 2026 Haixing Hu.
3//
4// SPDX-License-Identifier: Apache-2.0
5//
6// Licensed under the Apache License, Version 2.0.
7// =============================================================================
8//! Consumption-based construction of one ordered redacted text.
9
10use std::fmt::Display;
11
12use crate::RedactionTextOutput;
13use crate::domain::Redact;
14use crate::runtime::TextSession;
15
16/// Builds one ordered, redacted text value through consuming chained calls.
17///
18/// # Examples
19///
20/// ```
21/// use qubit_redact::Redactor;
22///
23/// let output = Redactor::strict()
24/// .text_composer()
25/// .literal("password=")
26/// .field("password", "raw-secret")
27/// .finish();
28/// assert!(!output.text().as_str().contains("raw-secret"));
29/// ```
30pub struct RedactedTextComposer {
31 /// Typed transaction that exclusively owns this composer's text output.
32 session: TextSession,
33}
34
35impl RedactedTextComposer {
36 /// Creates a composer backed by one private runtime transaction.
37 ///
38 /// # Parameters
39 ///
40 /// - `session`: Fresh text transaction exclusively owned by this composer.
41 ///
42 /// # Returns
43 ///
44 /// A composer retaining the transaction and its shared budget.
45 #[must_use]
46 #[inline(always)]
47 pub(crate) const fn from_session(session: TextSession) -> Self {
48 Self { session }
49 }
50
51 /// Appends trusted program-authored text.
52 ///
53 /// # Parameters
54 ///
55 /// - `text`: Trusted static program text, escaped and counted against
56 /// output capacity.
57 ///
58 /// # Returns
59 ///
60 /// This composer after attempting to append the literal.
61 #[must_use]
62 #[inline(always)]
63 pub fn literal(mut self, text: &'static str) -> Self {
64 let _ = self.session.literal(text);
65 self
66 }
67
68 /// Redacts and appends one scalar field.
69 ///
70 /// # Type Parameters
71 ///
72 /// - `T`: Lazily evaluated scalar formatter.
73 ///
74 /// # Parameters
75 ///
76 /// - `field`: Raw scalar key used for admission and policy classification.
77 /// - `value`: Scalar formatted only when admission and masking require it.
78 ///
79 /// # Returns
80 ///
81 /// This composer after recording the scalar result and accounting.
82 #[must_use]
83 #[inline(always)]
84 pub fn field<T>(mut self, field: &str, value: &T) -> Self
85 where
86 T: Display + ?Sized,
87 {
88 let _ = self.session.field(field, value);
89 self
90 }
91
92 /// Redacts and appends one domain value.
93 ///
94 /// # Type Parameters
95 ///
96 /// - `T`: Domain type exposing structured redaction.
97 ///
98 /// # Parameters
99 ///
100 /// - `value`: Domain value visited through its structured redaction
101 /// contract.
102 ///
103 /// # Returns
104 ///
105 /// This composer after recording the domain result and accounting.
106 #[must_use]
107 #[inline(always)]
108 pub fn value<T>(mut self, value: &T) -> Self
109 where
110 T: Redact + ?Sized,
111 {
112 let _ = self.session.value(value);
113 self
114 }
115
116 /// Appends command-line text configured through the argv writer.
117 ///
118 /// # Type Parameters
119 ///
120 /// - `F`: Callback whose writer borrow cannot escape the call.
121 ///
122 /// # Parameters
123 ///
124 /// - `configure`: One-shot callback using the format writer and this
125 /// transaction’s remaining budget.
126 ///
127 /// # Returns
128 ///
129 /// This composer retaining the updated output and execution summary.
130 #[must_use]
131 #[inline(always)]
132 pub fn argv<F>(mut self, configure: F) -> Self
133 where
134 F: for<'session> FnOnce(&mut crate::formats::argv::ArgvRedactionWriter<'session>),
135 {
136 self.session.argv(configure);
137 self
138 }
139
140 /// Appends environment text configured through the environment writer.
141 ///
142 /// # Type Parameters
143 ///
144 /// - `F`: Callback whose writer borrow cannot escape the call.
145 ///
146 /// # Parameters
147 ///
148 /// - `configure`: One-shot callback using the format writer and this
149 /// transaction’s remaining budget.
150 ///
151 /// # Returns
152 ///
153 /// This composer retaining the updated output and execution summary.
154 #[must_use]
155 #[inline(always)]
156 pub fn env<F>(mut self, configure: F) -> Self
157 where
158 F: for<'session> FnOnce(&mut crate::formats::env::EnvRedactionWriter<'session>),
159 {
160 self.session.env(configure);
161 self
162 }
163
164 /// Appends process text configured through the process writer.
165 ///
166 /// # Type Parameters
167 ///
168 /// - `F`: Callback whose writer borrow cannot escape the call.
169 ///
170 /// # Parameters
171 ///
172 /// - `configure`: One-shot callback using the format writer and this
173 /// transaction’s remaining budget.
174 ///
175 /// # Returns
176 ///
177 /// This composer retaining the updated output and execution summary.
178 #[must_use]
179 #[inline(always)]
180 pub fn process<F>(mut self, configure: F) -> Self
181 where
182 F: for<'session> FnOnce(&mut crate::formats::process::ProcessRedactionWriter<'session>),
183 {
184 let _ = self.session.process(configure);
185 self
186 }
187
188 /// Appends JSON text configured through the JSON writer.
189 ///
190 /// # Type Parameters
191 ///
192 /// - `F`: Callback whose writer borrow cannot escape the call.
193 ///
194 /// # Parameters
195 ///
196 /// - `configure`: One-shot callback using the format writer and this
197 /// transaction’s remaining budget.
198 ///
199 /// # Returns
200 ///
201 /// This composer retaining the updated output and execution summary.
202 #[cfg(feature = "json")]
203 #[must_use]
204 #[inline(always)]
205 pub fn json<F>(mut self, configure: F) -> Self
206 where
207 F: for<'session> FnOnce(&mut crate::formats::json::JsonRedactionWriter<'session>),
208 {
209 let _ = self.session.json(configure);
210 self
211 }
212
213 /// Appends HTTP text configured through the HTTP writer.
214 ///
215 /// # Type Parameters
216 ///
217 /// - `F`: Callback whose writer borrow cannot escape the call.
218 ///
219 /// # Parameters
220 ///
221 /// - `configure`: One-shot callback using the format writer and this
222 /// transaction’s remaining budget.
223 ///
224 /// # Returns
225 ///
226 /// This composer retaining the updated output and execution summary.
227 #[cfg(feature = "http")]
228 #[must_use]
229 #[inline(always)]
230 pub fn http<F>(mut self, configure: F) -> Self
231 where
232 F: for<'session> FnOnce(&mut crate::formats::http::HttpRedactionWriter<'session>),
233 {
234 let _ = self.session.http(configure);
235 self
236 }
237
238 /// Appends URI text configured through the URI writer.
239 ///
240 /// # Type Parameters
241 ///
242 /// - `F`: Callback whose writer borrow cannot escape the call.
243 ///
244 /// # Parameters
245 ///
246 /// - `configure`: One-shot callback using the format writer and this
247 /// transaction’s remaining budget.
248 ///
249 /// # Returns
250 ///
251 /// This composer retaining the updated output and execution summary.
252 #[cfg(feature = "uri")]
253 #[must_use]
254 #[inline(always)]
255 pub fn uri<F>(mut self, configure: F) -> Self
256 where
257 F: for<'session> FnOnce(&mut crate::formats::uri::UriRedactionWriter<'session>),
258 {
259 let _ = self.session.uri(configure);
260 self
261 }
262
263 /// Consumes the composer and publishes its redacted text and summary.
264 ///
265 /// # Returns
266 ///
267 /// The completed text and its actual completion, reasons, and resource
268 /// accounting.
269 #[must_use]
270 #[inline(always)]
271 pub fn finish(self) -> RedactionTextOutput {
272 self.session.finish()
273 }
274}