Skip to content

Commit eb24501

Browse files
authored
Merge pull request #7 from jozzzzep/dev
v1.5.6
2 parents 7877e35 + c05447f commit eb24501

15 files changed

+43713
-405
lines changed

CHANGELOG.md

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,31 @@
11
# Changelog
22

3-
All notable changes to the "shrink" package will be documented in this file.
3+
All notable changes to the `shrink` package will be documented in this file.
4+
5+
## 1.5.6
6+
7+
### Fixed
8+
9+
- Fixed a critical bug where compression method values 1–9 were ambiguously used for both ZLIB and GZIP
10+
11+
### Changed
12+
13+
- Simplified compression logic by removing redundant GZIP compression options
14+
- Migrated to a new fixed method ID scheme (identity=0, zlib=10) while maintaining backward compatibility
15+
16+
### Added
17+
18+
- Improved compression performance by 90%+ across all compressions
19+
- Optimized ZLIB level probing with early stopping when no further size gain is observed
20+
- Added extensive test coverage, including legacy method fallback
21+
- Added performance benchmarking and validation against real-world data samples
22+
- Added a comprehensive beginner's guide to the README with detailed step-by-step explanations for:
23+
- Package installation and setup
24+
- Importing and basic usage
25+
- Compressing different data types
26+
- Restoring compressed data
27+
- Firebase integration examples
28+
- Best practices and common patterns
429

530
## 1.5.5
631

README.md

