Skip to main content

ext_rs/
lib.rs

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}