matchmaker/proc/
io.rs

1use crate::Result;
2use log::{debug, error, warn};
3use std::{io::{self, BufRead, Read, Write}, process::Stdio};
4
5pub fn read_to_chunks<R: Read>(reader: R, delim: char) -> std::io::Split<std::io::BufReader<R>> {
6    io::BufReader::new(reader).split(delim as u8)
7}
8
9// do not use for newlines as it doesn't handle \r!
10// todo: warn about this in config
11pub fn map_chunks<const INVALID_FAIL: bool>(iter: impl Iterator<Item = std::io::Result<Vec<u8>>>, mut f: impl FnMut(String) -> Result<()>)
12{
13    for (i, chunk_result) in iter.enumerate() {
14        if i == u32::MAX as usize {
15            warn!("Reached maximum segment limit, stopping input read");
16            break;
17        }
18
19        let chunk = match chunk_result {
20            Ok(bytes) => bytes,
21            Err(e) => {
22                error!("Error reading from stdin: {e}");
23                break;
24            }
25        };
26
27        match String::from_utf8(chunk) {
28            Ok(s) => {
29                debug!("Read: {s}");
30                if f(s).is_err() {
31                    break;
32                }
33            }
34            Err(e) => {
35                error!("Invalid UTF-8 in stdin at byte {}: {}", e.utf8_error().valid_up_to(), e);
36                // Skip but continue reading
37                if INVALID_FAIL {
38                    break
39                } else {
40                    continue
41                }
42            }
43        }
44    }
45}
46
47pub fn map_reader_lines<const INVALID_FAIL: bool>(reader: impl Read, mut f: impl FnMut(String) -> Result<()>) {
48    let buf_reader = io::BufReader::new(reader);
49
50    for (i, line) in buf_reader.lines().enumerate() {
51        if i == u32::MAX as usize {
52            eprintln!("Reached maximum line limit, stopping input read");
53            break;
54        }
55        match line {
56            Ok(l) => {
57                if f(l).is_err() {
58                    break;
59                }
60            }
61            Err(e) => {
62                eprintln!("Error reading line: {}", e);
63                if INVALID_FAIL {
64                    break
65                } else {
66                    continue
67                }
68            }
69        }
70    }
71}
72
73pub fn tty_or_null() -> Stdio {
74    if let Ok(mut tty) = std::fs::File::open("/dev/tty") {
75        let _ = tty.flush(); // does nothing but seems logical
76        Stdio::from(tty)
77    } else {
78        error!("Failed to open /dev/tty");
79        Stdio::inherit()
80    }
81}