1use derive_wizard::Wizard;
8
9#[derive(Debug, Wizard)]
10#[allow(dead_code)]
11struct ServerConfig {
12 #[prompt("Enter server address (host:port):")]
13 #[validate("validate_address")]
14 address: String,
15
16 #[prompt("Enter admin username:")]
17 #[validate("validate_username")]
18 username: String,
19
20 #[prompt("Enter admin email:")]
21 #[validate("validate_email")]
22 email: String,
23}
24
25pub fn validate_address(input: &str, _answers: &derive_wizard::Answers) -> Result<(), String> {
27 if input.contains(':') && input.len() >= 3 && !input.starts_with(':') && !input.ends_with(':') {
28 let parts: Vec<&str> = input.split(':').collect();
29 if parts.len() == 2 && !parts[0].is_empty() && parts[1].parse::<u16>().is_ok() {
30 return Ok(());
31 }
32 }
33 Err("Address must be in format 'host:port' (e.g., 'localhost:8080')".to_string())
34}
35
36pub fn validate_username(input: &str, _answers: &derive_wizard::Answers) -> Result<(), String> {
38 if input.len() < 3 {
39 return Err("Username must be at least 3 characters long".to_string());
40 }
41 if input.len() > 20 {
42 return Err("Username must be at most 20 characters long".to_string());
43 }
44 if !input.chars().all(|c| c.is_alphanumeric() || c == '_') {
45 return Err("Username can only contain letters, numbers, and underscores".to_string());
46 }
47 Ok(())
48}
49
50pub fn validate_email(input: &str, _answers: &derive_wizard::Answers) -> Result<(), String> {
52 if !input.contains('@') {
53 return Err("Email must contain an @ symbol".to_string());
54 }
55 let parts: Vec<&str> = input.split('@').collect();
56 if parts.len() != 2 || parts[0].is_empty() || parts[1].is_empty() {
57 return Err("Email must be in format 'user@domain'".to_string());
58 }
59 if !parts[1].contains('.') {
60 return Err("Email domain must contain a dot (e.g., example.com)".to_string());
61 }
62 Ok(())
63}
64
65fn main() {
66 let config = ServerConfig::wizard_builder().build().unwrap();
67 println!("{config:#?}");
68}