use std::{fmt::Arguments, io::{self, BufRead, Write}, str::FromStr};
#[macro_export]
macro_rules! input {
() => {{
$crate::read_input_from(
&mut ::std::io::stdin().lock(),
None,
$crate::PrintStyle::Continue,
)
}};
($($arg:tt)*) => {{
$crate::read_input_from(
&mut ::std::io::stdin().lock(),
Some(format_args!($($arg)*)),
$crate::PrintStyle::Continue
)
}};
}
#[macro_export]
macro_rules! inputln {
() => {{
$crate::read_input_from(
&mut ::std::io::stdin().lock(),
None,
$crate::PrintStyle::NewLine
)
}};
($($arg:tt)*) => {{
$crate::read_input_from(
&mut ::std::io::stdin().lock(),
None,
$crate::PrintStyle::NewLine
)
}};
}
pub fn read_input_from<R, T>(
reader: &mut R,
prompt: Option<Arguments<'_>>,
print_style: PrintStyle,
) -> Result<T, InputError<T::Err>>
where
R: BufRead,
T: FromStr,
T::Err: std::fmt::Display + std::fmt::Debug,
{
if let Some(prompt_args) = prompt {
match print_style {
PrintStyle::Continue => {
print!("{}", prompt_args);
}
PrintStyle::NewLine => {
println!("{}", prompt_args);
}
}
io::stdout().flush().map_err(InputError::Io)?;
}
let mut input = String::new();
let bytes_read = reader.read_line(&mut input).map_err(InputError::Io)?;
if bytes_read == 0 {
return Err(InputError::Eof);
}
let trimmed = input.trim_end_matches(['\r', '\n'].as_ref());
trimmed.parse::<T>().map_err(InputError::Parse)
}
#[derive(Debug)]
pub enum InputError<E> {
Io(io::Error),
Parse(E),
Eof,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PrintStyle {
Continue,
NewLine,
}
impl<E: std::fmt::Display + std::fmt::Debug> std::fmt::Display for InputError<E> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
InputError::Io(e) => write!(f, "I/O error: {}", e),
InputError::Parse(e) => write!(f, "Parse error: {}", e),
InputError::Eof => write!(f, "EOF encountered"),
}
}
}
impl<E: std::fmt::Display + std::fmt::Debug> std::error::Error for InputError<E> {}