Skip to main content

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}