module Sprockets::DigestUtils

def detect_digest_class(bytes)

Returns Digest::Base or nil.

While not elegant, all the supported digests have a unique bytesize.

Internal: Detect digest class hash algorithm for digest bytes.
def detect_digest_class(bytes)
  DIGEST_SIZES[bytes.bytesize]
end

def digest(obj)

Returns a String digest of the object.

obj - A JSON serializable object.

wicked fast. Microbenchmarks away!
This is used for generating cache keys, so its pretty important its

Internal: Generate a hexdigest for a nested JSON serializable object.
def digest(obj)
  digest = digest_class.new
  queue  = [obj]
  while queue.length > 0
    obj = queue.shift
    klass = obj.class
    if klass == String
      digest << obj
    elsif klass == Symbol
      digest << 'Symbol'
      digest << obj.to_s
    elsif klass == Fixnum
      digest << 'Fixnum'
      digest << obj.to_s
    elsif klass == Bignum
      digest << 'Bignum'
      digest << obj.to_s
    elsif klass == TrueClass
      digest << 'TrueClass'
    elsif klass == FalseClass
      digest << 'FalseClass'
    elsif klass == NilClass
      digest << 'NilClass'.freeze
    elsif klass == Array
      digest << 'Array'
      queue.concat(obj)
    elsif klass == Hash
      digest << 'Hash'
      queue.concat(obj.sort)
    elsif klass == Set
      digest << 'Set'
      queue.concat(obj.to_a)
    elsif klass == Encoding
      digest << 'Encoding'
      digest << obj.name
    else
      raise TypeError, "couldn't digest #{klass}"
    end
  end
  digest.digest
end

def digest_class

Returns a Digest::Base subclass.

Internal: Default digest class.
def digest_class
  Digest::SHA256
end

def hexdigest_integrity_uri(hexdigest)

Returns a String or nil if hash algorithm is incompatible.

digest - The String hexbyte digest of the asset content.

as per the subresource integrity specification.
Public: Generate hash for use in the `integrity` attribute of an asset tag
def hexdigest_integrity_uri(hexdigest)
  integrity_uri(unpack_hexdigest(hexdigest))
end

def integrity_uri(digest)

Returns a String or nil if hash algorithm is incompatible.

digest - The String byte digest of the asset content.

as per the subresource integrity specification.
Public: Generate hash for use in the `integrity` attribute of an asset tag
def integrity_uri(digest)
  case digest
  when Digest::Base
    digest_class = digest.class
    digest = digest.digest
  when String
    digest_class = DIGEST_SIZES[digest.bytesize]
  else
    raise TypeError, "unknown digest: #{digest.inspect}"
  end
  if hash_name = HASH_ALGORITHMS[digest_class]
    "#{hash_name}-#{pack_base64digest(digest)}"
  end
end

def pack_base64digest(bin)

Returns base64 String.

bin - String bytes

Internal: Pack a binary digest to a base64 encoded string.
def pack_base64digest(bin)
  [bin].pack('m0')
end

def pack_hexdigest(bin)

Returns hex String.

bin - String bytes

Internal: Pack a binary digest to a hex encoded string.
def pack_hexdigest(bin)
  bin.unpack('H*').first
end

def pack_urlsafe_base64digest(bin)

Returns urlsafe base64 String.

bin - String bytes

Internal: Pack a binary digest to a urlsafe base64 encoded string.
def pack_urlsafe_base64digest(bin)
  str = pack_base64digest(bin)
  str.tr!('+/'.freeze, '-_'.freeze)
  str.tr!('='.freeze, ''.freeze)
  str
end

def unpack_hexdigest(hex)

Returns binary String.

hex - String hex

Internal: Unpack a hex encoded digest string into binary bytes.
def unpack_hexdigest(hex)
  [hex].pack('H*')
end