#[macro_export]
macro_rules! id {
(
$(#[$meta:meta])*
$id:ident
) => {
$(#[$meta])*
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
#[derive(serde::Deserialize, serde::Serialize)]
pub struct $id(u64);
#[allow(dead_code)]
impl $id {
#[cfg_attr(feature = "tracing", tracing::instrument)]
pub fn new(id: u64) -> Self {
Self(id)
}
#[cfg_attr(feature = "tracing", tracing::instrument)]
pub fn get(&self) -> u64 {
self.0
}
}
impl std::fmt::Display for $id {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl From<u64> for $id {
#[cfg_attr(feature = "tracing", tracing::instrument)]
fn from(id: u64) -> $id {
$id(id)
}
}
};
}
#[macro_export]
macro_rules! name {
(
$(#[$meta:meta])*
$name:ident
) => {
$(#[$meta])*
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
#[derive(serde::Deserialize, serde::Serialize)]
pub struct $name(String);
#[allow(dead_code)]
impl $name {
#[cfg_attr(feature = "tracing", tracing::instrument)]
pub fn new(name: &str) -> Self {
Self(name.into())
}
#[cfg_attr(feature = "tracing", tracing::instrument)]
pub fn get(&self) -> &str {
&self.0
}
}
impl std::fmt::Display for $name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl From<&str> for $name {
#[cfg_attr(feature = "tracing", tracing::instrument)]
fn from(string: &str) -> $name {
$name(string.into())
}
}
impl From<String> for $name {
#[cfg_attr(feature = "tracing", tracing::instrument)]
fn from(string: String) -> $name {
$name(string)
}
}
};
}
#[macro_export]
macro_rules! secret {
(
$(#[$meta:meta])*
$secret:ident
) => {
$(#[$meta])*
#[derive(Clone, Debug)]
pub struct $secret(secrecy::SecretString);
#[allow(dead_code)]
impl $secret {
#[cfg_attr(feature = "tracing", tracing::instrument)]
pub fn new(secret: &str) -> Self {
Self(secrecy::SecretString::new(String::from(secret)))
}
#[cfg_attr(feature = "tracing", tracing::instrument)]
pub fn expose(&self) -> &str {
use secrecy::ExposeSecret;
self.0.expose_secret()
}
}
impl std::fmt::Display for $secret {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "[REDACTED]")
}
}
impl From<&str> for $secret {
#[cfg_attr(feature = "tracing", tracing::instrument)]
fn from(secret: &str) -> $secret {
$secret(secrecy::SecretString::new(String::from(secret)))
}
}
impl From<String> for $secret {
#[cfg_attr(feature = "tracing", tracing::instrument)]
fn from(secret: String) -> $secret {
$secret(secrecy::SecretString::new(secret))
}
}
};
}
#[cfg(test)]
mod tests {
use crate::{id, name};
id!(
TestId
);
#[test]
fn id() {
let id = TestId::new(42);
assert_eq!(42, id.get());
assert_eq!("42", id.to_string());
}
#[test]
fn id_from_u64() {
let _id: TestId = 42.into();
}
name!(
TestName
);
#[test]
fn name() {
let name = TestName::new("test");
assert_eq!("test", name.get());
assert_eq!("test", name.to_string());
}
#[test]
fn name_from_str() {
let _name: TestName = "test".into();
}
#[test]
fn name_from_string() {
let _name: TestName = String::from("test").into();
}
secret!(
TestSecret
);
#[test]
fn secret() {
let secret = TestSecret::new("test");
assert_eq!("test", secret.expose());
assert_eq!("[REDACTED]", secret.to_string());
}
#[test]
fn secret_from_str() {
let _secret: TestSecret = "test".into();
}
#[test]
fn secret_from_string() {
let _secret: TestSecret = String::from("test").into();
}
}