class Protocol::HTTP::Body::Writable

A dynamic body which you can write to and read from.

def close(error = nil)

@parameter error [Exception] The error that caused this body to be closed, if any. Will be raised on the next call to {read}.

Stop generating output; cause the next call to write to fail with the given error. Does not prevent existing chunks from being read. In other words, this indicates both that no more data will be or should be written to the body.
def close(error = nil)
	@error ||= error
	
	@queue.clear
	@queue.close
	
	super
end

def close_write(error = nil)

@parameter error [Exception] The error that caused this body to be closed, if any.

Signal that no more data will be written to the body.
def close_write(error = nil)
	@error ||= error
	@queue.close
end

def closed?

@returns [Boolean] Whether the body is closed.

Whether the body is closed. A closed body can not be written to or read from.
def closed?
	@queue.closed?
end

def empty?

@returns [Boolean] Whether the body is empty.

Indicates whether the body is empty. This can occur if the body has been closed, or if the producer has invoked {close_write} and the reader has consumed all available chunks.
def empty?
	@queue.empty? && @queue.closed?
end

def initialize(length = nil, queue: Thread::Queue.new)

@parameter queue [Thread::Queue] Specify a different queue implementation, e.g. `Thread::SizedQueue` to enable back-pressure.
@parameter length [Integer] The length of the response body if known.

Initialize the writable body.
def initialize(length = nil, queue: Thread::Queue.new)
	@length = length
	@queue = queue
	@count = 0
	@error = nil
end

def inspect

@returns [String] A string representation of the body.

Inspect the body.
def inspect
	if @error
		"\#<#{self.class} #{@count} chunks written, #{status}, error=#{@error}>"
	else
		"\#<#{self.class} #{@count} chunks written, #{status}>"
	end
end

def output

@returns [Output] The output wrapper.
@parameter output [Output] The output wrapper.
@yields {|output| ...} if a block is given.

If a block is given, and the block raises an error, the error will used to close the body by invoking {close} with the error.

Create an output wrapper which can be used to write chunks to the body.
def output
	output = Output.new(self)
	
	unless block_given?
		return output
	end
	
	begin
		yield output
	rescue => error
		raise error
	ensure
		output.close(error)
	end
end

def read

@raises [Exception] If the body was closed due to an error.
@returns [String | Nil] The next chunk, or `nil` if the body is finished.

Read the next available chunk.
def read
	if @error
		raise @error
	end
	
	# This operation may result in @error being set.
	chunk = @queue.pop
	
	if @error
		raise @error
	end
	
	return chunk
end

def ready?

@returns [Boolean] Whether the body is ready to be read from, without blocking.
def ready?
	!@queue.empty? || @queue.closed?
end

def status

@returns [String] A string representation of the body's status.
def status
	if @queue.empty?
		if @queue.closed?
			"closed"
		else
			"waiting"
		end
	else
		if @queue.closed?
			"closing"
		else
			"ready"
		end
	end
end

def write(chunk)

@raises [Exception] If the body has been closed due to an error.
@raises [Closed] If the body has been closed without error.
@parameter chunk [String] The chunk to write.

Write a single chunk to the body. Signal completion by calling {close_write}.
def write(chunk)
	if @queue.closed?
		raise(@error || Closed)
	end
	
	@queue.push(chunk)
	@count += 1
end