diff --git a/vlib/io/buffered_reader.v b/vlib/io/buffered_reader.v index 3f1ccb7a87..b57fcab3cc 100644 --- a/vlib/io/buffered_reader.v +++ b/vlib/io/buffered_reader.v @@ -22,7 +22,9 @@ pub struct BufferedReaderConfig { // new_buffered_reader creates new BufferedReader pub fn new_buffered_reader(o BufferedReaderConfig) &BufferedReader { - assert o.cap >= 2 + if o.cap <= 0 { + panic('new_buffered_reader should be called with a positive `cap`') + } // create r := &BufferedReader{ reader: o.reader @@ -35,6 +37,9 @@ pub fn new_buffered_reader(o BufferedReaderConfig) &BufferedReader { // read fufills the Reader interface pub fn (mut r BufferedReader) read(mut buf []byte) ?int { + if r.end_of_stream { + return none + } // read data out of the buffer if we dont have any if r.needs_fill() { if !r.fill_buffer() { @@ -43,6 +48,9 @@ pub fn (mut r BufferedReader) read(mut buf []byte) ?int { } } read := copy(buf, r.buf[r.offset..r.len]) + if read == 0 { + return none + } r.offset += read return read } @@ -79,7 +87,7 @@ fn (mut r BufferedReader) fill_buffer() bool { // needs_fill returns whether the buffer needs refilling fn (r BufferedReader) needs_fill() bool { - return r.offset >= r.len - 1 + return r.offset >= r.len } // end_of_stream returns whether the end of the stream was reached diff --git a/vlib/io/custom_string_reading_test.v b/vlib/io/custom_string_reading_test.v new file mode 100644 index 0000000000..7a1212a84c --- /dev/null +++ b/vlib/io/custom_string_reading_test.v @@ -0,0 +1,57 @@ +import io + +struct StringReader { + text string +mut: + place int +} + +fn imin(a int, b int) int { + return if a < b { a } else { b } +} + +fn (mut s StringReader) read(mut buf []byte) ?int { + $if debug { + eprintln('>>>> StringReader.read output buf.len: $buf.len') + } + if s.place > s.text.len + 1 { + return none + } + mut howmany := imin(buf.len, s.text.len - s.place) + xxx := s.text[s.place..s.place + howmany].bytes() + read := copy(buf, xxx) + s.place += read + return read +} + +fn read_from_string(text string, capacity int) []byte { + mut str := StringReader{ + text: text + } + mut stream := io.new_buffered_reader(reader: io.make_reader(str), cap: capacity) + // + mut buf := []byte{len: 1} + mut res := []byte{} + mut i := 0 + for { + z := stream.read(mut buf) or { break } + res << buf + $if debug { + println('capacity: $capacity, i: $i, buf: $buf | z: $z') + } + i++ + } + return res +} + +pub fn test_reading_from_a_string() { + for capacity in 1 .. 1000 { + assert read_from_string('a', capacity) == [byte(`a`)] + assert read_from_string('ab', capacity) == [byte(`a`), `b`] + assert read_from_string('abc', capacity) == [byte(`a`), `b`, `c`] + assert read_from_string('abcde', capacity) == [byte(`a`), `b`, `c`, `d`, `e`] + large_string_bytes := []byte{len: 1000, init: `x`} + large_string := large_string_bytes.bytestr() + assert read_from_string(large_string, capacity) == large_string_bytes + } +}