data-input 0.1.7

Console (or text file) input assistant
Documentation
//! This crate provides a method to help you input data from the console (or text file).</br>
//! You can enter data of any primitive type (numbers, logical or chars), as well as strings.</br>
//! Crate provides the `Input` trait and its implementations for `Stdin` and `File` objects.

mod helpers;

use std::any::TypeId;
use std::fs::File;
use std::io::{self, Read, Stdin};
use std::str::FromStr;

pub trait Import {
    fn import<T: FromStr + 'static>(&self) -> io::Result<T>;
}

impl Import for Stdin {
    /// Imports data from Stdin.
    fn import<T: FromStr + 'static>(&self) -> io::Result<T> {
        let mut data = String::new();
        let _ = self.read_line(&mut data)?;
        data.trim().parse::<T>().map_err(|_| helpers::parse_error())
    }
}

impl Import for File {
    /// Imports data from text File.
    fn import<T: FromStr + 'static>(&self) -> io::Result<T> {
        let mut data = Vec::<u8>::new();
        let mut buf = [0_u8; 1];
        loop {
            let mut u_cell = std::cell::UnsafeCell::new(self);
            let mut_self = u_cell.get_mut();

            match mut_self.read_exact(&mut buf) {
                Ok(_) => {
                    if TypeId::of::<T>() == TypeId::of::<String>() {
                        if buf[0] == b'\n' {
                            break;
                        };
                    } else {
                        if buf[0] == b' ' || buf[0] == b'\t' || buf[0] == b'\n' {
                            break;
                        };
                    }
                    data.push(buf[0]);
                }
                Err(e) => {
                    if e.kind() == io::ErrorKind::UnexpectedEof {
                        break;
                    } else {
                        return Err(e);
                    }
                }
            }
        }
        let data = String::from_utf8(data).map_err(|e| helpers::utf8_error(e))?;
        data.trim().parse::<T>().map_err(|_| helpers::parse_error())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_import_numbers() {
        let f = File::open("tests/numbers.txt").unwrap();
        {
            let num = f.import::<i32>();
            assert_eq!(num.unwrap_or_default(), 123);
        }
        {
            let num = f.import::<u32>();
            assert_eq!(num.unwrap_or_default(), 12);
        }
        {
            let num = f.import::<i32>();
            assert_eq!(num.unwrap_or_default(), -9);
        }
        {
            let num = f.import::<f32>();
            assert_eq!(num.unwrap_or_default(), 12.098);
        }
        {
            let num = f.import::<f64>();
            assert_eq!(num.unwrap_or_default(), -0.000001);
        }
        {
            let num = f.import::<u64>();
            assert_eq!(num.unwrap_or_default(), 0);
        }
        {
            let num = f.import::<f64>();
            assert_eq!(num.unwrap_or_default(), -0.);
        }
        {
            let num = f.import::<f64>();
            assert_eq!(num.unwrap_or_default(), 0.);
        }
        {
            let num = f.import::<f32>();
            assert_eq!(num.unwrap_or_default(), 1e-5);
        }
    }

    #[test]
    fn test_import_strings() {
        let f = File::open("tests/strings.txt").unwrap();
        {
            let s = f.import::<String>();
            assert_eq!(s.unwrap_or_default(), "aaa bbb");
        }
        {
            let s = f.import::<String>();
            assert_eq!(s.unwrap_or("*".to_owned()), "");
        }
        {
            let s = f.import::<String>();
            assert_eq!(s.unwrap_or_default(), "ccc");
        }
        let _ = f.import::<String>();
        {
            let s = f.import::<String>();
            assert_eq!(s.unwrap_or_default(), "Привет !");
        }
        let _ = f.import::<String>();
        {
            let s = f.import::<String>();
            assert_eq!(s.unwrap_or_default(), "小 休");
        }
    }

    #[test]
    fn test_import_other() {
        let f = File::open("tests/other.txt").unwrap();
        {
            let b = f.import::<bool>();
            assert_eq!(b.unwrap_or_default(), true);
        }
        {
            let b = f.import::<bool>();
            assert_eq!(b.unwrap_or_default(), false);
        }
        {
            let mut chars = Vec::<char>::new();
            chars.push(f.import::<char>().unwrap());
            chars.push(f.import::<char>().unwrap());
            chars.push(f.import::<char>().unwrap());
            assert_eq!(chars, vec!['a','m','d']);
        }
        {
            let ch = f.import::<char>();
            assert_eq!(ch.unwrap_or_default(), 'ё');
        }
    }
}