#[derive(SecretVo)]
{
// Attributes available to this derive:
#[vo]
}
Expand description
Derives SecretVo for a single-field tuple struct, with a Debug
impl that always redacts the wrapped value.
Unlike ValueObject, this derive generates its
own Debug impl (printing TypeName(***), never the wrapped value) -
so the target must not derive or implement Debug itself, or the two
impls collide (E0119). It never generates Display either, which is
why no_display is rejected here: there is nothing for it to suppress.
See derive_value_object for the shared single-field-tuple-struct
requirement and the validate attribute, which behaves identically
here. rename_all is rejected for the same reason as on ValueObject.
§Attributes
validate = "path::to::fn"- seederive_value_object.zeroize- generates aDropimpl that callsZeroize::zeroizeon the wrapped value when it goes out of scope. Requires this crate’s ownzeroizeCargo feature to be enabled, and the calling crate to depend on thezeroizecrate directly (the generatedDropimpl references it by a bare path, which only resolves at the call site). Without the feature enabled,#[vo(zeroize)]is rejected at compile time with a message naming both requirements, rather than failing later with a confusing unresolved-crate error.
§Examples
use ddd_toolkit_core::domain::SecretVo;
use ddd_toolkit_macro::SecretVo as DeriveSecretVo;
#[derive(Clone, PartialEq, DeriveSecretVo)]
struct ApiKey(String);
let secret = ApiKey::try_new("sekret".to_string())?;
assert_eq!(secret.expose_secret(), "sekret");
let debug = format!("{secret:?}");
assert_eq!(debug, "ApiKey(***)");
assert!(!debug.contains("sekret"));With the zeroize feature enabled on this crate, and zeroize in the
caller’s own dependencies:
ⓘ
use ddd_toolkit_core::domain::SecretVo;
use ddd_toolkit_macro::SecretVo as DeriveSecretVo;
#[derive(Clone, PartialEq, DeriveSecretVo)]
#[vo(zeroize)]
struct ZeroizingSecret([u8; 4]);
let secret = ZeroizingSecret::try_new([1, 2, 3, 4])?;
drop(secret); // wipes the inner bytes on the way out