Skip to main content Arjen Wiersma

Type-Driven Design

Rust has allows for a pattern called Type-Driven Design. In the below example a SubscriberName is created. It has a single String value. In simple code this might be represented as let subscriber_name = "Arjen".to_string();. By making the type you can wrap the validation logic into the creation of the type. This means that wherever you get a paramter of type SubscriberName you know it is valid.

rust code snippet start

#[derive(Debug)]
pub struct SubscriberName(String);

impl SubscriberName {
    /// Returns an instance of `SubscriberName` if the input satisfies all
    /// our validation constraints on subscriber names.
    /// It panics otherwise.
    pub fn parse(s: String) -> Result<SubscriberName, String> {
        let is_empty_or_whitespace = s.trim().is_empty();
        let is_too_long = s.graphemes(true).count() > 256;
        let forbidden_characters = ['/', '(', ')', '"', '<', '>', '\\', '{', '}'];
        let contains_forbidden_characters = s.chars().any(|g| forbidden_characters.contains(&g));
        if is_empty_or_whitespace || is_too_long || contains_forbidden_characters {
            Err(format!("{} is not a valid subscriber name.", s))
        } else {
            Ok(Self(s))
        }
    }
}

// Usage
let subscriber_name = SubscriberName::parse("Arjen");

rust code snippet end

The source of this knowledge is from Zero2Prod (Book) .