1use core::fmt;
20use core::ops::Deref;
21
22#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
23pub struct Pii<T>(pub T);
24
25impl<T: fmt::Display> fmt::Display for Pii<T> {
26 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27 #[cfg(feature = "pii")]
28 {
29 write!(f, "{{REDACTED}}")
30 }
31 #[cfg(not(feature = "pii"))]
32 {
33 write!(f, "{}", self.0)
34 }
35 }
36}
37
38impl<T: fmt::Debug> fmt::Debug for Pii<T> {
39 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40 #[cfg(feature = "pii")]
41 {
42 write!(f, "{{REDACTED}}")
43 }
44 #[cfg(not(feature = "pii"))]
45 {
46 write!(f, "{:?}", self.0)
47 }
48 }
49}
50
51impl<T> Deref for Pii<T> {
52 type Target = T;
53
54 fn deref(&self) -> &Self::Target {
55 &self.0
56 }
57}
58
59#[cfg(test)]
60mod tests {
61 use super::*;
62 use std::net::{IpAddr, Ipv4Addr, SocketAddr};
63
64 #[test]
65 fn socket_addr_display() {
66 let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
67 let pii_addr = Pii(addr);
68
69 #[cfg(feature = "pii")]
70 assert_eq!(pii_addr.to_string(), "{REDACTED}");
71
72 #[cfg(not(feature = "pii"))]
73 assert_eq!(pii_addr.to_string(), "127.0.0.1:8080");
74 }
75
76 #[test]
77 fn string_display() {
78 let sensitive = String::from("sensitive data");
79 let pii_string = Pii(sensitive);
80
81 #[cfg(feature = "pii")]
82 assert_eq!(pii_string.to_string(), "{REDACTED}");
83
84 #[cfg(not(feature = "pii"))]
85 assert_eq!(pii_string.to_string(), "sensitive data");
86 }
87}