skp_validator_rules/string/
ascii.rs1use skp_validator_core::{Rule, ValidationContext, ValidationErrors, ValidationError, ValidationResult};
4
5#[derive(Debug, Clone, Default)]
20pub struct AsciiRule {
21 pub printable_only: bool,
23 pub message: Option<String>,
25}
26
27impl AsciiRule {
28 pub fn new() -> Self {
30 Self::default()
31 }
32
33 pub fn printable(mut self) -> Self {
35 self.printable_only = true;
36 self
37 }
38
39 pub fn message(mut self, msg: impl Into<String>) -> Self {
41 self.message = Some(msg.into());
42 self
43 }
44
45 fn get_message(&self) -> String {
46 self.message.clone().unwrap_or_else(|| {
47 if self.printable_only {
48 "Must contain only printable ASCII characters".to_string()
49 } else {
50 "Must contain only ASCII characters".to_string()
51 }
52 })
53 }
54}
55
56impl Rule<str> for AsciiRule {
57 fn validate(&self, value: &str, _ctx: &ValidationContext) -> ValidationResult<()> {
58 if value.is_empty() {
59 return Ok(());
60 }
61
62 let valid = if self.printable_only {
63 value.chars().all(|c| c.is_ascii() && (' '..='~').contains(&c))
64 } else {
65 value.is_ascii()
66 };
67
68 if valid {
69 Ok(())
70 } else {
71 Err(ValidationErrors::from_iter([
72 ValidationError::root("ascii", self.get_message())
73 ]))
74 }
75 }
76
77 fn name(&self) -> &'static str {
78 "ascii"
79 }
80
81 fn default_message(&self) -> String {
82 self.get_message()
83 }
84}
85
86impl Rule<String> for AsciiRule {
87 fn validate(&self, value: &String, ctx: &ValidationContext) -> ValidationResult<()> {
88 <Self as Rule<str>>::validate(self, value.as_str(), ctx)
89 }
90
91 fn name(&self) -> &'static str {
92 "ascii"
93 }
94
95 fn default_message(&self) -> String {
96 self.get_message()
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103
104 #[test]
105 fn test_ascii() {
106 let rule = AsciiRule::new();
107 let ctx = ValidationContext::default();
108
109 assert!(rule.validate("hello123", &ctx).is_ok());
110 assert!(rule.validate("Hello, World!", &ctx).is_ok());
111 assert!(rule.validate("héllo", &ctx).is_err()); assert!(rule.validate("你好", &ctx).is_err());
113 }
114
115 #[test]
116 fn test_printable_only() {
117 let rule = AsciiRule::new().printable();
118 let ctx = ValidationContext::default();
119
120 assert!(rule.validate("hello", &ctx).is_ok());
121 assert!(rule.validate("hello\t", &ctx).is_err()); assert!(rule.validate("hello\n", &ctx).is_err()); }
124
125 #[test]
126 fn test_empty_is_valid() {
127 let rule = AsciiRule::new();
128 let ctx = ValidationContext::default();
129
130 assert!(rule.validate("", &ctx).is_ok());
131 }
132}