Ограничить размер ввода в символах от стандартного ввода - PullRequest
0 голосов
/ 07 мая 2020

Я хочу написать приложение на Rust, которое обрабатывает ввод с терминала, и я хочу предотвратить его сбой / завершение работы из-за нехватки памяти. Он отображает приглашение, обрабатывает команду и снова отображает приглашение. В основном я ищу read_line_max(n) или read_until(delimiter, max_chars) API, где читается не более n байтов или пока не будет достигнут разделитель.

Возможности, которые я рассмотрел:

for io::stdin().lock().take(n).lines() занимает всего n байтов в большинство, мне нужно неограниченное количество символов, но ограничить размер строки.

for io::stdin().lock().lines().take(n) ограничивает количество строк

for line in io::stdin().lock().lines() {
    let line = line?.chars().take(n);
    println!("{}", respond_to(line));
}

слишком поздно, забирает 50 ГБ памяти, убивает неизбежное

I обнаружил, что у BufReader был итератор .chars (), который можно было использовать таким образом, но он был удален.

С io::stdin().lock().read(buff) есть проблема с байтами и символами, но это может быть моим лучшим выбором. А затем попробуйте бросить его в String, чтобы проверить действительность UTF-8, но это похоже на то, что я сделал бы в C и очень unidiomati c.

На самом деле, когда я писал это, я быстро собрал это :

let inp = io::stdin();
let mut bufinp = inp.lock();
let mut linebytes = [0_u8; 10];
loop {
    match bufinp.read(&mut linebytes) {
        Ok(bytes_read) => {
            match String::from_utf8(linebytes[..bytes_read].to_vec()) {
                Ok(line) => println!("processed line: {}", &line),
                Err(err) => eprintln!("utf8 err: {:?}", err),
            }
        },
        Err(err) => {
            eprintln!("line read err: {:?}", err);
        }
    }
}

Итак ... этот тип делает то, что я хочу, но у меня есть некоторые проблемы с ним:

1) Мне нужно обрезать '\ n', если ввод меньше чем буфер.

2) Остальная часть стандартного ввода не очищается, если ввод больше, чем буфер. Я предполагаю, что мне нужно поставить skip_while() там в конце, чтобы он не перекинулся на следующее чтение. Есть ли лучший способ очистить его?

3) Он может разбивать графемы, в то время как я фактически мог бы обработать эти дополнительные 3 байта. Я действительно не забочусь о том, чтобы читать до определенного c жесткого лимита. Я просто хочу, чтобы использование ввода / памяти не было "слишком большим".

4) Это слишком низкоуровневое и сложное решение, которое не соответствует принципу «делать хорошие и безопасные варианты, легко кодировать, а небезопасные» менее доступный », что заставляет меня думать, что я делаю это неправильно. Но по крайней мере cat /dev/zero | ./target/debug/test больше не приводит к SIGQUIT.

Мне кажется странным, что язык, который гордится своей безопасностью, не обеспечивает надежный способ работы с потенциально большими входными данными. Я что-то упускаю или слишком много об этом думаю? Каждая найденная мной статья просто закрывает глаза и запускает read_to_end() или read_line(), не задумываясь.

Как мне безопасно и идиоматично читать вводимые пользователем данные?

...