class Protocol::HTTP::Body::Digestable

Invokes a callback once the body has finished reading.

def self.wrap(message, digest = Digest::SHA256.new, &block)

@parameter block [Proc] the callback to invoke when the body is closed.
@parameter digest [Digest] the digest to use.
@parameter message [Request | Response] the message body.

Wrap a message body with a callback. If the body is empty, the callback is not invoked, as there is no data to digest.
def self.wrap(message, digest = Digest::SHA256.new, &block)
	if body = message&.body and !body.empty?
		message.body = self.new(message.body, digest, block)
	end
end

def etag(weak: false)

@returns [String] the ETag.
@parameter weak [Boolean] If true, the ETag is marked as weak.

Generate an appropriate ETag for the digest, assuming it is complete. If you call this method before the body is fully read, the ETag will be incorrect.
def etag(weak: false)
	if weak
		"W/\"#{digest.hexdigest}\""
	else
		"\"#{digest.hexdigest}\""
	end
end

def initialize(body, digest = Digest::SHA256.new, callback = nil)

@parameter callback [Block] The callback is invoked when the digest is complete.
@parameter digest [Digest] the digest to use.
@parameter body [Readable] the body to wrap.

Initialize the digestable body with a callback.
def initialize(body, digest = Digest::SHA256.new, callback = nil)
	super(body)
	
	@digest = digest
	@callback = callback
end

def read

@returns [String | Nil] the next chunk of data, or nil if the body is fully read.

Read the body and update the digest. When the body is fully read, the callback is invoked with `self` as the argument.
def read
	if chunk = super
		@digest.update(chunk)
		
		return chunk
	else
		@callback&.call(self)
		
		return nil
	end
end