Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
85df8a7
stuff
RandomHashTags Apr 7, 2026
39d1138
add deflate support
RandomHashTags Apr 7, 2026
9431360
refactor compressor/decompressor protocols
RandomHashTags Apr 7, 2026
cdad381
update readme and package.swift
RandomHashTags Apr 7, 2026
00e5815
add `libdeflate` to readme
RandomHashTags Apr 7, 2026
af60619
support gzip
RandomHashTags Apr 7, 2026
e5254ec
support compressing/decompressing `Span<UInt8>` for zlib
RandomHashTags Apr 7, 2026
14b9b7d
stuff
RandomHashTags Apr 8, 2026
5f4cda1
rename `CompressionResult` typealias to `ConcreteCompressionResult`
RandomHashTags Apr 9, 2026
f472187
rename `DecompressionResult` typealias to `ConcreteDecompressionResult`
RandomHashTags Apr 9, 2026
011fbe2
add Brotli support and...
RandomHashTags Apr 9, 2026
f36d01c
update README; add default `ConcreteCompressionResult` type
RandomHashTags Apr 9, 2026
24abc9b
add Snappy compression
RandomHashTags Apr 9, 2026
6a70163
remove compression technique convenience extensions
RandomHashTags Apr 9, 2026
37ef735
initialize brotli `outBuffer` after allocation
RandomHashTags Apr 9, 2026
14f0913
minor brotli decompress change
RandomHashTags Apr 9, 2026
68b43cd
move huffman to its own module
RandomHashTags Apr 9, 2026
169f047
move `ByteBuilder` to its own module
RandomHashTags Apr 9, 2026
8115272
move building frequency tables to its own module
RandomHashTags Apr 9, 2026
b2f8ae8
fix unit test compilation; rename `DataBuilder` to `BytesBuilder`
RandomHashTags Apr 9, 2026
4814ea2
remove `hexadecimal` function and unit test
RandomHashTags Apr 9, 2026
350d7ea
add `SwiftCompressionUtilities` product
RandomHashTags Apr 9, 2026
38c1685
remove `CompressionTechnique`; minor unit test corrections
RandomHashTags Apr 10, 2026
986ef73
Brotli & Snappy: use temporary buffers instead of ones always on the …
RandomHashTags Apr 10, 2026
ef8f54a
stuff
RandomHashTags Apr 12, 2026
f704fba
adopt package traits and...
RandomHashTags Apr 12, 2026
e40556e
macOS fixes
RandomHashTags Apr 13, 2026
c4f2865
macOS fix
RandomHashTags Apr 13, 2026
643ff52
add macOS availability checks for Span
RandomHashTags Apr 13, 2026
e26788c
fix some macOS availability annotations
RandomHashTags Apr 13, 2026
95a6262
update zlib shim
RandomHashTags Apr 13, 2026
8176629
update brotli shim
RandomHashTags Apr 13, 2026
a11b860
update shims checking if `__has_include`
RandomHashTags Apr 13, 2026
f60953b
update Snappy shim
RandomHashTags Apr 13, 2026
39eb9a8
bonk
RandomHashTags Apr 13, 2026
21bb887
more package traits to build successfully on any os
RandomHashTags Apr 13, 2026
ad14d00
zlib gzip requires deflate
RandomHashTags Apr 13, 2026
359d24f
`SwiftCompression` module fixes
RandomHashTags Apr 13, 2026
e0e8964
minor fix
RandomHashTags Apr 13, 2026
4e76411
update linker settings to utilize traits
RandomHashTags Apr 13, 2026
7263234
add 2 more traits + 1 change
RandomHashTags Apr 13, 2026
76b66a9
fix unit test compilation
RandomHashTags Aug 1, 2026
6c57953
lz77 & byte builder changes
RandomHashTags Aug 2, 2026
4055a18
remove `#if compiler(>=6.0)` compilation check
RandomHashTags Aug 2, 2026
ecd8723
fix byte builder logic; fix dna binary encoding
RandomHashTags Aug 3, 2026
a1252b0
fix bit tests
RandomHashTags Aug 3, 2026
0125283
fix failing huffman unit test
RandomHashTags Aug 3, 2026
c3a68f9
remove foundation package traits and imports
RandomHashTags Aug 3, 2026
c559c76
avoid unsafe pointers; delete empty files
RandomHashTags Aug 3, 2026
d70916e
simplify checking byte bits, making some code, and unit tests, obsolete
RandomHashTags Aug 3, 2026
87278d3
ByteBuilder: allow writing more than 8 bits at a time
RandomHashTags Aug 4, 2026
5df59b8
lzz77 compression tests + byte result
RandomHashTags Aug 4, 2026
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
220 changes: 153 additions & 67 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,94 +1,198 @@
// swift-tools-version:5.9
// swift-tools-version:6.1

