Я пишу низкоуровневое сетевое приложение, которое работает с сокетами TCP, где мне часто приходится обрабатывать потоки двоичных данных.Когда некоторые данные доступны, я считываю их в массив u8
, затем оборачиваю в std::io::Cursor<&[u8]>
и затем передаю их обработчикам.В обработчике мне часто нужно знать, есть ли еще какие-то данные в Cursor
или нет.
Представьте, что функция handle
получает данные, а затем обрабатывает их порциями, используя функцию handle_chunk
,Для простоты предположим, что размер фрагмента фиксирован и равен 10 байтам;если размер данных не делится на 10, это ошибка.Эта простая логика может быть реализована следующим образом:
fn handle(mut data: Cursor<&[u8]>) {
while !data.empty() {
if let Err(err) = handle_chunk(&mut data) {
eprintln!("Error while handling data: {}", err);
}
}
}
fn handle_chunk(data: &mut Cursor<&[u8]>) -> Result<(), String> {
// Returns Err("unexpected EOF".to_string()) if chunk is incomplete
// ...
}
Однако Cursor
не имеет метода empty()
или какого-либо другого метода, способного определить, нужно ли обрабатывать больше данных.Рабочее решение, которое я мог бы придумать:
fn handle(data: Cursor<&[u8]>) {
let data = data.into_inner();
let len = data.len();
let mut data = Cursor::new(data);
while (data.position() as usize) < len - 1 {
if let Err(err) = handle_chunk(&mut data) {
eprintln!("Error while handling data: {}", err);
}
}
}
Это выглядит хакерским и не элегантным.Есть ли лучшее решение?Может быть, в стандартной библиотеке Rust есть другой инструмент, который подходит здесь лучше, чем Cursor
?