use std::{cell::RefCell, marker::PhantomData};
use crate::{
IpAddress, RedactableMapper, RedactableWithFormatter, RedactionPolicy, ScalarRedaction, Secret,
redaction::{PolicyApplicable, PolicyApplicableRef},
};
#[cfg(feature = "ip-address")]
use crate::SensitiveWithPolicy;
#[cfg(feature = "json")]
pub use crate::redaction::serialize_redacted_json;
#[cfg(feature = "json")]
pub use serde;
#[cfg(feature = "slog")]
pub use slog;
pub use crate::redaction::PolicyMapper;
pub trait PolicyField<P: RedactionPolicy>: Sized {
#[must_use]
fn apply_field<M: RedactableMapper>(self, mapper: &M) -> Self;
}
pub trait PolicyFieldRef<P: RedactionPolicy> {
type Output;
fn apply_field_ref<M: RedactableMapper>(&self, mapper: &M) -> Self::Output;
}
pub trait RecursivePolicyField<P: RedactionPolicy>: Sized {
#[must_use]
fn apply_recursive<M: RedactableMapper>(self, mapper: &M) -> Self;
}
pub trait RecursivePolicyFieldRef<P: RedactionPolicy> {
type Output;
fn apply_recursive_ref<M: RedactableMapper>(&self, mapper: &M) -> Self::Output;
}
impl<P, T> RecursivePolicyField<P> for T
where
P: RedactionPolicy,
T: PolicyApplicable,
{
fn apply_recursive<M: RedactableMapper>(self, mapper: &M) -> Self {
self.apply_policy::<P, M>(mapper)
}
}
impl<P, T> PolicyField<P> for T
where
P: RedactionPolicy,
T: RecursivePolicyField<P>,
{
fn apply_field<M: RedactableMapper>(self, mapper: &M) -> Self {
self.apply_recursive(mapper)
}
}
impl<P, T> RecursivePolicyFieldRef<P> for T
where
P: RedactionPolicy,
T: PolicyApplicableRef,
{
type Output = T::Output;
fn apply_recursive_ref<M: RedactableMapper>(&self, mapper: &M) -> Self::Output {
self.apply_policy_ref::<P, M>(mapper)
}
}
impl<P, T> PolicyFieldRef<P> for T
where
P: RedactionPolicy,
T: RecursivePolicyFieldRef<P>,
{
type Output = T::Output;
fn apply_field_ref<M: RedactableMapper>(&self, mapper: &M) -> Self::Output {
self.apply_recursive_ref(mapper)
}
}
macro_rules! impl_secret_scalar {
($($ty:ty),+ $(,)?) => {$ (
impl PolicyField<Secret> for $ty {
fn apply_field<M: RedactableMapper>(self, _mapper: &M) -> Self {
ScalarRedaction::redact(self)
}
}
impl PolicyFieldRef<Secret> for $ty {
type Output = $ty;
fn apply_field_ref<M: RedactableMapper>(&self, _mapper: &M) -> Self::Output {
ScalarRedaction::redact(*self)
}
}
)+ };
}
impl_secret_scalar!(
i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, f32, f64, bool, char,
);
#[cfg(feature = "ip-address")]
macro_rules! impl_ip_leaf {
($($ty:ty),+ $(,)?) => {$ (
impl PolicyField<IpAddress> for $ty {
fn apply_field<M: RedactableMapper>(self, _mapper: &M) -> Self {
<Self as SensitiveWithPolicy<IpAddress>>::redact_with_policy(
self,
&<IpAddress as RedactionPolicy>::policy(),
)
}
}
impl PolicyFieldRef<IpAddress> for $ty {
type Output = String;
fn apply_field_ref<M: RedactableMapper>(&self, _mapper: &M) -> Self::Output {
<Self as SensitiveWithPolicy<IpAddress>>::redacted_string(
self,
&<IpAddress as RedactionPolicy>::policy(),
)
}
}
)+ };
}
#[cfg(feature = "ip-address")]
impl_ip_leaf!(
std::net::Ipv4Addr,
std::net::Ipv6Addr,
std::net::IpAddr,
std::net::SocketAddr,
);
pub enum PolicyRefCellOutput<T> {
Value(RefCell<T>),
Borrowed,
}
impl<T: RedactableWithFormatter> RedactableWithFormatter for PolicyRefCellOutput<T> {
fn fmt_redacted(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Value(value) => value.fmt_redacted(f),
Self::Borrowed => f.write_str("<borrowed>"),
}
}
}
impl<T: std::fmt::Debug> std::fmt::Debug for PolicyRefCellOutput<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Value(value) => std::fmt::Debug::fmt(value, f),
Self::Borrowed => f.write_str("<borrowed>"),
}
}
}
pub struct PolicyProbe<P, F>(PhantomData<fn() -> (P, F)>);
impl<P, F> PolicyProbe<P, F> {
pub const fn new() -> Self {
Self(PhantomData)
}
}
impl<P, F> Default for PolicyProbe<P, F> {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Copy)]
pub struct BuiltinIpAddress;
#[derive(Clone, Copy)]
pub struct OtherPolicy;
pub trait ClassifyPolicy {
type Kind;
fn classify(self) -> Self::Kind;
}
macro_rules! impl_builtin_ip_probe {
($($ty:ty),+ $(,)?) => {$ (
impl ClassifyPolicy for PolicyProbe<IpAddress, $ty> {
type Kind = BuiltinIpAddress;
fn classify(self) -> Self::Kind {
BuiltinIpAddress
}
}
)+ };
}
impl_builtin_ip_probe!(
std::net::Ipv4Addr,
std::net::Ipv6Addr,
std::net::IpAddr,
std::net::SocketAddr,
);
impl<P, F> ClassifyPolicy for &PolicyProbe<P, F> {
type Kind = OtherPolicy;
fn classify(self) -> Self::Kind {
OtherPolicy
}
}
pub trait RequireNonBuiltinIp {}
impl RequireNonBuiltinIp for OtherPolicy {}
pub fn require_non_builtin_ip<T: RequireNonBuiltinIp>(_marker: T) {}