1use serde::{Serialize, Deserialize};
49
50
51pub struct Secret<T> {
52 inner: T,
53}
54
55impl<T> Secret<T> {
56 pub fn new(inner: T) -> Self {
57 Self { inner }
58 }
59
60 pub fn leak_mut(&mut self) -> &mut T {
61 &mut self.inner
62 }
63
64 pub fn leak_ref(&self) -> &T {
65 &self.inner
66 }
67
68 pub fn leak_owned(self) -> T {
69 self.inner
70 }
71}
72
73impl<T> std::fmt::Debug for Secret<T> {
74 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
75 write!(f, "[redacted]")
76 }
77}
78
79impl<T: Clone> Clone for Secret<T> {
80 fn clone(&self) -> Self {
81 Self {
82 inner: self.inner.clone()
83 }
84 }
85}
86
87impl <T: Copy> Copy for Secret<T> {}
88
89impl<T: PartialEq> PartialEq for Secret<T> {
90 fn eq(&self, other: &Self) -> bool {
91 T::eq(&self.inner, &other.inner)
92 }
93
94 fn ne(&self, other: &Self) -> bool {
95 T::ne(&self.inner, &other.inner)
96 }
97}
98
99impl<T: Eq> Eq for Secret<T> {}
100
101impl<T: Serialize> Serialize for Secret<T> {
102 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
103 self.inner.serialize(serializer)
104 }
105}
106
107impl<'de, T: Deserialize<'de>> Deserialize<'de> for Secret<T> {
108 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
109 T::deserialize(deserializer).map(|x| Secret::new(x))
110 }
111}
112
113impl<T> From<T> for Secret<T> {
114 fn from(value: T) -> Self {
115 Secret::new(value)
116 }
117}
118
119#[cfg(test)]
120mod test {
121
122 use super::Secret;
123 use std::io::Write;
124
125 #[test]
126 fn debug_format_is_redacted() {
127 let secret = Secret::new(String::from("my-secret"));
128
129 let mut vec = Vec::new();
130 write!(vec, "{:?}", &secret).expect("Can write to Vec");
131 assert_eq!(String::from_utf8(vec).unwrap(), "[redacted]");
132 }
133
134 #[test]
135 fn cannot_pretty_print_by_accident() {
136 let secret = Secret::new(String::from("my-secret"));
137
138 let mut vec = Vec::new();
139 write!(vec, "{:#?}", &secret).expect("Can write to vec");
140 assert_eq!(String::from_utf8(vec).unwrap(), "[redacted]");
141 }
142
143 }