1pub struct Secret<T>(T);
38
39impl<T> Secret<T> {
40 pub fn new(value: T) -> Self {
41 Self(value)
42 }
43
44 pub fn expose(self) -> T {
45 self.0
46 }
47
48 pub fn expose_ref(&self) -> &T {
49 &self.0
50 }
51}
52
53impl<T: Clone> Secret<T> {
54 pub fn expose_clone(&self) -> T {
55 self.0.clone()
56 }
57}
58
59impl<T: Copy> Secret<T> {
60 pub fn expose_copy(&self) -> T {
61 self.0
62 }
63}
64
65impl<T> From<T> for Secret<T> {
66 fn from(value: T) -> Self {
67 Self::new(value)
68 }
69}
70
71impl<T: Clone> Clone for Secret<T> {
72 fn clone(&self) -> Self {
73 Self(self.0.clone())
74 }
75}
76
77impl<T: Copy> Copy for Secret<T> {}
78
79impl<T: PartialEq> PartialEq for Secret<T> {
80 fn eq(&self, other: &Self) -> bool {
81 self.0.eq(&other.0)
82 }
83}
84
85impl<T: Eq> Eq for Secret<T> {}
86
87impl<T: PartialOrd> PartialOrd for Secret<T> {
88 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
89 self.0.partial_cmp(&other.0)
90 }
91}
92
93impl<T: Ord> Ord for Secret<T> {
94 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
95 self.0.cmp(&other.0)
96 }
97}
98
99impl<T> core::fmt::Debug for Secret<T> {
100 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
101 f.write_fmt(format_args!("Secret<{}>", core::any::type_name::<T>()))
102 }
103}
104
105impl<T: core::hash::Hash> core::hash::Hash for Secret<T> {
106 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
107 self.0.hash(state)
108 }
109}
110
111#[cfg(feature = "serde")]
112mod serde {
113 use super::Secret;
114
115 impl<T: serde::Serialize> serde::Serialize for Secret<T> {
116 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
117 where
118 S: serde::Serializer,
119 {
120 self.0.serialize(serializer)
121 }
122 }
123
124 #[cfg(feature = "serde")]
125 impl<'de, T: serde::Deserialize<'de>> serde::Deserialize<'de> for Secret<T> {
126 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
127 where
128 D: serde::Deserializer<'de>,
129 {
130 T::deserialize(deserializer).map(Secret)
131 }
132 }
133}
134
135#[cfg(feature = "schemars")]
136mod schemars {
137 use super::Secret;
138 extern crate alloc;
139
140 impl<T: schemars::JsonSchema> schemars::JsonSchema for Secret<T> {
141 fn schema_id() -> alloc::borrow::Cow<'static, str> {
142 T::schema_id()
143 }
144
145 fn schema_name() -> alloc::borrow::Cow<'static, str> {
146 T::schema_name()
147 }
148
149 fn inline_schema() -> bool {
150 T::inline_schema()
151 }
152
153 fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
154 T::json_schema(generator)
155 }
156 }
157}
158
159#[cfg(feature = "sqlx")]
160mod sqlx_impls {
161 impl<DB: sqlx::Database, T: sqlx::Type<DB>> sqlx::Type<DB> for Secret<T> {
162 fn type_info() -> DB::TypeInfo {
163 T::type_info()
164 }
165
166 fn compatible(ty: &DB::TypeInfo) -> bool {
167 T::compatible(ty)
168 }
169 }
170}
171
172#[cfg(test)]
173mod tests {
174 use super::Secret;
175
176 #[test]
177 fn debug_should_output_type_only() {
178 let secret = Secret::new("Hello, world!");
179
180 assert_eq!(format!("{secret:#?}"), "Secret<&str>");
181 }
182}