1
use supp_macro::command;
2

            
3
#[derive(Debug)]
4
pub enum CmdError {
5
    Args(String),
6
}
7

            
8
impl std::fmt::Display for CmdError {
9
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
10
        match self {
11
            CmdError::Args(msg) => write!(f, "Argument error: {msg}"),
12
        }
13
    }
14
}
15

            
16
impl std::error::Error for CmdError {}
17

            
18
#[derive(Debug)]
19
pub enum CmdResult {
20
    Success(String),
21
    Value(i64),
22
}
23

            
24
// Define commands using the progressive types approach
25
command! {
26
    CreateUser {
27
        #[required]
28
        username: String,
29
        #[required]
30
        email: String,
31
        #[optional]
32
        is_admin: bool,
33
    } => {
34
        let admin_status = is_admin.unwrap_or(false);
35
        Ok(Some(CmdResult::Success(format!(
36
            "Created user {username} with email {email} (admin: {admin_status})"
37
        ))))
38
    }
39
}
40

            
41
command! {
42
    GetVersion {
43
    } => {
44
        Ok(Some(CmdResult::Success("v1.0.0".to_string())))
45
    }
46
}
47

            
48
command! {
49
    Calculate {
50
        #[required]
51
        a: i64,
52
        #[required]
53
        b: i64,
54
    } => {
55
        Ok(Some(CmdResult::Value(a + b)))
56
    }
57
}
58

            
59
#[tokio::main]
60
async fn main() -> Result<(), Box<dyn std::error::Error>> {
61
    println!("šŸš€ Progressive Types Command Demo");
62
    println!("===================================");
63

            
64
    // āœ… SIMPLE INTERFACE - No Args types visible to users!
65

            
66
    println!("\n1. Simple command with no arguments:");
67
    let result = GetVersion::new().run().await?;
68
    println!("   Result: {result:?}");
69

            
70
    println!("\n2. Command with required arguments (compile-time validated):");
71
    let result = Calculate::new()
72
        .a(10) // āœ… i64 type enforced at compile time
73
        .b(20) // āœ… i64 type enforced at compile time
74
        .run() // āœ… Only available when all required fields set
75
        .await?;
76
    println!("   Result: {result:?}");
77

            
78
    println!("\n3. Command with mixed required and optional arguments:");
79
    let result = CreateUser::new()
80
        .username("alice".to_string()) // āœ… Required
81
        .email("alice@example.com".to_string()) // āœ… Required
82
        .is_admin(true) // āœ… Optional
83
        .run()
84
        .await?;
85
    println!("   Result: {result:?}");
86

            
87
    println!("\n4. Same command with minimal arguments (optional fields omitted):");
88
    let result = CreateUser::new()
89
        .username("bob".to_string()) // āœ… Required
90
        .email("bob@example.com".to_string()) // āœ… Required
91
        // is_admin omitted - will be None/false
92
        .run()
93
        .await?;
94
    println!("   Result: {result:?}");
95

            
96
    println!("\nāœ… Features demonstrated:");
97
    println!("   - Zero Args type naming (users never see *Args structs)");
98
    println!("   - Compile-time type validation (wrong types = compile error)");
99
    println!("   - Compile-time required field validation (missing fields = compile error)");
100
    println!("   - Zero runtime checks (direct field access, no unwrap())");
101
    println!("   - Clean, intuitive interface (Command::new().field().run())");
102

            
103
    // Uncomment these to see compile-time errors:
104

            
105
    // āŒ This would NOT compile - missing required field:
106
    // let result = CreateUser::new()
107
    //     .username("incomplete".to_string())
108
    //     .run()  // ERROR: no method named `run` found
109
    //     .await?;
110

            
111
    // āŒ This would NOT compile - wrong type:
112
    // let result = Calculate::new()
113
    //     .a("not_a_number")  // ERROR: expected `i64`, found `&str`
114
    //     .b(20)
115
    //     .run()
116
    //     .await?;
117

            
118
    // āŒ This would NOT compile - method doesn't exist:
119
    // let result = GetVersion::new()
120
    //     .invalid_method("test")  // ERROR: no method named `invalid_method`
121
    //     .run()
122
    //     .await?;
123

            
124
    Ok(())
125
}