From a2bb060967315c4fcd3ce9c71640e89460b22dae Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Thu, 26 Feb 2026 10:16:58 +0300 Subject: [PATCH] io: fix stream_reader read function does not work (fixes #21768) --- vlib/io/string_reader/string_reader.v | 31 +++++++++++++++++++-- vlib/io/string_reader/string_reader_test.v | 32 ++++++++++++++++++++++ 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/vlib/io/string_reader/string_reader.v b/vlib/io/string_reader/string_reader.v index 24beeea9c..edfce10b1 100644 --- a/vlib/io/string_reader/string_reader.v +++ b/vlib/io/string_reader/string_reader.v @@ -40,6 +40,10 @@ pub fn StringReader.new(params StringReaderParams) StringReader { if source := params.source { r.builder = strings.new_builder(source.len) r.builder.write_string(source) + if params.reader == none { + // There is no upstream reader; only the preloaded buffer can be consumed. + r.end_of_stream = true + } } else { r.builder = strings.new_builder(params.initial_size) } @@ -190,9 +194,32 @@ pub fn (mut r StringReader) read_string(n int) !string { // read implements the Reader interface pub fn (mut r StringReader) read(mut buf []u8) !int { - start := r.offset + if buf.len == 0 { + return 0 + } + + available := r.builder.len - r.offset + if available < buf.len && !r.end_of_stream { + if r.reader != none { + missing := buf.len - available + r.fill_buffer_until(missing) or { + if err !is io.Eof { + return err + } + } + } + } - read := r.fill_buffer_until(buf.len)! + available_after_fill := r.builder.len - r.offset + if available_after_fill == 0 { + if r.reader == none && !r.end_of_stream { + return error('reader is not set') + } + return io.Eof{} + } + + read := if available_after_fill < buf.len { available_after_fill } else { buf.len } + start := r.offset r.offset += read copy(mut buf, r.builder[start..start + read]) diff --git a/vlib/io/string_reader/string_reader_test.v b/vlib/io/string_reader/string_reader_test.v index 2807ace2a..bb1d7f037 100644 --- a/vlib/io/string_reader/string_reader_test.v +++ b/vlib/io/string_reader/string_reader_test.v @@ -36,6 +36,10 @@ fn (mut r TwoByteReader) read(mut buf []u8) !int { return min } +fn read_from_reader_interface(mut r io.Reader, mut buf []u8) !int { + return r.read(mut buf) +} + fn test_read_all() { mut reader := StringReader.new() @@ -107,6 +111,34 @@ fn test_from_string() { } } +fn test_read_from_source_read() { + source := 'line 1\nline 2\n' + mut reader := StringReader.new(source: source) + mut buf := []u8{len: 100} + read := reader.read(mut buf)! + assert read == source.len + assert buf[..read].bytestr() == source + if _ := reader.read(mut buf) { + assert false, 'should return io.Eof' + } else { + assert err is io.Eof + } +} + +fn test_read_from_source_read_via_reader_interface() { + source := 'line 1\nline 2\n' + mut reader := StringReader.new(source: source) + mut buf := []u8{len: 100} + read := read_from_reader_interface(mut reader, mut buf)! + assert read == source.len + assert buf[..read].bytestr() == source + if _ := read_from_reader_interface(mut reader, mut buf) { + assert false, 'should return io.Eof' + } else { + assert err is io.Eof + } +} + fn test_from_string_read_byte_one_by_one() { mut reader := StringReader.new(source: 'test') assert reader.read_bytes(1)![0].ascii_str() == 't' -- 2.39.5