use crate::{
private::{RedactFlags, RedactionContent, RedactionFormatter, RedactionLength, RedactionTarget},
util::give_me_a_formatter,
};
use std::fmt::{Debug, Display};
#[derive(Clone, Copy)]
pub struct RedactWrapped<'a, T> {
data: &'a T,
flags: &'a RedactFlags,
}
impl<T> Display for RedactWrapped<'_, T>
where
T: Display,
{
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Debug::fmt(
&RedactionFormatter {
this: RedactionTarget::Display(self.data),
flags: *self.flags,
specialization: None,
},
fmt,
)
}
}
impl<T> Debug for RedactWrapped<'_, T>
where
T: Debug,
{
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Debug::fmt(
&RedactionFormatter {
this: RedactionTarget::Debug {
this: self.data,
alternate: fmt.alternate(),
},
flags: *self.flags,
specialization: None,
},
fmt,
)
}
}
pub struct Redactor(RedactFlags);
impl Redactor {
#[inline(always)]
pub const fn builder() -> RedactorBuilder {
RedactorBuilder::new()
}
pub fn redact(&self, data: String) -> String {
give_me_a_formatter(|fmt| {
std::fmt::Debug::fmt(
&RedactionFormatter {
this: RedactionTarget::Display(&data.as_str()),
flags: self.0,
specialization: None,
},
fmt,
)
})
.to_string()
}
pub fn redact_in_place(&self, data: &mut String) -> &Self {
*data = self.redact(core::mem::take(data));
self
}
pub const fn wrap<'a, T>(&'a self, data: &'a T) -> RedactWrapped<'a, T> {
RedactWrapped { flags: &self.0, data }
}
}
pub struct RedactorBuilder {
redact_content: Option<RedactionContent<'static>>,
partial: bool,
}
impl RedactorBuilder {
#[inline(always)]
pub const fn new() -> Self {
Self {
redact_content: None,
partial: false,
}
}
#[inline(always)]
pub const fn char(mut self, char: char) -> Self {
self.redact_content = Some(RedactionContent::Char(char));
self
}
#[inline(always)]
pub const fn str(mut self, str: &'static str) -> Self {
self.redact_content = Some(RedactionContent::Str(str));
self
}
#[inline(always)]
pub const fn partial(mut self) -> Self {
self.partial = true;
self
}
#[inline(always)]
pub const fn build(self) -> Result<Redactor, &'static str> {
let flags = RedactFlags {
redact_length: if self.partial {
RedactionLength::Partial
} else {
RedactionLength::Full
},
redact_content: match self.redact_content {
Some(style) => style,
None => RedactionContent::Asterisks,
},
};
Ok(Redactor(flags))
}
}
impl Default for RedactorBuilder {
fn default() -> Self {
Self::new()
}
}