pub fn find_valid_utf8_prefix(bytes: &[u8]) -> (String, Vec<u8>) {
match std::str::from_utf8(bytes) {
Ok(s) => (s.to_string(), Vec::new()),
Err(e) => {
let valid = &bytes[..e.valid_up_to()];
let trailing = bytes[e.valid_up_to()..].to_vec();
(String::from_utf8_lossy(valid).to_string(), trailing)
}
}
}
pub fn split_complete_lines(bytes: &[u8]) -> (String, Vec<u8>) {
match bytes.iter().rposition(|&b| b == b'\n') {
Some(last_nl) => {
let split_at = last_nl + 1;
let complete = match std::str::from_utf8(&bytes[..split_at]) {
Ok(s) => s.to_string(),
Err(_) => {
let (s, _) = find_valid_utf8_prefix(&bytes[..split_at]);
s
}
};
let trailing = bytes[split_at..].to_vec();
(complete, trailing)
}
None => {
(String::new(), bytes.to_vec())
}
}
}