1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use inquire::validator::{ErrorMessage, Validation};
use inquire::{Confirm, Text};
use rust_decimal::Decimal;
use solana_sdk::pubkey::Pubkey;
use std::fs::File;
use std::str::FromStr;

pub trait Parser {
    fn to_pubkey(self) -> Result<Pubkey, Box<dyn std::error::Error>>;
    fn to_u128(self) -> Result<u128, Box<dyn std::error::Error>>;
    fn to_u64(self) -> Result<u64, Box<dyn std::error::Error>>;
    fn to_u16(self) -> Result<u16, Box<dyn std::error::Error>>;
    fn to_f64(self) -> Result<f64, Box<dyn std::error::Error>>;
    fn to_file(self) -> Result<String, Box<dyn std::error::Error>>;
    fn to_string(self) -> Result<String, Box<dyn std::error::Error>>;
    fn to_decimal(self) -> Result<Decimal, Box<dyn std::error::Error>>;
    fn confirm() -> Result<(), Box<dyn std::error::Error>>;
}

impl Parser for Text<'_> {
    fn to_pubkey(self) -> Result<Pubkey, Box<dyn std::error::Error>> {
        let s = self
            .with_validator(|s: &str| match Pubkey::from_str(s).is_err() {
                true => Ok(Validation::Invalid(ErrorMessage::Custom(
                    "wrong address".to_string(),
                ))),
                false => Ok(Validation::Valid),
            })
            .prompt()?;
        Ok(Pubkey::from_str(s.as_str()).unwrap())
    }

    fn to_u128(self) -> Result<u128, Box<dyn std::error::Error>> {
        let s = self
            .with_validator(|s: &str| match s.parse::<u128>().is_err() {
                true => Ok(Validation::Invalid(ErrorMessage::Custom(
                    "wrong number with u128".to_string(),
                ))),
                false => Ok(Validation::Valid),
            })
            .prompt()?;
        Ok(s.parse::<u128>().unwrap())
    }

    fn to_u64(self) -> Result<u64, Box<dyn std::error::Error>> {
        let s = self
            .with_validator(|s: &str| match s.parse::<u64>().is_err() {
                true => Ok(Validation::Invalid(ErrorMessage::Custom(
                    "wrong number with u64".to_string(),
                ))),
                false => Ok(Validation::Valid),
            })
            .prompt()?;
        Ok(s.parse::<u64>().unwrap())
    }

    fn to_u16(self) -> Result<u16, Box<dyn std::error::Error>> {
        let s = self
            .with_validator(|s: &str| match s.parse::<u16>().is_err() {
                true => Ok(Validation::Invalid(ErrorMessage::Custom(
                    "wrong number with u16".to_string(),
                ))),
                false => Ok(Validation::Valid),
            })
            .prompt()?;
        Ok(s.parse::<u16>().unwrap())
    }

    fn to_f64(self) -> Result<f64, Box<dyn std::error::Error>> {
        let s = self
            .with_validator(|s: &str| match s.parse::<f64>().is_err() {
                true => Ok(Validation::Invalid(ErrorMessage::Custom(
                    "wrong number with f64".to_string(),
                ))),
                false => Ok(Validation::Valid),
            })
            .prompt()?;
        Ok(s.parse::<f64>().unwrap())
    }

    fn to_file(self) -> Result<String, Box<dyn std::error::Error>> {
        let s = self
            .with_validator(|s: &str| match File::open(s).is_err() {
                true => Ok(Validation::Invalid(ErrorMessage::Custom(
                    "wrong file path".to_string(),
                ))),
                false => Ok(Validation::Valid),
            })
            .prompt()?;
        Ok(s)
    }

    fn to_string(self) -> Result<String, Box<dyn std::error::Error>> {
        Ok(self.prompt()?)
    }

    fn to_decimal(self) -> Result<Decimal, Box<dyn std::error::Error>> {
        let s = self
            .with_validator(|s: &str| match Decimal::from_str(s).is_err() {
                true => Ok(Validation::Invalid(ErrorMessage::Custom(
                    "wrong decimal".to_string(),
                ))),
                false => Ok(Validation::Valid),
            })
            .prompt()?;
        Ok(Decimal::from_str(s.as_str()).unwrap())
    }

    fn confirm() -> Result<(), Box<dyn std::error::Error>> {
        let res = Confirm::new("Confirm this operation?")
            .with_default(false)
            .prompt();
        match res {
            Ok(true) => Ok(()),
            Ok(false) => Err(Box::<dyn std::error::Error>::from("Cancel the operation")),
            Err(_) => Err(Box::new(res.err().unwrap())),
        }
    }
}