From 0eaf310f292a610c502cac92f4957af66c0b4a82 Mon Sep 17 00:00:00 2001 From: Luca Palmieri Date: Wed, 9 Dec 2020 17:20:15 +0000 Subject: [PATCH] Add SubscriberName constructor. --- Cargo.lock | 1 + Cargo.toml | 1 + src/domain.rs | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 1f1cd45..b947c80 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2901,5 +2901,6 @@ dependencies = [ "tracing-futures", "tracing-log", "tracing-subscriber", + "unicode-segmentation", "uuid", ] diff --git a/Cargo.toml b/Cargo.toml index d162c25..044e166 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ tracing-bunyan-formatter = "0.1.6" tracing-log = "0.1.1" tracing-actix-web = "0.2.0" serde-aux = "1.0.1" +unicode-segmentation = "1.7.1" [dev-dependencies] reqwest = { version = "0.10.7", features = ["json"] } diff --git a/src/domain.rs b/src/domain.rs index 8f37567..df654a7 100644 --- a/src/domain.rs +++ b/src/domain.rs @@ -1 +1,39 @@ +use unicode_segmentation::UnicodeSegmentation; + 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) -> SubscriberName { + // `.trim()` returns a view over the input `s` without trailing + // whitespace-like characters. + // `.is_empty` checks if the view contains any character. + let is_empty_or_whitespace = s.trim().is_empty(); + + // A grapheme is defined by the Unicode standard as a "user-perceived" + // character: `å` is a single grapheme, but it is composed of two characters + // (`a` and `̊`). + // + // `graphemes` returns an iterator over the graphemes in the input `s`. + // `true` specifies that we want to use the extended grapheme definition set, + // the recommended one. + let is_too_long = s.graphemes(true).count() > 256; + + // Iterate over all characters in the input `s` to check if any of them matches + // one of the characters in the forbidden array. + let forbidden_characters = ['/', '(', ')', '"', '<', '>', '\\', '{', '}']; + let contains_forbidden_characters = s + .chars() + .filter(|g| forbidden_characters.contains(g)) + .count() + > 0; + + if is_empty_or_whitespace || is_too_long || contains_forbidden_characters { + panic!(format!("{} is not a valid subscriber name.", s)) + } else { + Self(s) + } + } +}