Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!(EncodeTryCompress): Brotli compression #105

Merged
merged 7 commits into from
Sep 11, 2023
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions src/FsCodec.Box/TryDeflate.fs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,17 @@ module private EncodedMaybeDeflated =
type Encoding =
| Direct = 0
| Deflate = 1
| Brotli = 2
bartelink marked this conversation as resolved.
Show resolved Hide resolved
type Encoded = (struct (int * ReadOnlyMemory<byte>))
let empty : Encoded = int Encoding.Direct, ReadOnlyMemory.Empty

let private brotliDecompress (data: ReadOnlyMemory<byte>): byte[] =
use s = new System.IO.MemoryStream(data.ToArray())
bartelink marked this conversation as resolved.
Show resolved Hide resolved
use decompressor = new System.IO.Compression.BrotliStream(s, System.IO.Compression.CompressionMode.Decompress)
use output = new System.IO.MemoryStream()
decompressor.CopyTo(output)
output.ToArray()

(* EncodedBody can potentially hold compressed content, that we'll inflate on demand *)

let private inflate (data : ReadOnlyMemory<byte>) : byte[] =
Expand All @@ -22,10 +30,18 @@ module private EncodedMaybeDeflated =
output.ToArray()
let decode struct (encoding, data) : ReadOnlyMemory<byte> =
if encoding = int Encoding.Deflate then inflate data |> ReadOnlyMemory
bartelink marked this conversation as resolved.
Show resolved Hide resolved
else if encoding = int Encoding.Brotli then brotliDecompress data |> ReadOnlyMemory
else data

(* Compression is conditional on the input meeting a minimum size, and the result meeting a required gain *)

let private brotliCompress (eventBody: ReadOnlyMemory<byte>): System.IO.MemoryStream =
let output = new System.IO.MemoryStream()
use compressor = new System.IO.Compression.BrotliStream(output, System.IO.Compression.CompressionLevel.Optimal, leaveOpen = true)
compressor.Write(eventBody.Span)
compressor.Close()
output

let private deflate (eventBody : ReadOnlyMemory<byte>) : System.IO.MemoryStream =
let output = new System.IO.MemoryStream()
let compressor = new System.IO.Compression.DeflateStream(output, System.IO.Compression.CompressionLevel.Optimal, leaveOpen = true)
Expand All @@ -35,8 +51,8 @@ module private EncodedMaybeDeflated =
let encodeUncompressed (raw : ReadOnlyMemory<byte>) : Encoded = 0, raw
let encode minSize minGain (raw : ReadOnlyMemory<byte>) : Encoded =
if raw.Length < minSize then encodeUncompressed raw
else match deflate raw with
| tmp when raw.Length > int tmp.Length + minGain -> int Encoding.Deflate, tmp.ToArray() |> ReadOnlyMemory
else match brotliCompress raw with
| tmp when raw.Length > int tmp.Length + minGain -> int Encoding.Brotli, tmp.ToArray() |> ReadOnlyMemory
| _ -> encodeUncompressed raw

type [<Struct>] CompressionOptions = { minSize : int; minGain : int } with
Expand Down