ratatui_form/validation/
rules.rs1use crate::validation::Validator;
4
5pub struct Required;
7
8impl Validator for Required {
9 fn validate(&self, value: &str) -> Result<(), String> {
10 if value.trim().is_empty() {
11 Err("This field is required".to_string())
12 } else {
13 Ok(())
14 }
15 }
16}
17
18pub struct Email;
20
21impl Validator for Email {
22 fn validate(&self, value: &str) -> Result<(), String> {
23 if value.is_empty() {
24 return Ok(()); }
26
27 let parts: Vec<&str> = value.split('@').collect();
29 if parts.len() != 2 {
30 return Err("Invalid email address".to_string());
31 }
32
33 let (local, domain) = (parts[0], parts[1]);
34
35 if local.is_empty() || domain.is_empty() {
36 return Err("Invalid email address".to_string());
37 }
38
39 if !domain.contains('.') {
40 return Err("Invalid email address".to_string());
41 }
42
43 let domain_parts: Vec<&str> = domain.split('.').collect();
44 if domain_parts.iter().any(|p| p.is_empty()) {
45 return Err("Invalid email address".to_string());
46 }
47
48 Ok(())
49 }
50}
51
52pub struct MinLength(pub usize);
54
55impl Validator for MinLength {
56 fn validate(&self, value: &str) -> Result<(), String> {
57 if value.is_empty() {
58 return Ok(()); }
60
61 if value.len() < self.0 {
62 Err(format!("Must be at least {} characters", self.0))
63 } else {
64 Ok(())
65 }
66 }
67}
68
69pub struct MaxLength(pub usize);
71
72impl Validator for MaxLength {
73 fn validate(&self, value: &str) -> Result<(), String> {
74 if value.len() > self.0 {
75 Err(format!("Must be at most {} characters", self.0))
76 } else {
77 Ok(())
78 }
79 }
80}
81
82pub struct Pattern {
84 regex: regex::Regex,
85 message: String,
86}
87
88impl Pattern {
89 pub fn new(pattern: &str, message: impl Into<String>) -> Self {
94 Self {
95 regex: regex::Regex::new(pattern).expect("Invalid regex pattern"),
96 message: message.into(),
97 }
98 }
99
100 pub fn zip_code() -> Self {
102 Self::new(r"^\d{5}(-\d{4})?$", "Invalid ZIP code format")
103 }
104
105 pub fn phone() -> Self {
107 Self::new(
108 r"^(\+1[-.\s]?)?(\(?\d{3}\)?[-.\s]?)?\d{3}[-.\s]?\d{4}$",
109 "Invalid phone number format",
110 )
111 }
112
113 pub fn date() -> Self {
115 Self::new(r"^\d{4}-\d{2}-\d{2}$", "Invalid date format (use YYYY-MM-DD)")
116 }
117}
118
119impl Validator for Pattern {
120 fn validate(&self, value: &str) -> Result<(), String> {
121 if value.is_empty() {
122 return Ok(()); }
124
125 if self.regex.is_match(value) {
126 Ok(())
127 } else {
128 Err(self.message.clone())
129 }
130 }
131}