import PackageDescription

let package = Package(
name: "swift-compression",
// MARK: Products
products: [
.library(
name: "SwiftCompression",
targets: ["SwiftCompression"]
),
.library(name: "SwiftCompression", targets: ["SwiftCompression"]),
.library(name: "SwiftCompressionUtilities", targets: ["SwiftCompressionUtilities"]),

.library(
name: "SwiftCompressionCSS",
targets: ["CompressionCSS"]
),
.library(name: "Brotli", targets: ["Brotli"]),
.library(name: "SwiftCompressionDNA", targets: ["CompressionDNA"]),
.library(name: "SwiftCompressionLZ", targets: ["CompressionLZ"]),
.library(name: "FrequencyTables", targets: ["FrequencyTables"]),
.library(name: "Huffman", targets: ["Huffman"]),
.library(name: "RunLengthEncoding", targets: ["RunLengthEncoding"]),
.library(name: "Snappy", targets: ["Snappy"]),
.library(name: "Zlib", targets: ["Zlib"])
],
// MARK: Traits
traits: [
.default(enabledTraits: [
"Brotli",
"Huffman",
"LZ77",
"RunLengthEncoding",
"Snappy",
"ZlibDeflate",
"ZlibGzip",

.library(
name: "SwiftCompressionDNA",
targets: ["CompressionDNA"]
),
"AlgorithmAnyCompressor",
"AlgorithmAnyDecompressor",

.library(
name: "SwiftCompressionJavaScript",
targets: ["CompressionJavaScript"]
),
"CollectionCompress", "CollectionDecompress",
"BrotliCompress", "BrotliDecompress",
"HuffmanCompress", "HuffmanDecompress",
"LZ77Compress", "LZ77Decompress",
"SnappyCompress", "SnappyDecompress",
"RunLengthEncodingCompress", "RunLengthEncodingDecompress",
"ZlibDeflateCompress", "ZlibDeflateDecompress",
"ZlibGzipCompress", "ZlibGzipDecompress",
]),

.library(
name: "SwiftCompressionLZ",
targets: ["CompressionLZ"]
),
.trait(name: "AlgorithmAnyCompressor", description: "Enables the `compressor: (any Compressor)?` computed property for `CompressionAlgorithm`."),
.trait(name: "AlgorithmAnyDecompressor", description: "Enables the `decompressor: (any Decompressor)?` computed property for `CompressionAlgorithm`."),

.library(
name: "SwiftCompressionSnappy",
targets: ["CompressionSnappy"]
),
.trait(name: "CollectionCompress", enabledTraits: [
"BrotliCompressCollection",
"HuffmanCompressCollection",
"LZ77CompressCollection",
"RunLengthEncodingCompressCollection",
"SnappyCompressCollection",
"ZlibDeflateCompressCollection",
"ZlibGzipCompressCollection",
]),

.trait(name: "CollectionDecompress", enabledTraits: [
"BrotliDecompressCollection",
"HuffmanDecompressCollection",
"LZ77DecompressCollection",
"RunLengthEncodingDecompressCollection",
"SnappyDecompressCollection",
"ZlibDeflateDecompressCollection",
"ZlibGzipDecompressCollection",
]),

.trait(name: "Brotli", description: "Enables Brotli."),
.trait(name: "BrotliCompress", description: "Enables Brotli compression for Span<UInt8>.", enabledTraits: ["Brotli"]),
.trait(name: "BrotliCompressCollection", description: "Enables Brotli compression for some Collection<UInt8>.", enabledTraits: ["BrotliCompress"]),
.trait(name: "BrotliDecompress", description: "Enables Brotli decompression for Span<UInt8>.", enabledTraits: ["Brotli"]),
.trait(name: "BrotliDecompressCollection", description: "Enables Brotli decompression for some Collection<UInt8>.", enabledTraits: ["BrotliDecompress"]),

.trait(name: "Huffman", description: "Enables Huffman."),
.trait(name: "HuffmanCompress", description: "Enables Huffman compression for Span<UInt8>.", enabledTraits: ["Huffman"]),
.trait(name: "HuffmanCompressCollection", description: "Enables Huffman compression for some Collection<UInt8>.", enabledTraits: ["HuffmanCompress"]),
.trait(name: "HuffmanDecompress", description: "Enables Huffman decompression for Span<UInt8>.", enabledTraits: ["Huffman"]),
.trait(name: "HuffmanDecompressCollection", description: "Enables Huffman decompression for some Collection<UInt8>.", enabledTraits: ["HuffmanDecompress"]),

.trait(name: "LZ77", description: "Enables LZ77."),
.trait(name: "LZ77Compress", description: "Enables LZ77 compression for Span<UInt8>.", enabledTraits: ["LZ77"]),
.trait(name: "LZ77CompressCollection", description: "Enables LZ77 compression for some Collection<UInt8>.", enabledTraits: ["LZ77Compress"]),
.trait(name: "LZ77Decompress", description: "Enables LZ77 decompression for Span<UInt8>.", enabledTraits: ["LZ77"]),
.trait(name: "LZ77DecompressCollection", description: "Enables LZ77 decompression for some Collection<UInt8>.", enabledTraits: ["LZ77Decompress"]),

.trait(name: "RunLengthEncoding", description: "Enables RunLengthEncoding."),
.trait(name: "RunLengthEncodingCompress", description: "Enables RunLengthEncoding compression for Span<UInt8>.", enabledTraits: ["RunLengthEncoding"]),
.trait(name: "RunLengthEncodingCompressCollection", description: "Enables RunLengthEncoding compression for some Collection<UInt8>.", enabledTraits: ["RunLengthEncodingCompress"]),
.trait(name: "RunLengthEncodingDecompress", description: "Enables RunLengthEncoding decompression for Span<UInt8>.", enabledTraits: ["RunLengthEncoding"]),
.trait(name: "RunLengthEncodingDecompressCollection", description: "Enables RunLengthEncoding decompression for some Collection<UInt8>.", enabledTraits: ["RunLengthEncodingDecompress"]),

.trait(name: "Snappy", description: "Enables Snappy."),
.trait(name: "SnappyCompress", description: "Enables Snappy compression for Span<UInt8>.", enabledTraits: ["Snappy"]),
.trait(name: "SnappyCompressCollection", description: "Enables Snappy compression for some Collection<UInt8>.", enabledTraits: ["SnappyCompress"]),
.trait(name: "SnappyDecompress", description: "Enables Snappy decompression for Span<UInt8>.", enabledTraits: ["Snappy"]),
.trait(name: "SnappyDecompressCollection", description: "Enables Snappy decompression for some Collection<UInt8>.", enabledTraits: ["SnappyDecompress"]),

.trait(name: "ZlibDeflate", description: "Enables ZlibDeflate."),
.trait(name: "ZlibDeflateCompress", description: "Enables ZlibDeflate compression for Span<UInt8>.", enabledTraits: ["ZlibDeflate"]),
.trait(name: "ZlibDeflateCompressCollection", description: "Enables ZlibDeflate compression for some Collection<UInt8>.", enabledTraits: ["ZlibDeflateCompress"]),
.trait(name: "ZlibDeflateDecompress", description: "Enables ZlibDeflate decompression for Span<UInt8>.", enabledTraits: ["ZlibDeflate"]),
.trait(name: "ZlibDeflateDecompressCollection", description: "Enables ZlibDeflate decompression for some Collection<UInt8>.", enabledTraits: ["ZlibDeflateDecompress"]),

.trait(name: "ZlibGzip", description: "Enables ZlibGzip"),
.trait(name: "ZlibGzipCompress", description: "Enables ZlibGzip compression for Span<UInt8>.", enabledTraits: ["ZlibGzip", "ZlibDeflateCompress"]),
.trait(name: "ZlibGzipCompressCollection", description: "Enables ZlibGzip compression for some Collection<UInt8>.", enabledTraits: ["ZlibGzipCompress"]),
.trait(name: "ZlibGzipDecompress", description: "Enables ZlibGzip decompression for Span<UInt8>.", enabledTraits: ["ZlibGzip", "ZlibDeflateDecompress"]),
.trait(name: "ZlibGzipDecompressCollection", description: "Enables ZlibGzip decompression for some Collection<UInt8>.", enabledTraits: ["ZlibGzipDecompress"]),
],

// MARK: Targets
targets: [
.target(
name: "SwiftCompressionUtilities"
),
.target(name: "ByteBuilder"),
.target(name: "FrequencyTables"),
.target(name: "SwiftCompressionUtilities"),

.target(
name: "SwiftCompression",
dependencies: [
"SwiftCompressionUtilities",
"CompressionCSS",
"Brotli",
"CompressionDNA",
"CompressionJavaScript",
"CompressionLZ",
"CompressionSnappy"
"Huffman",
"RunLengthEncoding",
"Snappy",
"Zlib",
"SwiftCompressionUtilities",
]
),

// MARK: Techniques
.systemLibrary(name: "BrotliShim"),
.target(
name: "CompressionCSS",
name: "Brotli",
dependencies: [
"SwiftCompressionUtilities"
"SwiftCompressionUtilities",
"BrotliShim"
],
path: "Sources/CSS"
linkerSettings: [
.unsafeFlags(["-lbrotlienc"], .when(traits: ["BrotliCompress"])),
.unsafeFlags(["-lbrotlidec"], .when(traits: ["BrotliDecompress"]))
]
),
.systemLibrary(name: "ZlibShim"),
.target(
name: "Zlib",
dependencies: [
"SwiftCompressionUtilities",
"ZlibShim"
]
),

.target(
name: "CompressionDNA",
dependencies: [
"ByteBuilder",
"FrequencyTables",
"SwiftCompressionUtilities"
],
path: "Sources/DNA"
),
.target(
name: "CompressionJavaScript",
name: "CompressionLZ",
dependencies: [
"ByteBuilder",
"SwiftCompressionUtilities"
],
path: "Sources/JavaScript"
path: "Sources/LZ"
),

.target(
name: "CompressionLZ",
name: "Huffman",
dependencies: [
"ByteBuilder",
"SwiftCompressionUtilities"
],
path: "Sources/LZ"
]
),

.target(
name: "CompressionSnappy",
name: "RunLengthEncoding",
dependencies: [
"SwiftCompressionUtilities"
]
),

.systemLibrary(name: "SnappyShim"),
.target(
name: "Snappy",
dependencies: [
"ByteBuilder",
"SwiftCompressionUtilities",
"SnappyShim"
],
path: "Sources/Snappy"
linkerSettings: [
.unsafeFlags(["-lsnappy"], .when(traits: ["Snappy"]))
]
),

// MARK: Run
Expand All @@ -100,30 +204,12 @@ let package = Package(
),

// MARK: Unit tests
.testTarget(
name: "SwiftCompressionTests",
dependencies: ["SwiftCompression"]
),
.testTarget(
name: "CSSTests",
dependencies: ["CompressionCSS"]
),
.testTarget(
name: "DNATests",
dependencies: ["CompressionDNA"]
),
.testTarget(
name: "JavaScriptTests",
dependencies: ["CompressionJavaScript"]
),
.testTarget(
name: "LZTests",
dependencies: ["CompressionLZ"]
),
.testTarget(
name: "SnappyTests",
dependencies: ["CompressionSnappy"]
)
.testTarget(name: "SwiftCompressionTests", dependencies: ["SwiftCompression"]),
.testTarget(name: "BrotliTests", dependencies: ["Brotli"]),
.testTarget(name: "DNATests", dependencies: ["CompressionDNA"]),
.testTarget(name: "LZTests", dependencies: ["CompressionLZ"]),
.testTarget(name: "SnappyTests", dependencies: ["Snappy"]),
.testTarget(name: "ZlibTests", dependencies: ["Zlib"])
]
)

