oxidite_utils/
validation.rs1use regex::Regex;
4use std::sync::OnceLock;
5
6fn email_regex() -> &'static Regex {
7 static EMAIL: OnceLock<Regex> = OnceLock::new();
8 EMAIL.get_or_init(|| {
9 Regex::new(r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$")
10 .expect("email regex must compile")
11 })
12}
13
14fn url_regex() -> &'static Regex {
15 static URL: OnceLock<Regex> = OnceLock::new();
16 URL.get_or_init(|| {
17 Regex::new(r"^https?://[a-zA-Z0-9][-a-zA-Z0-9]*(\.[a-zA-Z0-9][-a-zA-Z0-9]*)*(:\d+)?(/.*)?$")
18 .expect("url regex must compile")
19 })
20}
21
22fn phone_regex() -> &'static Regex {
23 static PHONE: OnceLock<Regex> = OnceLock::new();
24 PHONE
25 .get_or_init(|| Regex::new(r"^\+?[0-9]{10,15}$").expect("phone regex must compile"))
26}
27
28pub fn is_email(s: &str) -> bool {
30 email_regex().is_match(s)
31}
32
33pub fn is_url(s: &str) -> bool {
35 url_regex().is_match(s)
36}
37
38pub fn is_phone(s: &str) -> bool {
40 phone_regex().is_match(s.replace(['-', ' ', '(', ')'], "").as_str())
41}
42
43pub fn is_alphanumeric(s: &str) -> bool {
45 !s.is_empty() && s.chars().all(|c| c.is_alphanumeric())
46}
47
48pub fn is_numeric(s: &str) -> bool {
50 !s.is_empty() && s.chars().all(|c| c.is_ascii_digit())
51}
52
53pub fn min_length(s: &str, min: usize) -> bool {
55 s.len() >= min
56}
57
58pub fn max_length(s: &str, max: usize) -> bool {
60 s.len() <= max
61}
62
63pub fn length_between(s: &str, min: usize, max: usize) -> bool {
65 min_length(s, min) && max_length(s, max)
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71
72 #[test]
73 fn test_is_email() {
74 assert!(is_email("test@example.com"));
75 assert!(is_email("user.name+tag@domain.co.uk"));
76 assert!(!is_email("invalid"));
77 assert!(!is_email("@example.com"));
78 }
79
80 #[test]
81 fn test_is_url() {
82 assert!(is_url("https://example.com"));
83 assert!(is_url("http://localhost:3000/path"));
84 assert!(!is_url("not-a-url"));
85 assert!(!is_url("ftp://example.com"));
86 }
87
88 #[test]
89 fn test_is_phone() {
90 assert!(is_phone("+1234567890"));
91 assert!(is_phone("123-456-7890"));
92 assert!(is_phone("(123) 456-7890"));
93 assert!(!is_phone("12345"));
94 }
95
96 #[test]
97 fn test_length_validators() {
98 assert!(min_length("hello", 3));
99 assert!(!min_length("hi", 3));
100 assert!(max_length("hi", 5));
101 assert!(!max_length("hello world", 5));
102 assert!(length_between("hello", 3, 10));
103 }
104
105 #[test]
106 fn test_numeric_is_ascii_only() {
107 assert!(is_numeric("12345"));
108 assert!(!is_numeric("١٢٣"));
109 }
110}