io: fix detection of end_of_stream, when reading files through io.new_buffered_reader(reader: io.make_reader(f))
parent
843de10442
commit
4961d3ea17
|
@ -5,17 +5,15 @@ import io
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Make a new connection
|
// Make a new connection
|
||||||
mut conn := net.dial_tcp('google.com:80')?
|
mut conn := net.dial_tcp('google.com:80') ?
|
||||||
// Simple http HEAD request for a file
|
// Simple http HEAD request for a file
|
||||||
conn.write_str('GET /index.html HTTP/1.0\r\n\r\n')?
|
conn.write_str('GET /index.html HTTP/1.0\r\n\r\n') ?
|
||||||
// Wrap in a buffered reader
|
// Wrap in a buffered reader
|
||||||
mut r := io.new_buffered_reader(reader: io.make_reader(conn))
|
mut r := io.new_buffered_reader(reader: io.make_reader(conn))
|
||||||
for {
|
for {
|
||||||
l := r.read_line() or {
|
l := r.read_line() or { break }
|
||||||
break
|
|
||||||
}
|
|
||||||
println('$l')
|
println('$l')
|
||||||
// Make it nice and obvious that we are doing this line by line
|
// Make it nice and obvious that we are doing this line by line
|
||||||
time.sleep_ms(10)
|
time.sleep_ms(100)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,19 +3,21 @@ module io
|
||||||
// BufferedReader provides a buffered interface for a reader
|
// BufferedReader provides a buffered interface for a reader
|
||||||
struct BufferedReader {
|
struct BufferedReader {
|
||||||
mut:
|
mut:
|
||||||
reader Reader
|
reader Reader
|
||||||
buf []byte
|
buf []byte
|
||||||
// current offset in the buffer
|
offset int // current offset in the buffer
|
||||||
offset int
|
len int
|
||||||
len int
|
fails int // how many times fill_buffer has read 0 bytes in a row
|
||||||
// Whether we reached the end of the upstream reader
|
mfails int // maximum fails, after which we can assume that the stream has ended
|
||||||
end_of_stream bool
|
pub mut:
|
||||||
|
end_of_stream bool // whether we reached the end of the upstream reader
|
||||||
}
|
}
|
||||||
|
|
||||||
// BufferedReaderConfig are options that can be given to a reader
|
// BufferedReaderConfig are options that can be given to a reader
|
||||||
pub struct BufferedReaderConfig {
|
pub struct BufferedReaderConfig {
|
||||||
reader Reader
|
reader Reader
|
||||||
cap int = 128 * 1024 // large for fast reading of big(ish) files
|
cap int = 128 * 1024 // large for fast reading of big(ish) files
|
||||||
|
retries int = 2 // how many times to retry before assuming the stream ended
|
||||||
}
|
}
|
||||||
|
|
||||||
// new_buffered_reader creates new BufferedReader
|
// new_buffered_reader creates new BufferedReader
|
||||||
|
@ -26,6 +28,7 @@ pub fn new_buffered_reader(o BufferedReaderConfig) &BufferedReader {
|
||||||
reader: o.reader
|
reader: o.reader
|
||||||
buf: []byte{len: o.cap, cap: o.cap}
|
buf: []byte{len: o.cap, cap: o.cap}
|
||||||
offset: 0
|
offset: 0
|
||||||
|
mfails: o.retries
|
||||||
}
|
}
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
@ -59,6 +62,17 @@ fn (mut r BufferedReader) fill_buffer() bool {
|
||||||
r.end_of_stream = true
|
r.end_of_stream = true
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if r.len == 0 {
|
||||||
|
r.fails++
|
||||||
|
} else {
|
||||||
|
r.fails = 0
|
||||||
|
}
|
||||||
|
if r.fails >= r.mfails {
|
||||||
|
// When reading 0 bytes several times in a row, assume the stream has ended.
|
||||||
|
// This prevents infinite loops ¯\_(ツ)_/¯ ...
|
||||||
|
r.end_of_stream = true
|
||||||
|
return false
|
||||||
|
}
|
||||||
// we got some data
|
// we got some data
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
import os
|
||||||
|
import io
|
||||||
|
|
||||||
|
fn read_file(file string, cap int) []string {
|
||||||
|
mut lines := []string{}
|
||||||
|
mut f := os.open(file) or { panic(err) }
|
||||||
|
defer {
|
||||||
|
f.close()
|
||||||
|
}
|
||||||
|
mut r := io.new_buffered_reader(reader: io.make_reader(f), cap: cap)
|
||||||
|
for {
|
||||||
|
l := r.read_line() or { break }
|
||||||
|
lines << l
|
||||||
|
// println('Line: $l')
|
||||||
|
}
|
||||||
|
assert lines.len > 0
|
||||||
|
assert r.end_of_stream == true
|
||||||
|
println('------------------------------------------------ cap: ${cap:6}; read: ${lines.len:3} lines')
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_file_reader() {
|
||||||
|
for cap := 64; cap <= 10000; cap += 256 {
|
||||||
|
lines := read_file(@FILE, cap)
|
||||||
|
assert lines.last() == '// my last line'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// my last line
|
Loading…
Reference in New Issue