Skip to content
This repository was archived by the owner on Aug 29, 2024. It is now read-only.

Commit 81c6728

Browse files
Add functionality to be able to peek n bytes off the wire (#72)
1 parent 5dab8dd commit 81c6728

File tree

2 files changed

+50
-2
lines changed

2 files changed

+50
-2
lines changed

lib/async/io/stream.rb

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,21 @@ def read_until(pattern, offset = 0, chomp: true)
125125
return matched
126126
end
127127

128-
def peek
129-
until yield(@read_buffer) or @eof
128+
def peek(size = nil)
129+
if size
130+
until @eof or @read_buffer.bytesize >= size
131+
# Compute the amount of data we need to read from the underlying stream:
132+
read_size = size - @read_buffer.bytesize
133+
134+
# Don't read less than @block_size to avoid lots of small reads:
135+
fill_read_buffer(read_size > @block_size ? read_size : @block_size)
136+
end
137+
return @read_buffer[..([size, @read_buffer.size].min - 1)]
138+
end
139+
until (block_given? && yield(@read_buffer)) or @eof
130140
fill_read_buffer
131141
end
142+
return @read_buffer
132143
end
133144

134145
def gets(separator = $/, **options)

spec/async/io/stream_spec.rb

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,43 @@
184184
expect(subject.read_partial(20)).to be == "o World"
185185
expect(subject).to be_eof
186186
end
187+
188+
it "should peek everything" do
189+
io.write "Hello World"
190+
io.seek(0)
191+
192+
expect(subject.io).to receive(:read_nonblock).and_call_original.twice
193+
194+
expect(subject.peek).to be == "Hello World"
195+
expect(subject.read).to be == "Hello World"
196+
expect(subject).to be_eof
197+
end
198+
199+
it "should peek only the amount requested" do
200+
io.write "Hello World"
201+
io.seek(0)
202+
203+
expect(subject.io).to receive(:read_nonblock).and_call_original.twice
204+
205+
expect(subject.peek(4)).to be == "Hell"
206+
expect(subject.read_partial(4)).to be == "Hell"
207+
expect(subject).to_not be_eof
208+
209+
expect(subject.peek(20)).to be == "o World"
210+
expect(subject.read_partial(20)).to be == "o World"
211+
expect(subject).to be_eof
212+
end
213+
214+
it "peeks everything when requested bytes is too large" do
215+
io.write "Hello World"
216+
io.seek(0)
217+
218+
expect(subject.io).to receive(:read_nonblock).and_call_original.twice
219+
220+
expect(subject.peek(400)).to be == "Hello World"
221+
expect(subject.read_partial(400)).to be == "Hello World"
222+
expect(subject).to be_eof
223+
end
187224

188225
context "with large content", if: !Async::IO.buffer? do
189226
it "allocates expected amount of bytes" do

0 commit comments

Comments
 (0)