#[derive(ValueObject)]
{
// Attributes available to this derive:
#[vo]
}
Expand description
Derives ValueObject, Wrapped, TryFrom<Inner>, From<Self> for Inner, and Display for a single-field tuple struct.
§Requirements
The target must be a tuple struct with exactly one field, and that
field must not be pub. A pub field would let callers construct the
type directly (Email("anything".into())), bypassing the validation
this derive puts into the generated TryFrom impl - so both violations
are rejected at compile time rather than left as a foot-gun.
§Attributes
All are passed as #[vo(...)] on the struct itself:
validate = "path::to::fn"- runsfn(&Inner) -> Result<(), ValidationError>inside the generatedTryFrombefore the value is constructed. Without it,TryFrom::ErrorisInfallible.no_display- skips the generatedDisplayimpl, so a hand-written one can be provided instead.
rename_all and zeroize are rejected here: rename_all only affects
EnumVo’s variant names, and zeroize only makes
sense on SecretVo, which owns a value worth
scrubbing from memory on drop.
§Examples
use ddd_toolkit_core::domain::{ValidationError, Wrapped};
use ddd_toolkit_macro::ValueObject;
#[derive(ValueObject, Clone, PartialEq, Debug)]
#[vo(validate = "validate_email")]
struct Email(String);
fn validate_email(s: &str) -> Result<(), ValidationError> {
if s.contains('@') {
Ok(())
} else {
Err(ValidationError::new("Email", "missing @"))
}
}
let email = Email::try_from("a@b.com".to_string())?;
assert_eq!(email.as_inner(), "a@b.com");
assert_eq!(email.to_string(), "a@b.com");
assert!(Email::try_from("no-at-sign".to_string()).is_err());