#![feature(let_chains)]
pub mod input_options;
pub mod ranges;
use std::{error::Error, io::Write};
pub type BoxResult<T> = Result<T, Box<dyn Error>>;
#[macro_export]
macro_rules! read {
($($args:tt)*) => {
smart_read::try_read!($($args)*).unwrap()
}
}
#[macro_export]
macro_rules! try_read {
() => {
smart_read::read_string()
};
([$default:expr]) => {{
print!("(default: {}) ", $default);
smart_read::read_string_or_default($default.to_string())
}};
($custom_input:expr) => {{
use smart_read::ReadLine;
$custom_input.try_read_line(None, None)
}};
([$default:expr] $custom_input:expr) => {{
use smart_read::ReadLine;
$custom_input.try_read_line(None, Some($default))
}};
(= $($choice:expr),*) => {{
use smart_read::ReadLine;
let choices = &[$($choice,)*];
choices.try_read_line(None, None)
}};
([$default:expr] = $($choice:expr),*) => {{
use smart_read::ReadLine;
let choices = &[$($choice,)*];
choices.try_read_line(None, Some($default))
}};
}
#[macro_export]
macro_rules! prompt {
($($args:tt)*) => {
smart_read::try_prompt!($($args)*).unwrap()
}
}
#[macro_export]
macro_rules! try_prompt {
($prompt:expr) => {{
print!("{}", $prompt);
smart_read::read_string()
}};
($prompt:expr; [$default:expr]) => {
print!("{}(default: {}) ", $prompt, $default);
smart_read::read_string_or_default($default.to_string())
};
($prompt:expr; $custom_input:expr) => {{
use smart_read::ReadLine;
$custom_input.try_read_line(Some($prompt.to_string()), None)
}};
($prompt:expr; [$default:expr] $custom_input:expr) => {{
use smart_read::ReadLine;
$custom_input.try_read_line(Some($prompt.to_string()), Some($default))
}};
($prompt:expr; = $($choice:expr),*) => {{
use smart_read::ReadLine;
let choices = &[$($choice,)*];
choices.try_read_line(Some($prompt.to_string()), None)
}};
($prompt:expr; [$default:expr] = $($choice:expr),*) => {{
use smart_read::ReadLine;
let choices = &[$($choice,)*];
choices.try_read_line(Some($prompt.to_string()), Some($default))
}};
}
pub trait ReadLine: Sized {
type Output;
fn try_read_line(&self, prompt: Option<String>, default: Option<Self::Output>) -> BoxResult<Self::Output>;
fn read_line(&self, prompt: Option<String>, default: Option<Self::Output>) -> Self::Output {
self.try_read_line(prompt, default).unwrap()
}
}
pub fn read_string() -> BoxResult<String> {
let mut output = String::new();
std::io::stdout().flush()?;
std::io::stdin().read_line(&mut output)?;
if output.as_bytes().last() == Some(&10) {output.pop();} if output.as_bytes().last() == Some(&13) {output.pop();} Ok(output)
}
pub fn read_string_or_default(default: String) -> BoxResult<String> {
let mut output = String::new();
std::io::stdout().flush()?;
std::io::stdin().read_line(&mut output)?;
if output.as_bytes().last() == Some(&10) {output.pop();} if output.as_bytes().last() == Some(&13) {output.pop();} Ok(if output.is_empty() {
default
} else {
output
})
}