1#![deny(warnings)]
5#![warn(unused_extern_crates)]
6#![deny(clippy::todo)]
7#![deny(clippy::unimplemented)]
8#![deny(clippy::unwrap_used)]
9#![deny(clippy::expect_used)]
10#![deny(clippy::panic)]
11#![deny(clippy::unreachable)]
12#![deny(clippy::await_holding_lock)]
13#![deny(clippy::needless_pass_by_value)]
14#![deny(clippy::trivially_copy_pass_by_ref)]
15
16use std::fmt::Debug;
17
18pub struct SecretString<T>(T)
28where
29 T: AsRef<str>;
30
31impl<T: AsRef<str>> SecretString<T> {
32 pub fn new(s: T) -> Self {
33 SecretString(s)
34 }
35
36 pub fn value(&self) -> &str {
37 self.0.as_ref()
38 }
39
40 fn as_stars(&self) -> String {
41 self.0.as_ref().bytes().map(|_| "*").collect::<String>()
42 }
43}
44
45impl<T: AsRef<str>> std::fmt::Display for SecretString<T> {
46 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
47 write!(f, "{}", self.as_stars())
48 }
49}
50
51impl Debug for SecretString<&str> {
52 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53 write!(f, "SecretString({})", self.as_stars())
54 }
55}
56
57#[cfg(test)]
58mod tests {
59 use super::SecretString;
60
61 #[test]
62 fn test_secret_string_display() {
63 let secret = SecretString::new("my_secret_password");
64 assert_eq!(format!("{}", secret), "******************");
65 }
66
67 #[test]
68 fn test_secret_string_debug() {
69 let secret = SecretString::new("my_secret_password");
70 assert_eq!(format!("{:?}", secret), "SecretString(******************)");
71 }
72 #[test]
73 fn test_secret_string_value() {
74 let secret = SecretString::new("my_secret_password");
75 assert_eq!(secret.value(), "my_secret_password");
76 }
77}