101 lines
2.1 KiB
V
101 lines
2.1 KiB
V
module io
|
|
|
|
// BufferedReader provides a buffered interface for a reader
|
|
struct BufferedReader {
|
|
mut:
|
|
reader Reader
|
|
buf []byte
|
|
// current offset in the buffer
|
|
offset int
|
|
len int
|
|
}
|
|
|
|
// BufferedReaderConfig are options that can be given to a reader
|
|
pub struct BufferedReaderConfig {
|
|
reader Reader
|
|
buf_cap int = 128 * 1024 // large for fast reading of big(ish) files
|
|
}
|
|
|
|
// new_buffered_reader creates new BufferedReader
|
|
pub fn new_buffered_reader(o BufferedReaderConfig) &BufferedReader {
|
|
assert o.buf_cap >= 2
|
|
|
|
// create
|
|
r := &BufferedReader{
|
|
reader: o.reader
|
|
buf: []byte{len: o.buf_cap, cap: o.buf_cap}
|
|
offset: 0
|
|
}
|
|
return r
|
|
}
|
|
|
|
// read fufills the Reader interface
|
|
pub fn (mut r BufferedReader) read(mut buf []byte) ?int {
|
|
// read data out of the buffer if we dont have any
|
|
if r.offset >= r.len-1 {
|
|
r.fill_buffer()?
|
|
}
|
|
|
|
read := copy(buf, r.buf[r.offset..r.len])
|
|
r.offset += read
|
|
|
|
return read
|
|
}
|
|
|
|
// fill buffer attempts to refill the internal buffer
|
|
fn (mut r BufferedReader) fill_buffer() ? {
|
|
// TODO we should keep track of when we get an end of stream
|
|
// from the upstream reader so that we dont have to keep
|
|
// trying to call this
|
|
r.offset = 0
|
|
new_len := r.reader.read(mut r.buf) or {
|
|
if errcode != 0 || err.len != 0 {
|
|
eprintln('>> BufferedReader.reader.read err: $err | errcode: $errcode')
|
|
}
|
|
0
|
|
}
|
|
r.len = new_len
|
|
}
|
|
|
|
// read_line reads a line from the buffered reader
|
|
pub fn (mut r BufferedReader) read_line() ?string {
|
|
mut line := []byte{}
|
|
for {
|
|
if r.offset >= (r.len-1) {
|
|
// go fetch some new data
|
|
r.fill_buffer()?
|
|
}
|
|
|
|
if r.len == 0 {
|
|
// if we have no data then return nothing
|
|
return none
|
|
}
|
|
|
|
// try and find a newline character
|
|
mut i := r.offset
|
|
for ; i < r.len; i++ {
|
|
c := r.buf[i]
|
|
if c == `\n` {
|
|
// great, we hit something
|
|
// do some checking for whether we hit \r\n or just \n
|
|
|
|
if i != 0 && r.buf[i-1] == `\r` {
|
|
x := i-1
|
|
line << r.buf[r.offset..x]
|
|
} else {
|
|
line << r.buf[r.offset..i]
|
|
}
|
|
|
|
r.offset = i + 1
|
|
|
|
return line.bytestr()
|
|
}
|
|
}
|
|
|
|
line << r.buf[r.offset..i]
|
|
|
|
r.offset = i
|
|
}
|
|
}
|
|
|