use std::fmt::{
self,
Debug,
Display,
Formatter,
};
use crate::{
BoundedRedactedDisplay,
LogOutputLimit,
Redact,
RedactionPolicy,
RedactionSession,
};
use super::bounded_redacted_display::{
format_bounded,
format_debug_bounded,
};
use super::internal::mask_byte_limit;
#[must_use = "format or serialize the redacted view"]
pub struct Redacted<'a, T: ?Sized> {
value: &'a T,
policy: RedactionPolicy,
}
impl<'a, T: ?Sized> Redacted<'a, T> {
#[inline(always)]
pub(crate) const fn new(value: &'a T, policy: RedactionPolicy) -> Self {
Self { value, policy }
}
#[inline(always)]
pub const fn with_output_limit(
self,
limit: LogOutputLimit,
) -> BoundedRedactedDisplay<Self> {
BoundedRedactedDisplay::new(self, limit)
}
#[must_use = "format the bounded redacted display adapter"]
#[inline]
pub fn with_policy_output_limit(self) -> BoundedRedactedDisplay<Self> {
let limit =
LogOutputLimit::from(self.policy.limits().diagnostic_event());
BoundedRedactedDisplay::new(self, limit)
}
#[cfg(feature = "serde")]
#[inline(always)]
pub(crate) const fn value(&self) -> &'a T {
self.value
}
#[cfg(feature = "serde")]
#[inline(always)]
pub(crate) const fn policy(&self) -> &RedactionPolicy {
&self.policy
}
}
#[cfg(feature = "serde")]
impl<T: crate::domain::RedactSerialize + ?Sized> serde::Serialize
for Redacted<'_, T>
{
#[inline(always)]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.value().serialize_redacted(self.policy(), serializer)
}
}
impl<T: Redact + ?Sized> Debug for Redacted<'_, T> {
#[inline(always)]
fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
let session = RedactionSession::diagnostic(&self.policy);
if mask_byte_limit().is_some() {
return self.value.fmt_redacted(&session, formatter);
}
let view = RedactedSessionView::new(self.value, &session);
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,
RedactionSession,
text::internal::LogEscapeWriter,
};
#[must_use = "format the nested redacted view"]
pub struct RedactedSessionView<'value, 'session, 'policy, T: ?Sized> {
value: &'value T,
session: &'session RedactionSession<'policy>,
}
impl<'value, 'session, 'policy, T: ?Sized>
RedactedSessionView<'value, 'session, 'policy, T>
{
#[inline(always)]
pub fn new(
value: &'value T,
session: &'session RedactionSession<'policy>,
) -> Self {
Self { value, session }
}
}
impl<T: Redact + ?Sized> Debug for RedactedSessionView<'_, '_, '_, T> {
#[inline(always)]
fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
self.value.fmt_redacted(self.session, formatter)
}
}
impl<T: Redact + ?Sized> Display for RedactedSessionView<'_, '_, '_, T> {
#[inline(always)]
fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
let mut writer = LogEscapeWriter::new(formatter);
write!(&mut writer, "{self:?}")
}
}
}
pub use session_view::RedactedSessionView;
impl<T: Redact + ?Sized> Display for Redacted<'_, T> {
#[inline]
fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
let session = RedactionSession::diagnostic(&self.policy);
let view = RedactedSessionView::new(self.value, &session);
format_bounded(
&view,
LogOutputLimit::from(self.policy.limits().diagnostic_event()),
formatter,
)
}
}