data_input/
lib.rs

1//! This crate provides a method to help you input data from the console (or text file).</br>
2//! You can enter data of any primitive type (numbers, logical or chars), as well as strings.</br>
3//! Crate provides the `Input` trait and its implementations for `Stdin` and `File` objects.
4
5mod helpers;
6
7use std::any::TypeId;
8use std::fs::File;
9use std::io::{self, Read, Stdin};
10use std::str::FromStr;
11
12pub trait Import {
13    fn import<T: FromStr + 'static>(&self) -> io::Result<T>;
14}
15
16impl Import for Stdin {
17    /// Imports data from Stdin.
18    fn import<T: FromStr + 'static>(&self) -> io::Result<T> {
19        let mut data = String::new();
20        let _ = self.read_line(&mut data)?;
21        data.trim().parse::<T>().map_err(|_| helpers::parse_error())
22    }
23}
24
25impl Import for File {
26    /// Imports data from text File.
27    fn import<T: FromStr + 'static>(&self) -> io::Result<T> {
28        let mut data = Vec::<u8>::new();
29        let mut buf = [0_u8; 1];
30        loop {
31            let mut u_cell = std::cell::UnsafeCell::new(self);
32            let mut_self = u_cell.get_mut();
33
34            match mut_self.read_exact(&mut buf) {
35                Ok(_) => {
36                    if TypeId::of::<T>() == TypeId::of::<String>() {
37                        if buf[0] == b'\n' {
38                            break;
39                        };
40                    } else {
41                        if buf[0] == b' ' || buf[0] == b'\t' || buf[0] == b'\n' {
42                            break;
43                        };
44                    }
45                    data.push(buf[0]);
46                }
47                Err(e) => {
48                    if e.kind() == io::ErrorKind::UnexpectedEof {
49                        break;
50                    } else {
51                        return Err(e);
52                    }
53                }
54            }
55        }
56        let data = String::from_utf8(data).map_err(|e| helpers::utf8_error(e))?;
57        data.trim().parse::<T>().map_err(|_| helpers::parse_error())
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64
65    #[test]
66    fn test_import_numbers() {
67        let f = File::open("tests/numbers.txt").unwrap();
68        {
69            let num = f.import::<i32>();
70            assert_eq!(num.unwrap_or_default(), 123);
71        }
72        {
73            let num = f.import::<u32>();
74            assert_eq!(num.unwrap_or_default(), 12);
75        }
76        {
77            let num = f.import::<i32>();
78            assert_eq!(num.unwrap_or_default(), -9);
79        }
80        {
81            let num = f.import::<f32>();
82            assert_eq!(num.unwrap_or_default(), 12.098);
83        }
84        {
85            let num = f.import::<f64>();
86            assert_eq!(num.unwrap_or_default(), -0.000001);
87        }
88        {
89            let num = f.import::<u64>();
90            assert_eq!(num.unwrap_or_default(), 0);
91        }
92        {
93            let num = f.import::<f64>();
94            assert_eq!(num.unwrap_or_default(), -0.);
95        }
96        {
97            let num = f.import::<f64>();
98            assert_eq!(num.unwrap_or_default(), 0.);
99        }
100        {
101            let num = f.import::<f32>();
102            assert_eq!(num.unwrap_or_default(), 1e-5);
103        }
104    }
105
106    #[test]
107    fn test_import_strings() {
108        let f = File::open("tests/strings.txt").unwrap();
109        {
110            let s = f.import::<String>();
111            assert_eq!(s.unwrap_or_default(), "aaa bbb");
112        }
113        {
114            let s = f.import::<String>();
115            assert_eq!(s.unwrap_or("*".to_owned()), "");
116        }
117        {
118            let s = f.import::<String>();
119            assert_eq!(s.unwrap_or_default(), "ccc");
120        }
121        let _ = f.import::<String>();
122        {
123            let s = f.import::<String>();
124            assert_eq!(s.unwrap_or_default(), "Привет !");
125        }
126        let _ = f.import::<String>();
127        {
128            let s = f.import::<String>();
129            assert_eq!(s.unwrap_or_default(), "小 休");
130        }
131    }
132
133    #[test]
134    fn test_import_other() {
135        let f = File::open("tests/other.txt").unwrap();
136        {
137            let b = f.import::<bool>();
138            assert_eq!(b.unwrap_or_default(), true);
139        }
140        {
141            let b = f.import::<bool>();
142            assert_eq!(b.unwrap_or_default(), false);
143        }
144        {
145            let mut chars = Vec::<char>::new();
146            chars.push(f.import::<char>().unwrap());
147            chars.push(f.import::<char>().unwrap());
148            chars.push(f.import::<char>().unwrap());
149            assert_eq!(chars, vec!['a','m','d']);
150        }
151        {
152            let ch = f.import::<char>();
153            assert_eq!(ch.unwrap_or_default(), 'ё');
154        }
155    }
156}