Files
RedBear-OS/src/platform/rlb.rs
T
2018-09-02 08:17:52 +02:00

98 lines
2.4 KiB
Rust

use alloc::vec::Vec;
use platform::types::*;
use platform::{Pal, Sys};
use header::unistd::{lseek, SEEK_SET};
/// Implements an `Iterator` which returns on either newline or EOF.
#[derive(Clone)]
pub struct RawLineBuffer {
pub fd: c_int,
buf: Vec<u8>,
newline: Option<usize>,
read: usize,
}
#[derive(PartialEq)]
pub enum Line<'a> {
Error,
EOF,
Some(&'a [u8]),
}
impl RawLineBuffer {
pub const fn new(fd: c_int) -> Self {
Self {
fd: fd,
buf: Vec::new(),
newline: None,
read: 0,
}
}
// Can't use iterators because we want to return a reference.
// See https://stackoverflow.com/a/30422716/5069285
pub fn next(&mut self) -> Line {
// Remove last line
if let Some(newline) = self.newline {
self.buf.drain(..newline + 1);
}
loop {
// Exit if newline was read already
self.newline = self.buf.iter().position(|b| *b == b'\n');
if self.newline.is_some() {
break;
}
let len = self.buf.len();
if len >= self.buf.capacity() {
self.buf.reserve(1024);
}
// Create buffer of what's left in the vector, uninitialized memory
unsafe {
let capacity = self.buf.capacity();
self.buf.set_len(capacity);
}
let read = Sys::read(self.fd, &mut self.buf[len..]);
let read_usize = read.max(0) as usize;
// Remove all uninitialized memory that wasn't read
unsafe {
self.buf.set_len(len + read_usize);
}
self.read += read_usize;
if read == 0 {
return Line::EOF;
}
if read < 0 {
return Line::Error;
}
}
let newline = self.newline.unwrap(); // safe because it doesn't break the loop otherwise
Line::Some(&self.buf[..newline])
}
/// Return the byte position of the start of the line
pub fn line_pos(&self) -> usize {
self.read - self.buf.len()
}
/// Seek to a byte position in the file
pub fn seek(&mut self, pos: usize) -> off_t {
let ret = lseek(self.fd, pos as i64, SEEK_SET);
if ret != !0 {
self.read = pos;
}
ret
}
}