use std::fmt;
pub struct Secret<T>(T);
impl<T> Secret<T> {
#[inline]
pub fn new(value: T) -> Self {
Self(value)
}
#[inline]
pub fn expose(&self) -> &T {
&self.0
}
#[inline]
pub fn into_inner(self) -> T {
self.0
}
}
impl<T> fmt::Debug for Secret<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "<redacted>")
}
}
impl<T> fmt::Display for Secret<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "<redacted>")
}
}
impl<T: Clone> Clone for Secret<T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<T: PartialEq> PartialEq for Secret<T> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<T: Eq> Eq for Secret<T> {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn debug_is_redacted() {
let s = Secret::new("hunter2".to_string());
assert_eq!(format!("{s:?}"), "<redacted>");
}
#[test]
fn display_is_redacted() {
let s = Secret::new(42u32);
assert_eq!(format!("{s}"), "<redacted>");
}
#[test]
fn expose_returns_inner() {
let s = Secret::new("value");
assert_eq!(*s.expose(), "value");
}
#[test]
fn into_inner_unwraps() {
let s = Secret::new(99u8);
assert_eq!(s.into_inner(), 99);
}
#[test]
fn clone_and_eq() {
let a = Secret::new("x".to_string());
let b = a.clone();
assert_eq!(a, b);
}
}