secret-value 0.1.0

Prevents values from being displayed or logged.
Documentation
use std::{fmt, ops};

#[repr(transparent)]
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash, Default)]
pub struct Secret<T>(T);

impl<T> From<T> for Secret<T> {
    fn from(t: T) -> Self {
        Self(t)
    }
}

impl<T> Secret<T> {
    pub fn inner(self) -> T {
        self.0
    }
}

impl<T> ops::Deref for Secret<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<T> ops::DerefMut for Secret<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

impl<T> fmt::Debug for Secret<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "<hidden>")
    }
}

impl<T> fmt::Display for Secret<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "<hidden>")
    }
}

#[cfg(feature = "serde")]
mod serde {
    use serde::{Deserialize, Deserializer, Serialize, Serializer};

    use super::Secret;

    impl<'de, T: Deserialize<'de>> Deserialize<'de> for Secret<T> {
        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where
            D: Deserializer<'de>,
        {
            T::deserialize(deserializer).map(Self)
        }
    }

    impl<T: Serialize> Serialize for super::Secret<T> {
        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where
            S: Serializer,
        {
            serializer.serialize_str("<hidden>")
        }
    }

    pub fn insecure_serialize<T: Serialize, S>(x: &Secret<T>, s: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        x.0.serialize(s)
    }
}

#[cfg(feature = "serde")]
pub use self::serde::insecure_serialize;

#[cfg(test)]
mod tests {
    use super::*;

    #[cfg(feature = "serde")]
    #[test]
    fn test_insecure_serialize() {
        use serde_test::{assert_tokens, Token};
        #[derive(::serde::Serialize, ::serde::Deserialize, PartialEq, Debug)]
        struct X {
            #[serde(serialize_with = "insecure_serialize")]
            y: Secret<u32>,
        }
        let x = X { y: Secret(1) };
        assert_tokens(
            &x,
            &[
                Token::Struct { name: "X", len: 1 },
                Token::Str("y"),
                Token::U32(1),
                Token::StructEnd,
            ],
        );
    }

    #[cfg(feature = "serde")]
    #[test]
    fn test_secure_serialize() {
        use serde_test::{assert_de_tokens, assert_ser_tokens, Token};
        #[derive(::serde::Serialize, ::serde::Deserialize, PartialEq, Debug)]
        struct X {
            z: Secret<u32>,
        }
        let x = X { z: Secret(1) };
        assert_ser_tokens(
            &x,
            &[
                Token::Struct { name: "X", len: 1 },
                Token::Str("z"),
                Token::Str("<hidden>"),
                Token::StructEnd,
            ],
        );
        assert_de_tokens(
            &x,
            &[
                Token::Struct { name: "X", len: 1 },
                Token::Str("z"),
                Token::U32(1),
                Token::StructEnd,
            ],
        );
    }
}