use crate::{
__private::{
PolicyApplicableRefForGeneratedFormatting, PolicyField, PolicyFieldRef,
PolicyFormattingOutput,
},
policy::{RecursivePolicyKind, RedactionPolicy},
redaction::traits::{RedactableWithMapper, SensitiveWithPolicy},
};
pub(super) fn collect_policy_formatting<T, C>(
values: impl IntoIterator<Item = PolicyFormattingOutput<T>>,
) -> PolicyFormattingOutput<C>
where
C: FromIterator<T>,
{
let collected = values
.into_iter()
.map(|value| match value {
PolicyFormattingOutput::Value(value) => Some(value),
PolicyFormattingOutput::Borrowed => None,
})
.collect::<Option<C>>();
collected.map_or_else(
|| PolicyFormattingOutput::Borrowed,
PolicyFormattingOutput::Value,
)
}
#[doc(hidden)]
pub trait RedactableMapper {
fn map_sensitive<V, P>(&self, value: V) -> V
where
V: SensitiveWithPolicy<P>,
P: RedactionPolicy;
fn map_scalar<S>(&self, value: S) -> S
where
S: Default + ScalarRedaction;
#[doc(hidden)]
fn debug_alternate(&self) -> bool {
false
}
}
#[derive(Clone, Copy, Debug)]
#[doc(hidden)]
pub struct PolicyMapper;
impl RedactableMapper for PolicyMapper {
fn map_sensitive<V, P>(&self, value: V) -> V
where
V: SensitiveWithPolicy<P>,
P: RedactionPolicy,
{
value.redact_with_policy(&P::policy())
}
fn map_scalar<S>(&self, value: S) -> S
where
S: Default + ScalarRedaction,
{
ScalarRedaction::redact(value)
}
}
#[derive(Clone, Copy, Debug)]
#[doc(hidden)]
pub struct PolicyFormattingMapper {
debug_alternate: bool,
}
impl PolicyFormattingMapper {
#[must_use]
pub fn new(debug_alternate: bool) -> Self {
Self { debug_alternate }
}
}
impl RedactableMapper for PolicyFormattingMapper {
fn map_sensitive<V, P>(&self, value: V) -> V
where
V: SensitiveWithPolicy<P>,
P: RedactionPolicy,
{
PolicyMapper.map_sensitive::<V, P>(value)
}
fn map_scalar<S>(&self, value: S) -> S
where
S: Default + ScalarRedaction,
{
PolicyMapper.map_scalar(value)
}
fn debug_alternate(&self) -> bool {
self.debug_alternate
}
}
#[doc(hidden)]
pub trait ScalarRedaction: Default {
#[must_use]
fn redact(self) -> Self {
Self::default()
}
}
impl ScalarRedaction for i8 {}
impl ScalarRedaction for i16 {}
impl ScalarRedaction for i32 {}
impl ScalarRedaction for i64 {}
impl ScalarRedaction for i128 {}
impl ScalarRedaction for isize {}
impl ScalarRedaction for u8 {}
impl ScalarRedaction for u16 {}
impl ScalarRedaction for u32 {}
impl ScalarRedaction for u64 {}
impl ScalarRedaction for u128 {}
impl ScalarRedaction for usize {}
impl ScalarRedaction for f32 {}
impl ScalarRedaction for f64 {}
impl ScalarRedaction for bool {}
impl ScalarRedaction for char {
fn redact(self) -> Self {
'*'
}
}
pub fn redact<W>(value: W) -> W
where
W: RedactableWithMapper,
{
let mapper = PolicyMapper;
value.redact_with(&mapper)
}
pub fn apply_policy<P, V>(value: V) -> V
where
P: RedactionPolicy,
V: PolicyField<P>,
{
let mapper = PolicyMapper;
value.apply_field(&mapper)
}
pub fn apply_policy_ref<P, V>(value: &V) -> <V as PolicyFieldRef<P>>::Output
where
P: RedactionPolicy,
V: PolicyFieldRef<P> + ?Sized,
{
let mapper = PolicyMapper;
value.apply_field_ref(&mapper)
}
#[diagnostic::on_unimplemented(
message = "`{Self}` cannot have a policy applied",
label = "this type doesn't support redaction policies",
note = "policies work on String, Cow<str>, and containers of these types",
note = "for custom values, implement `SensitiveWithPolicy<YourPolicy>` and wrap them in `SensitiveValue<T, YourPolicy>`"
)]
#[doc(hidden)]
pub trait PolicyApplicable {
#[must_use]
fn apply_policy<P, M>(self, mapper: &M) -> Self
where
P: RedactionPolicy,
P::Kind: RecursivePolicyKind,
M: RedactableMapper;
}
#[doc(hidden)]
pub trait PolicyApplicableRef {
type Output;
#[must_use]
fn apply_policy_ref<P, M>(&self, mapper: &M) -> Self::Output
where
P: RedactionPolicy,
P::Kind: RecursivePolicyKind,
M: RedactableMapper;
}
pub(super) fn apply_child_policy_ref_for_formatting<P, T, M>(
value: &T,
mapper: &M,
) -> PolicyFormattingOutput<T::FormattingOutput>
where
P: RedactionPolicy,
P::Kind: RecursivePolicyKind,
T: PolicyApplicableRefForGeneratedFormatting,
M: RedactableMapper,
{
value.apply_policy_ref_for_generated_formatting::<P, M>(mapper)
}