Я хочу написать приложение на 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()
, не задумываясь.
Как мне безопасно и идиоматично читать вводимые пользователем данные?