use inquire::validator::{ErrorMessage, Validation};
use inquire::{Confirm, Text};
use rust_decimal::Decimal;
use std::fs::File;
use std::str::FromStr;
pub trait Parser {
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>>;
fn confirm_with_prompt(message: &str) -> Result<(), Box<dyn std::error::Error>>;
}
impl Parser for Text<'_> {
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())),
}
}
fn confirm_with_prompt(message: &str) -> Result<(), Box<dyn std::error::Error>> {
let res = Confirm::new(message).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())),
}
}
}