Expand Down
44 changes: 20 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,33 +1,29 @@
# Swift Compression

<a href="https://swift.org"><img src="https://img.shields.io/badge/Swift-5.9+-F05138?style=&logo=swift" alt="Requires at least Swift 5.9"></a> <img src="https://img.shields.io/badge/Platforms-Any-gold"> <a href="https://discord.com/invite/VyuFQUpcUz"><img src="https://img.shields.io/badge/Chat-Discord-7289DA?style=&logo=discord"></a> <a href="https://github.com/RandomHashTags/destiny/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-Apache_2.0-blue" alt="Apache 2.0 License"></a>
<a href="https://swift.org"><img src="https://img.shields.io/badge/Swift-5.9+-F05138?style=&logo=swift" alt="Requires at least Swift 5.9"></a> <img src="https://img.shields.io/badge/Platforms-Any-gold"> <a href="./LICENSE"><img src="https://img.shields.io/badge/License-Apache_2.0-blue" alt="Apache 2.0 License"></a>

Standalone compression & decompression library.

## Techniques

### Compression and decompression

- [Brotli](https://github.com/google/brotli)
- [DEFLATE](https://www.rfc-editor.org/rfc/rfc1951)
- [DNA Binary Encoding](https://en.wikipedia.org/wiki/DNA_digital_data_storage)
- [DNA Single-Block Encoding](https://www.mdpi.com/1999-4893/13/4/99)
- [Huffman Coding](https://en.wikipedia.org/wiki/Huffman_coding)
- [iWork Archive](https://en.wikipedia.org/wiki/IWork)
- [LZ77 & LZ78](https://en.wikipedia.org/wiki/LZ77_and_LZ78)
- [Move-to-front](https://en.wikipedia.org/wiki/Move-to-front_transform)
- [Run-Length Encoding](https://en.wikipedia.org/wiki/Run-length_encoding)
- [Snappy](https://github.com/google/snappy)
- [Snappy Framed](https://github.com/google/snappy/blob/main/framing_format.txt)
- [Zstd](https://github.com/facebook/zstd)

### Minification

- CSS
- JavaScript
- Swift

## Getting starting
- [x] [Brotli](https://github.com/google/brotli)
- [ ] [DEFLATE](https://www.rfc-editor.org/rfc/rfc1951)
- [x] via zlib
- [ ] via libdeflate
- [x] [DNA Binary Encoding](https://en.wikipedia.org/wiki/DNA_digital_data_storage)
- [ ] [DNA Single-Block Encoding](https://www.mdpi.com/1999-4893/13/4/99)
- [x] [Huffman Coding](https://en.wikipedia.org/wiki/Huffman_coding)
- [ ] [iWork Archive](https://en.wikipedia.org/wiki/IWork)
- [ ] [LZ77 & LZ78](https://en.wikipedia.org/wiki/LZ77_and_LZ78)
- [x] [Move-to-front](https://en.wikipedia.org/wiki/Move-to-front_transform)
- [x] [Run-Length Encoding](https://en.wikipedia.org/wiki/Run-length_encoding)
- [x] [Snappy](https://github.com/google/snappy)
- [ ] [Snappy Framed](https://github.com/google/snappy/blob/main/framing_format.txt)
- [ ] [Zstd](https://github.com/facebook/zstd)

## Getting started

coming soon...

Expand All @@ -36,11 +32,11 @@ coming soon...
The products are broken up into their respective algorithms, but the __SwiftCompression__ product includes all of them and is the recommended one to use in your projects.

- SwiftCompression
- SwiftCompressionCSS
- SwiftCompressionDNA
- SwiftCompressionJavaScript
- SwiftCompressionLZ
- SwiftCompressionSnappy
- Brotli
- Snappy
- Zlib

## Contributing

Expand Down
34 changes: 34 additions & 0 deletions Sources/Brotli/Brotli+Compress+Collection.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@

#if BrotliCompressCollection

import BrotliShim
import SwiftCompressionUtilities

extension Brotli {
/// - Parameters:
/// - data: Sequence of bytes to compress.
/// - Complexity: O(_n_) where _n_ is the length of `data`.
public func compress(
_ collection: some Collection<UInt8>,
configuration: ConcreteCompressionConfiguration
) -> ConcreteCompressionResult {
var outLength = collection.count
let maxSize = BrotliEncoderMaxCompressedSize(outLength)
return withUnsafeTemporaryAllocation(of: UInt8.self, capacity: maxSize, { outBuffer in
let success = collection.withContiguousStorageIfAvailable {
return BrotliEncoderCompress(
quality,
windowSize,
BrotliEncoderMode(rawValue: mode),
outLength,
$0.baseAddress,
&outLength,
outBuffer.baseAddress
)
} ?? BROTLI_FALSE
return success == BROTLI_TRUE ? [UInt8](outBuffer.prefix(outLength)) : nil
})
}
}

#endif
Loading