From 282e986b8951bed7fb130b61763af8d371e24343 Mon Sep 17 00:00:00 2001 From: Maruth Goyal Date: Mon, 6 Nov 2023 11:21:20 -0800 Subject: [PATCH 1/5] add peek n bytes --- lib/async/io/stream.rb | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/async/io/stream.rb b/lib/async/io/stream.rb index 914e709..154eae6 100644 --- a/lib/async/io/stream.rb +++ b/lib/async/io/stream.rb @@ -125,7 +125,17 @@ def read_until(pattern, offset = 0, chomp: true) return matched end - def peek + def peek(size = nil) + if size + until @eof or @read_buffer.bytesize >= size + # Compute the amount of data we need to read from the underlying stream: + read_size = size - @read_buffer.bytesize + + # Don't read less than @block_size to avoid lots of small reads: + fill_read_buffer(read_size > @block_size ? read_size : @block_size) + end + return @read_buffer[..[size, @read_buffer.size].min] + end until yield(@read_buffer) or @eof fill_read_buffer end From d7a11b1f5329ce5f99a37ce949b95686378ce598 Mon Sep 17 00:00:00 2001 From: Maruth Goyal Date: Mon, 6 Nov 2023 16:34:05 -0800 Subject: [PATCH 2/5] add basic tests --- spec/async/io/stream_spec.rb | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/spec/async/io/stream_spec.rb b/spec/async/io/stream_spec.rb index 812f319..c5a385f 100644 --- a/spec/async/io/stream_spec.rb +++ b/spec/async/io/stream_spec.rb @@ -184,6 +184,32 @@ expect(subject.read_partial(20)).to be == "o World" expect(subject).to be_eof end + + it "should peek everything" do + io.write "Hello World" + io.seek(0) + + expect(subject.io).to receive(:read_nonblock).and_call_original.twice + + expect(subject.peek).to be == "Hello World" + expect(subject.read).to be == "Hello World" + expect(subject).to be_eof + end + + it "should peek only the amount requested" do + io.write "Hello World" + io.seek(0) + + expect(subject.io).to receive(:read_nonblock).and_call_original.once + + expect(subject.peek(4)).to be == "Hell" + expect(subject.read_partial(4)).to be == "Hell" + expect(subject).to_not be_eof + + expect(subject.peek(20)).to be == "o World" + expect(subject.read_partial(20)).to be == "o World" + expect(subject).to be_eof + end context "with large content", if: !Async::IO.buffer? do it "allocates expected amount of bytes" do From bc6b0fa6dbe4cb4fb856cf8262441e7a7eb85881 Mon Sep 17 00:00:00 2001 From: Maruth Goyal Date: Mon, 6 Nov 2023 16:39:37 -0800 Subject: [PATCH 3/5] add another --- spec/async/io/stream_spec.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/spec/async/io/stream_spec.rb b/spec/async/io/stream_spec.rb index c5a385f..db34c98 100644 --- a/spec/async/io/stream_spec.rb +++ b/spec/async/io/stream_spec.rb @@ -210,6 +210,17 @@ expect(subject.read_partial(20)).to be == "o World" expect(subject).to be_eof end + + it "peeks everything when requested bytes is too large" do + io.write "Hello World" + io.seek(0) + + expect(subject.io).to receive(:read_nonblock).and_call_original.once + + expect(subject.peek(400)).to be == "Hello World" + expect(subject.read_partial(400)).to be == "Hello World" + expect(subject).to be_eof + end context "with large content", if: !Async::IO.buffer? do it "allocates expected amount of bytes" do From abd1abc26c6f4cb88972fddcc09c582f8c46421b Mon Sep 17 00:00:00 2001 From: Maruth Goyal Date: Tue, 7 Nov 2023 13:55:47 -0800 Subject: [PATCH 4/5] Fix tests --- lib/async/io/stream.rb | 4 ++-- spec/async/io/stream_spec.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/async/io/stream.rb b/lib/async/io/stream.rb index 154eae6..f816467 100644 --- a/lib/async/io/stream.rb +++ b/lib/async/io/stream.rb @@ -134,9 +134,9 @@ def peek(size = nil) # Don't read less than @block_size to avoid lots of small reads: fill_read_buffer(read_size > @block_size ? read_size : @block_size) end - return @read_buffer[..[size, @read_buffer.size].min] + return @read_buffer[..([size, @read_buffer.size].min - 1)] end - until yield(@read_buffer) or @eof + until (block_given? && yield(@read_buffer)) or @eof fill_read_buffer end end diff --git a/spec/async/io/stream_spec.rb b/spec/async/io/stream_spec.rb index db34c98..c1506aa 100644 --- a/spec/async/io/stream_spec.rb +++ b/spec/async/io/stream_spec.rb @@ -215,7 +215,7 @@ io.write "Hello World" io.seek(0) - expect(subject.io).to receive(:read_nonblock).and_call_original.once + expect(subject.io).to receive(:read_nonblock).and_call_original.twice expect(subject.peek(400)).to be == "Hello World" expect(subject.read_partial(400)).to be == "Hello World" From ed42fcdb18dfd1026ec2af270dd25150592f730b Mon Sep 17 00:00:00 2001 From: Maruth Goyal Date: Tue, 7 Nov 2023 14:15:27 -0800 Subject: [PATCH 5/5] Fix tests --- lib/async/io/stream.rb | 1 + spec/async/io/stream_spec.rb | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/async/io/stream.rb b/lib/async/io/stream.rb index f816467..d1f27a1 100644 --- a/lib/async/io/stream.rb +++ b/lib/async/io/stream.rb @@ -139,6 +139,7 @@ def peek(size = nil) until (block_given? && yield(@read_buffer)) or @eof fill_read_buffer end + return @read_buffer end def gets(separator = $/, **options) diff --git a/spec/async/io/stream_spec.rb b/spec/async/io/stream_spec.rb index c1506aa..4dd042c 100644 --- a/spec/async/io/stream_spec.rb +++ b/spec/async/io/stream_spec.rb @@ -200,7 +200,7 @@ io.write "Hello World" io.seek(0) - expect(subject.io).to receive(:read_nonblock).and_call_original.once + expect(subject.io).to receive(:read_nonblock).and_call_original.twice expect(subject.peek(4)).to be == "Hell" expect(subject.read_partial(4)).to be == "Hell"