The fs2.hash object provides the ability to compute the hash of a stream of bytes (i.e. Stream[F, Byte]). The hash computation is modeled as a Pipe[F, Byte, Byte], where pulling on the output stream results in all the source bytes getting hashed and then a final chunk being emitted that contains the hash of the seen bytes.
This API is not expressive enough for common use cases though. Consider the case where a Stream[F, Byte] needs to be written to a file (or uploaded to an S3 bucket, or sent to a socket, etc) and the hash also needs to be stored. The current hashing API makes this awkward -- either requiring heavy duty machinery like broadcastThrough or requiring the stream to be processed twice.
This PR deprecates the fs2.hash object and replaces it with the new fs2.hashing package. The entry point to the new package is the Hashing[F] capability trait, allowing the creation of Hash[F] objects as well as providing various convenience methods.
The hashing package contains:
HashAlgorithm enumeration -- e.g., HashAlgorithm.SHA256 and HashAlgorithm.Named("MD2")
Hash[F] mutable object -- allows incremental computation of hashes with a specific algorithm. Hash defines the following operations:
Low level hashing operations: addChunk(c: Chunk[Byte]): F[Unit] and computeAndReset: F[Chunk[Byte]]
update: Pipe[F, Byte, Byte] - updates the hash with the chunks pulled through the pipe
observe(source: Stream[F, Byte], sink: Pipe[F, Byte, Nothing]): Stream[F, Byte] - returns a stream that outputs the hash of the source bytes after they've been consumed by the supplied sink
hash: Pipe[F, Byte, Byte] - outputs the hash of the source bytes
verify(expected: Chunk[Byte])(implicit F: RaiseThrowable[F]): Pipe[F, Byte, Byte] - pipe that outputs the source bytes but raises a HashVerificationException when the source terminates if the hash of seen bytes doesn't match the expected hash
Hashing[F] capability trait -- allows creation of Hash[F] objects
The Hashing[F] trait returns Hash[F] objects as resources (i.e. Resource[F, Hash[F]]) because (on some platforms) they have to be released after computations are complete.
With this new API, writing the contents of a source to a file and then subsequently writing a hash to a separate file, while processing the source just once, can be accomplished like so:
The Hashing object also contains utility functions for hashing a pure stream and a chunk.
val h1 = Hashing.hashChunk(HashAlgorithm.SHA256, Chunk.array("The quick brown fox".getBytes))
val h2 = Hashing.hashPureStream(HashAlgorithm.SHA256, Stream.chunk(Chunk.array("The quick brown fox".getBytes)))
The
fs2.hash
object provides the ability to compute the hash of a stream of bytes (i.e.Stream[F, Byte]
). The hash computation is modeled as aPipe[F, Byte, Byte]
, where pulling on the output stream results in all the source bytes getting hashed and then a final chunk being emitted that contains the hash of the seen bytes.This API is not expressive enough for common use cases though. Consider the case where a
Stream[F, Byte]
needs to be written to a file (or uploaded to an S3 bucket, or sent to a socket, etc) and the hash also needs to be stored. The current hashing API makes this awkward -- either requiring heavy duty machinery likebroadcastThrough
or requiring the stream to be processed twice.This PR deprecates the
fs2.hash
object and replaces it with the newfs2.hashing
package. The entry point to the new package is theHashing[F]
capability trait, allowing the creation ofHash[F]
objects as well as providing various convenience methods.The hashing package contains:
HashAlgorithm
enumeration -- e.g.,HashAlgorithm.SHA256
andHashAlgorithm.Named("MD2")
Hash[F]
mutable object -- allows incremental computation of hashes with a specific algorithm.Hash
defines the following operations:addChunk(c: Chunk[Byte]): F[Unit]
andcomputeAndReset: F[Chunk[Byte]]
update: Pipe[F, Byte, Byte]
- updates the hash with the chunks pulled through the pipeobserve(source: Stream[F, Byte], sink: Pipe[F, Byte, Nothing]): Stream[F, Byte]
- returns a stream that outputs the hash of the source bytes after they've been consumed by the supplied sinkhash: Pipe[F, Byte, Byte]
- outputs the hash of the source bytesverify(expected: Chunk[Byte])(implicit F: RaiseThrowable[F]): Pipe[F, Byte, Byte]
- pipe that outputs the source bytes but raises aHashVerificationException
when the source terminates if the hash of seen bytes doesn't match the expected hashHashing[F]
capability trait -- allows creation ofHash[F]
objectsThe
Hashing[F]
trait returnsHash[F]
objects as resources (i.e.Resource[F, Hash[F]]
) because (on some platforms) they have to be released after computations are complete.With this new API, writing the contents of a source to a file and then subsequently writing a hash to a separate file, while processing the source just once, can be accomplished like so:
The
Hashing
object also contains utility functions for hashing a pure stream and a chunk.