use std::fmt::{
self,
Write as _,
};
use crate::{
LogOutputLimit,
RedactionPolicy,
Sensitivity,
text::internal::BoundedLogEscapeWriter,
};
use super::{
RedactedJson,
redact_json_text_in_place::redacted_json_text,
};
#[must_use = "format or serialize the redacted JSON text view"]
pub struct RedactedJsonText<'text, 'policy> {
text: &'text str,
policy: &'policy RedactionPolicy,
}
impl<'text, 'policy> RedactedJsonText<'text, 'policy> {
#[inline(always)]
pub const fn new(
text: &'text str,
policy: &'policy RedactionPolicy,
) -> Self {
Self { text, policy }
}
#[inline(always)]
const fn exceeds_diagnostic_input_budget(&self) -> bool {
self.text.len() > self.policy.diagnostic_budget().max_input_bytes()
}
#[inline(always)]
fn opaque_secret(&self) -> &str {
self.policy.masking().mask_opaque(Sensitivity::Secret)
}
fn diagnostic_json_text(&self) -> String {
if self.exceeds_diagnostic_input_budget() {
return self.opaque_secret().to_owned();
}
redacted_json_text(self.text, self.policy)
}
}
impl fmt::Debug for RedactedJsonText<'_, '_> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut writer = BoundedLogEscapeWriter::new(LogOutputLimit::from(
self.policy.diagnostic_budget(),
));
if self.exceeds_diagnostic_input_budget() {
let _ = write!(&mut writer, "{:?}", self.opaque_secret());
} else {
match serde_json::from_str(self.text) {
Ok(value) if formatter.alternate() => {
let _ = write!(
&mut writer,
"{:#?}",
RedactedJson::new(&value, self.policy),
);
}
Ok(value) => {
let _ = write!(
&mut writer,
"{:?}",
RedactedJson::new(&value, self.policy),
);
}
Err(_) => {
let _ = write!(&mut writer, "{:?}", self.opaque_secret());
}
}
}
formatter.write_str(&writer.finish())
}
}
impl fmt::Display for RedactedJsonText<'_, '_> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut writer = BoundedLogEscapeWriter::new(LogOutputLimit::from(
self.policy.diagnostic_budget(),
));
let _ = writer.write_str(&self.diagnostic_json_text());
formatter.write_str(&writer.finish())
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for RedactedJsonText<'_, '_> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(&redacted_json_text(self.text, self.policy))
}
}