Lines changed: 198 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Compress any data in one line — no setup, no boilerplate, and nothing to confi
1717
- [How It Works Under the Hood](#-how-it-works-under-the-hood)
1818
- [Testing & Validation](#-testing--validation)
1919
- [Firebase Integration Example](#-firebase-integration-example)
20+
- [Beginner's Guide: Step-by-Step Setup & Usage](#-beginners-guide-step-by-step-setup--usage)
2021
- [Roadmap & Future Plans](#-roadmap--future-plans)
2122

2223
---
@@ -141,6 +142,12 @@ final restoredBytes = Restore.bytes(shrinkedBytes);
141142

142143
# 📊 Benchmarks
143144

145+
> 🛡 **Built for the long haul.**
146+
> When `shrink` gets faster, smaller, and smarter — **you don’t have to lift a finger**.
147+
> Every version in the `1.x.x` line is fully **backward compatible**.
148+
> Your existing data will always decompress perfectly, no matter how the internals evolve.
149+
> Just update and enjoy the gains — **no migrations, no breakage, no surprises**.
150+
144151
`shrink` has been benchmarked with a variety of real-world data scenarios, including:
145152

146153
- Raw bytes: random, repetitive, alternating, zero-filled
@@ -166,13 +173,18 @@ Shrink leverages this reality and combines compression strategies to achieve sig
166173

167174
## 📦 Compression Results (Bytes & Text)
168175

169-
| Data Pattern | Input Size (Bytes) | Shrink Size | Space Saved | Factor |
170-
| ------------------ | ------------------ | ----------- | ----------- | --------- |
171-
| Random (1KB) | 1,000 | 1,001 | `None` | `No gain` |
172-
| Repetitive (1KB) | 1,000 | 27 | **97.3%** | **37.0×** |
173-
| Alternating Bytes | 1,000 | 18 | **98.2%** | **55.6×** |
174-
| Mostly Zeros | 1,000 | 73 | **92.7%** | **13.7×** |
175-
| Large Random (1MB) | 1,048,576 | 1,048,577 | `None` | `No gain` |
176+
| Data Pattern | Input Size (Bytes) | Shrink Size | Space Saved | Factor |
177+
| ----------------- | ------------------ | ----------- | ----------- | --------- |
178+
| Random (1KB) | 1,000 | 1,001 | `None` | `No gain` |
179+
| Repetitive (1KB) | 1,000 | 27 | **97.3%** | **37.0×** |
180+
| Alternating Bytes | 1,000 | 18 | **98.2%** | **55.6×** |
181+
| Mostly Zeros | 1,000 | 73 | **92.7%** | **13.7×** |
182+
183+
🔍 **Notes:**
184+
185+
- **Large Alternating**: Simulates binary signal streams or periodic sensor toggles (0x00, 0xFF, repeated).
186+
- **Large Structured (Logs)**: Mimics repetitive log lines like INFO [12:00] Started....
187+
- **Large Repeated Strings**: Represents large user content with repeated headers, phrases, or template fragments.
176188

177189
> 💡 In Shrink, when compression doesn’t help, it’s intelligently skipped — so there’s no overhead.
178190
@@ -186,6 +198,7 @@ Shrink leverages this reality and combines compression strategies to achieve sig
186198
| Repeated Struct. | 10,591 | 623 | 94.12% | 17.0× |
187199
| Mixed Content | 1,632 | 403 | 75.31% | 4.05× |
188200
| Large (12101 chars) | 12,101 | 428 | 96.46% | 28.27× |
201+
| Real-world JSON (40K) | 83,389 | 24,312 | 70.84% | 3.43× |
189202

190203
## 🔢 Unique Integer Lists
191204

@@ -220,11 +233,8 @@ When using `Shrink.bytes(...)`, the input is evaluated with multiple algorithms:
220233
- **Identity** (no compression)
221234
Useful when compression would increase the data size.
222235

223-
- **ZLIB** (levels 1–9)
224-
Fast and widely supported, good for structured data.
225-
226-
- **GZIP** (levels 1–9)
227-
Slightly larger output, but better for HTTP-compatible scenarios.
236+
- **ZLIB** (optimized level between 4–9)
237+
Fast, compact, and widely supported — ideal for structured or repetitive data.
228238

229239
The smallest result is selected automatically.
230240
The **first byte** of the compressed output encodes the method used, so `Restore.bytes(...)` can safely reverse the process.
@@ -300,6 +310,8 @@ You can rely on `shrink` in **production environments** such as:
300310
- Network transmission over low bandwidth
301311
- Size-optimized APIs or backups
302312

313+
Performance and compression algorithms continue to improve with each release — but all `1.x.x` versions of `shrink` maintain **full backward compatibility**. You’ll never need to re-compress or migrate your existing data — it will always restore correctly, regardless of how the internals evolve.
314+
303315
# 🔥 Firebase Integration Example
304316

305317
Storing large lists (like inventory, user items, or flags) in Firestore can get expensive — especially when using arrays of integers. With `shrink`, you can compress the list into a tiny `Blob` field, saving both **space** and **money**, while preserving full data integrity.
@@ -350,6 +362,180 @@ final restoredItems = compressed.restoreUnique(); // or Restore.unique(compresse
350362

351363
> ℹ️ _Tip: You can use this approach for storing compressed JSON, logs, flags, or anything serializable into a list or string._
352364
365+
# 🧑‍🏫 Beginner's Guide: Step-by-Step Setup & Usage
366+
367+
This guide walks you through installing and using shrink — a lightweight and powerful tool to compress your data and save space with just one line of code.
368+
369+
You can shrink text, JSON, byte data, or lists of IDs. It’s great for reducing payloads, speeding up storage, and minimizing Firebase costs.
370+
371+
---
372+
373+
### ✅ Step 1: Add `shrink` to Your Project
374+
375+
#### 🔧 Option A: Use a command (easy & automatic)
376+
377+
In your terminal, run one of these:
378+
379+
```bash
380+
flutter pub add shrink # if you're using Flutter
381+
```
382+
383+
or
384+
385+
```bash
386+
dart pub add shrink # if you're using Dart only (no Flutter)
387+
```
388+
389+
#### 📄 Option B: Edit `pubspec.yaml` manually
390+
391+
Open your `pubspec.yaml` file and add:
392+
393+
```yaml
394+
dependencies:
395+
shrink: ^latest
396+
```
397+
398+
Then run:
399+
400+
```bash
401+
flutter pub get # for Flutter
402+
```
403+
404+
or
405+
406+
```bash
407+
dart pub get # for Dart only
408+
```
409+
410+
That’s it! You’ve added `shrink` to your project.
411+
Now you're ready to compress and restore data with just a few lines of code.
412+
413+
---
414+
415+
### ✅ Step 2: Import the Package
416+
417+
In your Dart/Flutter file:
418+
419+
```dart
420+
import 'package:shrink/shrink.dart';
421+
```
422+
423+
This gives you access to all the `.shrink()` and `.restoreX()` functions.
424+
425+
---
426+
427+
### ✅ Step 3: Shrink Different Types of Data
428+
429+
You can shrink 4 types of data.
430+
Each type has its own example — use the one that matches what you want to compress.
431+
432+
#### 📦 Example 1: Shrink a String (like a message, log, or description)
433+
434+
```dart
435+
final compressed = 'Hello world! This is a long message.'.shrink();
436+
437+
// Later, to get it back:
438+
final restored = compressed.restoreText();
439+
```
440+
441+
#### 🧠 Example 2: Shrink a JSON object (like user data or settings)
442+
443+
```dart
444+
final compressed = {'name': 'Alice', 'age': 30}.shrink();
445+
446+
// Later:
447+
final restored = compressed.restoreJson();
448+
```
449+
450+
#### 🔢 Example 3: Shrink a list of IDs (like item IDs, selected indexes)
451+
452+
```dart
453+
final compressed = [1, 2, 3, 5, 8, 13, 21].shrink();
454+
455+
// Later:
456+
final restored = compressed.restoreUnique();
457+
```
458+
459+
#### 🛠️ Example 4: Shrink custom data (by converting to bytes)
460+
461+
> 🔍 Prefer using .shrink() on String, JSON, or ID lists when possible. Use bytes only for data types that shrink doesn't support directly.
462+
463+
```dart
464+
final custom = {'type': 'note', 'text': 'Welcome!'};
465+
466+
// Convert to bytes (e.g., JSON + UTF-8)
467+
final bytes = Uint8List.fromList(utf8.encode(jsonEncode(custom)));
468+
469+
// Compress the bytes
470+
final compressed = bytes.shrink();
471+
472+
// Later: restore the bytes
473+
final restored = compressed.restoreBytes();
474+
475+
// Convert bytes back to original data
476+
final original = jsonDecode(utf8.decode(restored));
477+
```
478+
479+
> 💡 Perfect for compressing files, binary blobs, or custom data structures.
480+
481+
---
482+
483+
### ✅ Step 4: Store or Send the Compressed Data
484+
485+
You can now:
486+
487+
- Save it to a database
488+
- Send it over a network
489+
- Store it in memory or a file
490+
491+
**Example: Store it in Firestore**
492+
493+
```dart
494+
await FirebaseFirestore.instance
495+
.collection('users')
496+
.doc('abc123')
497+
.set({'profile_blob': compressed});
498+
```
499+
500+
## ✅ Bonus: Use the Static API Instead (Optional)
501+
502+
If you prefer something more explicit than `.shrink()`, use:
503+
504+
```dart
505+
final compressedText = Shrink.text('Hello');
506+
final compressedJson = Shrink.json({'a': 1});
507+
final compressedIDs = Shrink.unique([10, 20, 30]);
508+
final compressedData = Shrink.bytes(Uint8List.fromList([1, 2, 3]));
509+
```
510+
511+
And to restore:
512+
513+
```dart
514+
final original = Restore.text(compressedText);
515+
```
516+
517+
## 🧪 Complete Example
518+
519+
```dart
520+
import 'package:shrink/shrink.dart';
521+
522+
void main() {
523+
final user = {'id': 1, 'name': 'Bob', 'age': 42};
524+
525+
final compressed = user.shrink(); // Compress
526+
final restored = compressed.restoreJson(); // Restore
527+
528+
print(restored); // Output: {id: 1, name: Bob, age: 42}
529+
}
530+
```
531+
532+
### ℹ️ Good to Know
533+
534+
- ✅ Shrinking is automatic — it picks the best method for your data.
535+
- ✅ Shrink is **lossless** — you always get the original data back.
536+
- ✅ If the data can't be compressed, it just returns it as-is (no size increase).
537+
- ❗ Make sure you use the right `.restoreX()` based on what you compressed.
538+
353539
# 🚀 Roadmap & Future Plans
354540

355541
The `shrink` package is actively maintained and will continue to evolve with new features, performance optimizations, and developer-friendly tools. Here's what’s coming next:

lib/core/restore.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import 'package:shrink/utils/utils.dart';
55
/// A utility class for decompressing data that was compressed using the [Shrink] class.
66
///
77
/// This class provides static methods to decompress various data types:
8-
/// - bytes: Decompresses raw binary data using the optimal compression method (identity, ZLIB, or GZIP)
8+
/// - bytes: Decompresses raw binary data using the optimal compression method (identity or ZLIB)
99
/// - json: Decompresses and parses JSON objects
1010
/// - text: Decompresses strings encoded with UTF-8 and compressed with zlib
1111
/// - unique: Decompresses lists of unique integers
@@ -25,7 +25,9 @@ abstract class Restore {
2525
/// the appropriate decompression algorithm:
2626
/// - Identity (no compression)
2727
/// - ZLIB decompression for ZLIB-compressed data
28-
/// - GZIP decompression for GZIP-compressed data
28+
///
29+
/// Note: For backward compatibility, it also supports legacy compression methods
30+
/// from versions prior to 1.5.6.
2931
///
3032
/// Returns the original uncompressed [Uint8List].
3133
/// Throws [ArgumentError] if the input is empty.

lib/core/shrink.dart

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import 'package:shrink/utils/utils.dart';
55
/// A utility class for compressing different types of data.
66
///
77
/// This class provides static methods to compress various data types:
8-
/// - bytes: Compresses raw binary data using multiple compression algorithms and selects the best result (identity, ZLIB, or GZIP)
8+
/// - bytes: Compresses raw binary data using identity or ZLIB compression and selects the best result
99
/// - json: Compresses JSON objects efficiently
1010
/// - text: Compresses strings using UTF-8 encoding and zlib
1111
/// - unique: Compresses lists of unique integers using specialized algorithms
@@ -19,12 +19,11 @@ import 'package:shrink/utils/utils.dart';
1919
/// final jsonCompressed = Shrink.json({'name': 'John', 'age': 30});
2020
/// ```
2121
abstract class Shrink {
22-
/// Compresses a [Uint8List] using multiple compression algorithms and selects the best result.
22+
/// Compresses a [Uint8List] using zlib compression or no compression (identity).
2323
///
24-
/// This function tries different compression methods and levels to find the optimal compression:
24+
/// This function tries different compression levels to find the optimal compression:
2525
/// - No compression (identity) - used when compression would increase size
26-
/// - ZLIB compression with levels 1-9
27-
/// - GZIP compression with levels 1-9
26+
/// - ZLIB compression with levels 4-9
2827
///
2928
/// The first byte of the returned [Uint8List] indicates the compression method used,
3029
/// followed by the compressed data.

lib/extensions/shrink_extensions_bytes.dart

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,9 @@ import 'package:shrink/utils/utils.dart' as utils;
88
/// These extension methods make it more convenient to work with compressed data
99
/// by allowing method chaining and providing a more fluent API.
1010
extension ShrinkExtensionsBytes on Uint8List {
11-
/// Compresses this [Uint8List] using multiple compression algorithms and selects the best result.
11+
/// Compresses bytes using zlib compression.
1212
///
13-
/// This method tries different compression methods and levels to find the optimal compression:
14-
/// - No compression (identity) - used when compression would increase size
15-
/// - ZLIB compression with levels 1-9
16-
/// - GZIP compression with levels 1-9
17-
///
18-
/// The first byte of the returned [Uint8List] indicates the compression method used,
19-
/// followed by the compressed data.
20-
///
21-
/// Returns a compressed [Uint8List] using the most efficient method for the input data.
22-
/// The compression is lossless - the original data can be fully restored.
13+
/// Returns compressed data that can be restored with [restoreBytes].
2314
Uint8List shrink() => utils.shrinkBytes(this);
2415

2516
/// Converts this [Uint8List] to a base64-encoded string.

lib/extensions/shrink_extensions_json.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ extension ShrinkExtensionsJson on Map<String, dynamic> {
1111
///
1212
/// This method first encodes the JSON object to a minified string,
1313
/// then compresses that string using UTF-8 encoding and zlib compression.
14-
/// For decompression, use [Uint8List.restoreJson].
14+
/// For decompression, use [Uint8List.restoreJson] or [Restore.json].
1515
///
1616
/// Returns a [Uint8List] containing the compressed JSON data.
1717
Uint8List shrink() => utils.shrinkJson(this);

lib/extensions/shrink_extensions_list_int.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ extension ShrinkExtensionsListInt on List<int> {
1414
/// the one that produces the smallest result for the given input. It works best
1515
/// when the list contains unique integers (no duplicates).
1616
///
17-
/// For decompression, use [Uint8List.restoreUnique].
17+
/// For decompression, use [Uint8List.restoreUnique]. or [Restore.unique].
1818
///
1919
/// Returns a [Uint8List] containing the compressed integer list.
2020
Uint8List shrink() => utils.shrinkUnique(this);
@@ -34,7 +34,7 @@ extension ShrinkExtensionsListInt on List<int> {
3434
/// - [UniqueCompressionMethod.chunked]: Good for lists with clustered values
3535
/// - [UniqueCompressionMethod.bitmask]: Good for dense sets of integers within a limited range
3636
///
37-
/// For decompression, use [Uint8List.restoreUnique].
37+
/// For decompression, use [Uint8List.restoreUnique]. or [Restore.unique].
3838
///
3939
/// Parameters:
4040
/// [method]: The specific compression method to use

lib/extensions/shrink_extensions_string.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ extension ShrinkExtensionsString on String {
1111
/// Compresses this string using UTF-8 encoding and zlib compression.
1212
///
1313
/// This method encodes the string as UTF-8, then applies zlib compression
14-
/// to reduce its size. For decompression, use [Uint8List.restoreText].
14+
/// to reduce its size. For decompression, use [Uint8List.restoreText] or [Restore.text].
1515
///
1616
/// Returns a [Uint8List] containing the compressed string data.
1717
Uint8List shrink() => utils.shrinkText(this);
1818

19-
/// Decodes this base64-encoded string to a [Uint8List].
19+
/// Decodes this base64-encoded string to bytes [Uint8List].
2020
///
2121
/// This method is the inverse of [Uint8List.toBase64].
2222
///

0 commit comments

Comments
 (0)