Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions spec/std/io/io_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,17 @@ describe IO do
IO.same_content?(io1, io2).should be_false
end
end

it "combines multiple reads using #read_greedy" do
bytes = Bytes.new 7

io = SimpleIOMemory.new("Hello World", max_read: 2)
io.read_greedy(bytes).should eq(7)
bytes.should eq("Hello W".to_slice)
io.read_greedy(bytes).should eq(4)
bytes[0, 4].should eq("orld".to_slice)
io.read_greedy(bytes).should eq(0)
end
end

describe "write operations" do
Expand Down
30 changes: 28 additions & 2 deletions src/io.cr
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,9 @@ abstract class IO
# slice # => Bytes[49, 50, 51, 52, 53]
# io.read_fully(slice) # raises IO::EOFError
# ```
#
# `#read_greedy` also tries to fill the entire buffer if possible,
# but still allows the partially filled slice to be used if an early EOF was reached.
def read_fully(slice : Bytes) : Int32
read_fully?(slice) || raise(EOFError.new)
end
Expand All @@ -538,11 +541,34 @@ abstract class IO
# slice # => Bytes[49, 50, 51, 52, 53]
# io.read_fully?(slice) # => nil
# ```
#
# `#read_greedy` also tries to fill the entire buffer if possible,
# but still allows the partially filled slice to be used if an early EOF was reached.
def read_fully?(slice : Bytes) : Int32?
count = read_greedy(slice)
return nil if count != slice.size
count
end

# Similar to `#read`, but with the additional guarantee that either
# the buffer will be entirely filled or the EOF will be reached while trying.
#
# Calling this method may result in multiple calls to `#read` if necessary.
#
# ```
# io = IO::Memory.new "123451234"
# slice = Bytes.new(5)
# io.read_greedy(slice) # => 5
# slice # => Bytes[49, 50, 51, 52, 53]
# io.read_greedy(slice) # => 4
# ```
#
# `#read_fully` and `#read_fully?` also try to fill the entire buffer but error on unexpected EOF.
def read_greedy(slice : Bytes) : Int32
count = slice.size
while slice.size > 0
read_bytes = read slice
return nil if read_bytes == 0
read_bytes = read(slice)
return count &- slice.size if read_bytes == 0
slice += read_bytes
end
count
Expand Down