ez_input 0.1.0

make rust input easy!
Documentation
// src/input.rs
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),
        }
    }

    /// 读取一行,返回 Result
    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 实现
#[macro_export]
macro_rules! inputln {
    // 基础版本 - 无提示,直接返回 String,出错时 panic
    () => {{
        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),
        }
    }};

    // 带提示信息,出错时 panic
    ($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),
        }
    }};

    // 安全版本 - 返回 Result
    (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)
}