use std::fmt::{
self,
Debug,
Display,
Formatter,
};
#[cfg(feature = "serde")]
use crate::policy::ResolvedField;
use crate::{
LogOutputLimit,
Redact,
RedactValue,
RedactionPolicy,
RedactionSession,
};
use super::{
bounded_redacted_display::format_bounded,
bounded_redacted_display::format_debug_bounded,
internal::mask_byte_limit,
};
#[must_use = "format or serialize the keyed redaction view"]
pub struct RedactedKeyedValue<'value, 'policy, T: ?Sized> {
key: &'value str,
value: &'value T,
policy: &'policy RedactionPolicy,
}
impl<'value, 'policy, T: ?Sized> RedactedKeyedValue<'value, 'policy, T> {
#[must_use = "format or serialize the keyed redaction view"]
#[inline(always)]
pub const fn new(
key: &'value str,
value: &'value T,
policy: &'policy RedactionPolicy,
) -> Self {
Self { key, value, policy }
}
#[must_use]
#[inline(always)]
pub const fn key(&self) -> &'value str {
self.key
}
}
impl<T: Redact + RedactValue + ?Sized> Debug for RedactedKeyedValue<'_, '_, T> {
#[inline]
fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
let session = RedactionSession::diagnostic(self.policy);
let view =
RedactedKeyedValueSession::new(self.key, self.value, &session);
if mask_byte_limit().is_some() {
return Debug::fmt(&view, formatter);
}
format_debug_bounded(
&view,
LogOutputLimit::from(self.policy.limits().diagnostic_event()),
formatter,
)
}
}
mod session_view {
use std::fmt::{
self,
Debug,
Display,
Formatter,
Write as _,
};
use crate::{
Redact,
RedactValue,
RedactionSession,
policy::ResolvedField,
text::internal::LogEscapeWriter,
};
#[must_use = "format the keyed redacted value view"]
pub struct RedactedKeyedValueSession<'value, 'session, 'policy, T: ?Sized> {
key: &'value str,
value: &'value T,
session: &'session RedactionSession<'policy>,
}
impl<'value, 'session, 'policy, T: ?Sized>
RedactedKeyedValueSession<'value, 'session, 'policy, T>
{
#[inline(always)]
pub fn new(
key: &'value str,
value: &'value T,
session: &'session RedactionSession<'policy>,
) -> Self {
Self {
key,
value,
session,
}
}
}
impl<T: Redact + RedactValue + ?Sized> Debug
for RedactedKeyedValueSession<'_, '_, '_, T>
{
#[inline]
fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
let policy = self.session.policy();
let resolved = policy.resolve_field(self.key);
match resolved {
ResolvedField::Sensitive { sensitivity } => Debug::fmt(
&self.value.redact_value(sensitivity, policy.masking()),
formatter,
),
ResolvedField::PassThrough => {
self.value.fmt_redacted(self.session, formatter)
}
}
}
}
impl<T: Redact + RedactValue + ?Sized> Display
for RedactedKeyedValueSession<'_, '_, '_, T>
{
#[inline]
fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
let mut writer = LogEscapeWriter::new(formatter);
write!(&mut writer, "{self:?}")
}
}
}
pub use session_view::RedactedKeyedValueSession;
impl<T: Redact + RedactValue + ?Sized> Display
for RedactedKeyedValue<'_, '_, T>
{
#[inline]
fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
let session = RedactionSession::diagnostic(self.policy);
let view =
RedactedKeyedValueSession::new(self.key, self.value, &session);
format_bounded(
&view,
LogOutputLimit::from(self.policy.limits().diagnostic_event()),
formatter,
)
}
}
#[cfg(feature = "serde")]
impl<T: RedactValue + crate::domain::RedactSerialize + ?Sized> serde::Serialize
for RedactedKeyedValue<'_, '_, T>
{
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let resolved = self.policy.resolve_field(self.key);
match resolved {
ResolvedField::Sensitive { sensitivity } => {
serde::Serialize::serialize(
&self
.value
.redact_value(sensitivity, self.policy.masking()),
serializer,
)
}
ResolvedField::PassThrough => {
crate::domain::RedactSerialize::serialize_redacted(
self.value,
self.policy,
serializer,
)
}
}
}
}