use bytes::Bytes;
pub trait Secret {
fn describe(&self) -> &'static str;
}
impl<T> Secret for Option<T> {
fn describe(&self) -> &'static str {
if self.is_some() {
"Some(<redacted>)"
} else {
"None"
}
}
}
macro_rules! always_redacted {
($($ty:ty),+ $(,)?) => {
$( impl Secret for $ty {
fn describe(&self) -> &'static str { "<redacted>" }
} )+
};
}
always_redacted!(Vec<u8>, Bytes, String);
pub struct Redacted<'a, T: Secret + ?Sized>(pub &'a T);
impl<T: Secret + ?Sized> core::fmt::Debug for Redacted<'_, T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str(self.0.describe())
}
}
#[macro_export]
macro_rules! redacted_debug {
($ty:ident { $($field:ident),* $(,)? } secret { $($secret:ident),+ $(,)? }) => {
impl ::core::fmt::Debug for $ty {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
f.debug_struct(stringify!($ty))
$( .field(stringify!($field), &self.$field) )*
$( .field(stringify!($secret), &$crate::support::Redacted(&self.$secret)) )+
.finish()
}
}
};
}