1use std::{
2 io::{BufReader, Read},
3 ops::Shr,
4 str::FromStr,
5};
6
7pub struct ExtReader<R: Read>(pub BufReader<R>);
8
9pub trait Extractable {
10 fn extract<T>(&mut self, value: &mut T) -> &mut Self
11 where
12 T: FromStr;
13}
14
15impl<R: Read> Extractable for ExtReader<R> {
16 fn extract<T>(&mut self, value: &mut T) -> &mut Self
17 where
18 T: FromStr,
19 {
20 let delimiters = [b' ', b'\n', b'\t'];
21
22 let mut buf = Vec::new();
23
24 read_until(&mut self.0, &delimiters, &mut buf);
25
26 *value = String::from_utf8(buf)
27 .unwrap()
28 .trim()
29 .parse::<T>()
30 .ok()
31 .unwrap();
32
33 self
34 }
35}
36
37impl<R: Read, T: FromStr> Shr<&mut T> for ExtReader<R> {
38 type Output = Self;
39
40 fn shr(mut self, rhs: &mut T) -> Self::Output {
41 self.extract(rhs);
42 self
43 }
44}
45
46fn read_until<T>(reader: &mut BufReader<T>, delimiters: &[u8], buffer: &mut Vec<u8>) -> usize
47where
48 T: Read,
49{
50 let mut total_read = 0;
51
52 loop {
53 let mut byte = [0u8; 1];
54 let bytes_read = reader.read(&mut byte).unwrap();
55
56 if bytes_read == 0 {
57 break;
58 }
59
60 if delimiters.contains(&byte[0]) {
61 break;
62 }
63
64 buffer.push(byte[0]);
65 total_read += bytes_read;
66 }
67
68 total_read
69}
70
71#[cfg(test)]
72#[allow(unused_must_use)]
73mod tests {
74 use super::*;
75
76 #[test]
77 fn test_extractable() {
78 let data = b"42 3.1 hello\nworld";
79 let cursor = std::io::Cursor::new(data);
80 let mut reader = ExtReader(BufReader::new(cursor));
81
82 let mut int_value: i32 = 0;
83 let mut float_value: f64 = 0.0;
84 let mut string_value = String::new();
85 reader
86 .extract(&mut int_value)
87 .extract(&mut float_value)
88 .extract(&mut string_value);
89
90 assert_eq!(int_value, 42);
91 assert_eq!(float_value, 3.1);
92 assert_eq!(string_value, "hello");
93 }
94
95 #[test]
96 fn test_shr_operator() {
97 let data = b"100 2.5 test\ncase";
98 let cursor = std::io::Cursor::new(data);
99 let reader = ExtReader(BufReader::new(cursor));
100
101 let mut int_value: i32 = 0;
102 let mut float_value: f64 = 0.0;
103 let mut string_value = String::new();
104 reader >> &mut int_value >> &mut float_value >> &mut string_value;
105 assert_eq!(int_value, 100);
106 assert_eq!(float_value, 2.5);
107 assert_eq!(string_value, "test");
108 }
109}