use std::io::{self, Write};
use std::fmt;
#[derive(Debug)]
pub enum InputError {
IoError(io::Error),
Eof,
Interrupted,
}
impl fmt::Display for InputError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
InputError::IoError(e) => write!(f, "IO error: {}", e),
InputError::Eof => write!(f, "End of file reached"),
InputError::Interrupted => write!(f, "Input interrupted"),
}
}
}
impl std::error::Error for InputError {}
impl From<io::Error> for InputError {
fn from(err: io::Error) -> Self {
InputError::IoError(err)
}
}
pub type InputResult<T> = Result<T, InputError>;
pub struct InputReader {
buffer: String,
}
impl InputReader {
pub fn new() -> Self {
InputReader {
buffer: String::with_capacity(256),
}
}
pub fn read_line(&mut self) -> InputResult<String> {
self.buffer.clear();
match io::stdin().read_line(&mut self.buffer) {
Ok(0) => Err(InputError::Eof),
Ok(_) => {
if self.buffer.ends_with('\n') {
self.buffer.pop();
if self.buffer.ends_with('\r') {
self.buffer.pop();
}
}
Ok(self.buffer.clone())
}
Err(e) if e.kind() == io::ErrorKind::Interrupted => Err(InputError::Interrupted),
Err(e) => Err(InputError::IoError(e)),
}
}
pub fn read_line_with_prompt(&mut self, prompt: &str) -> InputResult<String> {
print!("{}", prompt);
io::stdout().flush()?;
self.read_line()
}
}
impl Default for InputReader {
fn default() -> Self {
Self::new()
}
}
#[macro_export]
macro_rules! inputln {
() => {{
let mut s = String::new();
match ::std::io::stdin().read_line(&mut s) {
Ok(0) => panic!("EOF reached"),
Ok(_) => {
if s.ends_with('\n') {
s.pop();
if s.ends_with('\r') {
s.pop();
}
}
s
}
Err(e) => panic!("Input error: {}", e),
}
}};
($prompt:expr) => {{
use ::std::io::Write;
print!($prompt);
let _ = ::std::io::stdout().flush();
let mut s = String::new();
match ::std::io::stdin().read_line(&mut s) {
Ok(0) => panic!("EOF reached"),
Ok(_) => {
if s.ends_with('\n') {
s.pop();
if s.ends_with('\r') {
s.pop();
}
}
s
}
Err(e) => panic!("Input error: {}", e),
}
}};
($fmt:expr, $($arg:tt)*) => {{
use ::std::io::Write;
print!($fmt, $($arg)*);
let _ = ::std::io::stdout().flush();
let mut s = String::new();
match ::std::io::stdin().read_line(&mut s) {
Ok(0) => panic!("EOF reached"),
Ok(_) => {
if s.ends_with('\n') {
s.pop();
if s.ends_with('\r') {
s.pop();
}
}
s
}
Err(e) => panic!("Input error: {}", e),
}
}};
(safe $prompt:expr) => {{
use $crate::InputReader;
let mut reader = InputReader::new();
reader.read_line_with_prompt($prompt)
}};
(safe) => {{
use $crate::InputReader;
let mut reader = InputReader::new();
reader.read_line()
}};
}
pub fn input() -> InputResult<String> {
let mut reader = InputReader::new();
reader.read_line()
}
pub fn input_with_prompt(prompt: &str) -> InputResult<String> {
let mut reader = InputReader::new();
reader.read_line_with_prompt(prompt)
}