use crate::*;
impl TryRead for () {
type Output = String;
fn try_read_line(&self, prompt: Option<String>, default: Option<Self::Output>) -> BoxResult<Self::Output> {
match (prompt, &default) {
(Some(prompt), Some(default)) => print!("{prompt}(default: {default}) "),
(None, Some(default)) => print!("(default: {default}) "),
(Some(prompt), None) => print!("{prompt}"),
(None, None) => {},
}
let output = read_stdin()?;
Ok(if output.is_empty() && let Some(default) = default {
default
} else {
output
})
}
}
pub struct NonEmptyInput;
impl TryRead for NonEmptyInput {
type Output = String;
fn try_read_line(&self, prompt: Option<String>, default: Option<Self::Output>) -> BoxResult<Self::Output> {
let mut prompt = prompt.unwrap_or_default();
if let Some(default) = default.as_ref() {
prompt += &format!("(default: {default}) ");
}
loop {
print!("{prompt}");
let input = read_stdin()?;
if input.is_empty() {
println!();
println!("Invalid input, must not be empty");
continue;
}
return BoxResult::Ok(input);
}
}
}
pub struct NonWhitespaceInput;
impl TryRead for NonWhitespaceInput {
type Output = String;
fn try_read_line(&self, prompt: Option<String>, default: Option<Self::Output>) -> BoxResult<Self::Output> {
let mut prompt = prompt.unwrap_or_default();
if let Some(default) = default.as_ref() {
prompt += &format!("(default: {default}) ");
}
loop {
print!("{prompt}");
let input = read_stdin()?;
if input.trim().is_empty() {
println!();
println!("Invalid input, must contain non-whitespace characters");
continue;
}
return BoxResult::Ok(input);
}
}
}
pub struct BoolInput;
impl TryRead for BoolInput {
type Output = bool;
fn try_read_line(&self, prompt: Option<String>, default: Option<Self::Output>) -> crate::BoxResult<Self::Output> {
let mut prompt = prompt.unwrap_or(String::from("Enter a bool: "));
if let Some(default) = default.as_ref() {
prompt += &format!("(default: {default}) ");
}
loop {
print!("{prompt}");
let input = read_stdin()?.to_lowercase();
match (&*input, default) {
("", Some(default)) => return Ok(default),
("true", _) | ("t", _) => return Ok(true),
("false", _) | ("f", _) => return Ok(false),
(_, _) => {
println!();
println!("Invalid input, please enter \"true\" or \"false\"");
}
}
}
}
}
pub struct YesNoInput;
impl TryRead for YesNoInput {
type Output = bool;
fn try_read_line(&self, prompt: Option<String>, default: Option<Self::Output>) -> crate::BoxResult<Self::Output> {
let mut prompt = prompt.unwrap_or(String::from("Enter 'Yes' or 'No': "));
if let Some(default) = default.as_ref() {
prompt += &format!("(default: {}) ", if *default {"Yes"} else {"No"});
}
loop {
print!("{prompt}");
let input = read_stdin()?.to_lowercase();
match (&*input, default) {
("", Some(default)) => return Ok(default),
("yes", _) | ("y", _) => return Ok(true),
("no", _) | ("n", _) => return Ok(false),
(_, _) => {
println!();
println!("Invalid input, please enter \"yes\" or \"no\"");
}
}
}
}
}
macro_rules! implement_number_input {
($type_name:tt, $type_base:ty, $default_prompt:expr) => {
impl TryRead for $type_name {
type Output = $type_base;
fn try_read_line(&self, prompt: Option<String>, default: Option<Self::Output>) -> crate::BoxResult<Self::Output> {
let mut prompt = prompt.unwrap_or(String::from($default_prompt));
if let Some(default) = default.as_ref() {
prompt += &format!("(default: {default}) ");
}
loop {
print!("{prompt}");
let input_string = read_stdin()?;
if input_string.is_empty() && let Some(default) = default {
return Ok(default);
}
let input = match input_string.parse::<$type_base>() {
Ok(v) => v,
Err(err) => {
println!();
println!("Could not parse input (error: {err})");
continue;
}
};
return Ok(input);
}
}
}
};
}
pub struct CharInput;
implement_number_input!(CharInput, char, "Enter a character: ");
pub struct UsizeInput;
implement_number_input!(UsizeInput, usize, "Enter a number (positive integer): ");
pub struct IsizeInput;
implement_number_input!(IsizeInput, isize, "Enter a number (integer): ");
pub struct U8Input;
implement_number_input!(U8Input, u8, "Enter a number (positive integer): ");
pub struct I8Input;
implement_number_input!(I8Input, i8, "Enter a number (integer): ");
pub struct U16Input;
implement_number_input!(U16Input, u16, "Enter a number (positive integer): ");
pub struct I16Input;
implement_number_input!(I16Input, i16, "Enter a number (integer): ");
pub struct U32Input;
implement_number_input!(U32Input, u32, "Enter a number (positive integer): ");
pub struct I32Input;
implement_number_input!(I32Input, i32, "Enter a number (integer): ");
pub struct U64Input;
implement_number_input!(U64Input, u64, "Enter a number (positive integer): ");
pub struct I64Input;
implement_number_input!(I64Input, i64, "Enter a number (integer): ");
pub struct U128Input;
implement_number_input!(U128Input, u128, "Enter a number (positive integer): ");
pub struct I128Input;
implement_number_input!(I128Input, i128, "Enter a number (integer): ");
pub struct F32Input;
implement_number_input!(F32Input, f32, "Enter a number: ");
pub struct F64Input;
implement_number_input!(F64Input, f64, "Enter a number: ");