module IO::Stream::Readable

def read(size = nil, buffer = nil)

@returns [String] The data read from the stream, or the provided buffer filled with data.
@parameter buffer [String | Nil] An optional buffer to fill with data instead of allocating a new string.
@parameter size [Integer | Nil] The number of bytes to read. If nil, read until end of stream.
Read data from the stream.
def read(size = nil, buffer = nil)
	if size == 0
		if buffer
			buffer.clear
			buffer.force_encoding(Encoding::BINARY)
			return buffer
		else
			return String.new(encoding: Encoding::BINARY)
		end
	end
	
	if size
		until @finished 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 @minimum_read_size to avoid lots of small reads:
			fill_read_buffer(read_size > @minimum_read_size ? read_size : @minimum_read_size)
		end
	else
		until @finished
			fill_read_buffer
		end
		
		if buffer
			buffer.replace(@read_buffer)
			@read_buffer.clear
		else
			buffer = @read_buffer
			@read_buffer = StringBuffer.new
		end
		
		# Read without size always returns a non-nil value, even if it is an empty string.
		return buffer
	end
	
	return consume_read_buffer(size, buffer)
end