class Protocol::HTTP::Body::Buffered

A body which buffers all its contents.

def self.read(body)

@returns [Buffered] the buffered body.
@parameter body [Readable] the body to read.

Read the entire body into a buffered representation.
def self.read(body)
	chunks = []
	
	body.each do |chunk|
		chunks << chunk
	end
	
	self.new(chunks)
end

def self.wrap(object)

@returns [Readable | nil] the wrapped body or nil if nil was given.
@parameter body [String | Array(String) | Readable | nil] the body to wrap.

For compatibility, also accepts anything that behaves like an `Array(String)`.

Tries to wrap an object in a {Buffered} instance.
def self.wrap(object)
	if object.is_a?(Readable)
		return object
	elsif object.is_a?(Array)
		return self.new(object)
	elsif object.is_a?(String)
		return self.new([object])
	elsif object
		return self.read(object)
	end
end

def buffered

@returns [Buffered] the buffered body.

A rewindable body wraps some other body. Convert it to a buffered body. The buffered body will share the same chunks as the rewindable body.
def buffered
	self.class.new(@chunks)
end

def clear

Clear the buffered chunks.
def clear
	@chunks = []
	@length = 0
	@index = 0
end

def close(error = nil)

@parameter error [Exception | Nil] the error that caused the body to be closed, if any.

Ensure that future reads return `nil`, but allow for rewinding.
def close(error = nil)
	@index = @chunks.length
	
	return nil
end

def close_write(error)

Close the body for writing. This is a no-op.
def close_write(error)
	# Nothing to do.
end

def discard

Discard the body. Invokes {#close}.
def discard
	# It's safe to call close here because there is no underlying stream to close:
	self.close
end

def empty?

@returns [Boolean] if the body is empty.
def empty?
	@index >= @chunks.length
end

def finish

@returns [Buffered] self.

Finish the body, this is a no-op.
def finish
	self
end

def initialize(chunks = [], length = nil)

@parameter length [Integer] the length of the body, if known.
@parameter chunks [Array(String)] the chunks to buffer.

Initialize the buffered body with some chunks.
def initialize(chunks = [], length = nil)
	@chunks = chunks
	@length = length
	
	@index = 0
end

def inspect

@returns [String] a string representation of the buffered body.

Inspect the buffered body.
def inspect
	if @chunks
		"\#<#{self.class} #{@chunks.size} chunks, #{self.length} bytes>"
	end
end

def length

The length of the body. Will compute and cache the length of the body, if it was not provided.
def length
	@length ||= @chunks.inject(0) {|sum, chunk| sum + chunk.bytesize}
end

def read

@returns [String | Nil] the next chunk or nil if there are no more chunks.

Read the next chunk from the buffered body.
def read
	return nil unless @chunks
	
	if chunk = @chunks[@index]
		@index += 1
		
		return chunk.dup
	end
end

def ready?

@returns [Boolean] a buffered response is always ready.
Whether the body is ready to be read.
def ready?
	true
end

def rewind

Rewind the body to the beginning, causing a subsequent read to return the first chunk.
def rewind
	return false unless @chunks
	
	@index = 0
	
	return true
end

def rewindable?

@returns [Boolean] if the body has chunks.

Whether the body can be rewound.
def rewindable?
	@chunks != nil
end

def write(chunk)

Write a chunk to the buffered body.
def write(chunk)
	@chunks << chunk
end