Skip to main content

qubit_redact/facade/
redacted_text.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//! Final text produced by one redaction operation.
9
10use std::borrow::Cow;
11use std::fmt;
12
13/// Final UTF-8 text produced by a redaction operation under its selected
14/// policy.
15///
16/// The value has crossed the runtime's plain-text presentation boundary. It is
17/// owned and can be rendered with [`std::fmt::Display`] without running another
18/// redaction pass. This guarantee is policy-relative: a disabled policy or an
19/// explicitly unredacted writer operation may deliberately preserve source
20/// content. Callers must not treat this type as proof that the text is
21/// confidential in every policy configuration. Any additional length
22/// restriction belongs to the caller's final logging or presentation sink.
23///
24/// # Examples
25///
26/// ```
27/// use qubit_redact::Redactor;
28///
29/// let output = Redactor::strict().redact_field("password", "raw-secret");
30/// assert_eq!(output.text().as_str(), "<redacted>");
31/// ```
32#[derive(Debug, Clone, PartialEq, Eq, Hash)]
33pub struct RedactedText(
34    /// Owned text that has already crossed the redaction safety boundary.
35    String,
36);
37
38impl RedactedText {
39    /// Creates final text from an already escaped representation.
40    ///
41    /// # Parameters
42    ///
43    /// - `value`: Already escaped text whose policy transformation is complete.
44    ///
45    /// # Returns
46    ///
47    /// An owned final-text wrapper without another escaping or redaction pass.
48    #[must_use]
49    #[inline(always)]
50    pub(crate) fn from_escaped(value: impl Into<Cow<'static, str>>) -> Self {
51        Self(value.into().into_owned())
52    }
53
54    /// Borrows the final redacted text.
55    ///
56    /// # Returns
57    ///
58    /// The finalized UTF-8 text borrowed from this wrapper.
59    #[must_use]
60    #[inline(always)]
61    pub fn as_str(&self) -> &str {
62        &self.0
63    }
64
65    /// Consumes the wrapper and returns its owned text.
66    ///
67    /// # Returns
68    ///
69    /// The owned finalized text without cloning.
70    #[must_use]
71    #[inline(always)]
72    pub fn into_string(self) -> String {
73        self.0
74    }
75}
76
77impl AsRef<str> for RedactedText {
78    /// Borrows the safe text through the standard string-reference contract.
79    ///
80    /// # Returns
81    ///
82    /// The finalized text borrowed under the standard string-reference
83    /// contract.
84    #[inline(always)]
85    fn as_ref(&self) -> &str {
86        self.as_str()
87    }
88}
89
90impl fmt::Display for RedactedText {
91    /// Writes only the finalized safe text to the destination formatter.
92    ///
93    /// # Parameters
94    ///
95    /// - `formatter`: Destination receiving the already finalized text.
96    ///
97    /// # Returns
98    ///
99    /// Success after writing the text.
100    ///
101    /// # Errors
102    ///
103    /// Propagates a destination formatting error.
104    #[inline(always)]
105    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
106        formatter.write_str(self.as_str())
107    }
108}