Expand description
§compress-json-rs
A space-efficient JSON compression library with lossless round-trip compression and decompression.
This crate compresses JSON data by deduplicating values and keys, storing them in a compact format with base-62 encoded references. It’s particularly effective for JSON with repetitive structures like API responses, configuration files, and data collections.
§Features
| Feature | Description |
|---|---|
| Full JSON Support | Objects, arrays, strings, numbers, booleans, and null |
| Value Deduplication | Repeated values stored once with reference keys |
| Schema Deduplication | Objects with identical keys share schemas |
| Compact Keys | Base-62 encoding for minimal key size |
| UTF-8 Safe | Full Unicode support for all string values |
| Zero Dependencies | Only requires serde_json |
§Quick Start
Add to your Cargo.toml:
[dependencies]
compress-json-rs = "0.1"
serde_json = "1.0"Basic usage:
use compress_json_rs::{compress, decompress};
use serde_json::json;
// Original JSON data
let data = json!({
"user": "Alice",
"active": true,
"roles": ["admin", "user"]
});
// Compress into (values, root_key)
let compressed = compress(&data);
// Decompress back to original
let restored = decompress(compressed);
assert_eq!(data, restored);§API Overview
§Core Functions
| Function | Description |
|---|---|
compress | Compress a JSON value into Compressed format |
decompress | Restore original JSON from Compressed format |
decode | Decode a single key from the values array |
§Types
| Type | Description |
|---|---|
Compressed | Tuple type (Vec<String>, String) for compressed data |
Key | String type alias for base-62 encoded references |
CONFIG | Global configuration constants |
§Helper Functions
| Function | Description |
|---|---|
trim_undefined | Remove null values from object (shallow) |
trim_undefined_recursively | Remove null values from nested objects |
§Low-Level API
| Function | Description |
|---|---|
make_memory | Create a new compression memory store |
add_value | Add a value to memory, get its key |
mem_to_values | Extract values array from memory |
§Compression Format
The Compressed type is a tuple (Vec<String>, String):
- First element: Deduplicated value store
- Second element: Base-62 key pointing to root value
§Value Encoding
Values are encoded with type prefixes:
| Prefix | Type | Example Encoded | Original Value |
|---|---|---|---|
b|T | Boolean | b|T | true |
b|F | Boolean | b|F | false |
n| | Number | n|42.5 | 42.5 |
N|+ | Infinity | N|+ | Infinity |
N|- | -Infinity | N|- | -Infinity |
N|0 | NaN | N|0 | NaN |
s| | Escaped string | s|n|foo | "n|foo" |
a| | Array | a|0|1|2 | [val0, val1, val2] |
o| | Object | o|0|1|2 | {schema0: val1, ...} |
| (none) | String | hello | "hello" |
"" / _ | Null | null |
§Base-62 Keys
Keys use characters 0-9, A-Z, a-z for compact representation:
Index: 0 1 2 ... 9 10 11 ... 35 36 37 ... 61 62 63
Key: "0" "1" "2" "9" "A" "B" "Z" "a" "b" "z" "10" "11"§Examples
§Serialize for Storage
use compress_json_rs::{compress, decompress, Compressed};
use serde_json::json;
let data = json!({"items": [1, 2, 3]});
// Compress and serialize to JSON string
let compressed = compress(&data);
let json_str = serde_json::to_string(&compressed).unwrap();
// Store json_str to file/database/network...
// Later: deserialize and decompress
let loaded: Compressed = serde_json::from_str(&json_str).unwrap();
let restored = decompress(loaded);
assert_eq!(data, restored);§Arrays of Similar Objects
Compression is most effective for repetitive data:
use compress_json_rs::{compress, decompress};
use serde_json::json;
// Data with repeated schema and values
let users = json!([
{ "id": 1, "name": "Alice", "role": "user" },
{ "id": 2, "name": "Bob", "role": "user" },
{ "id": 3, "name": "Charlie", "role": "admin" },
]);
let (values, root) = compress(&users);
// Schema ["id", "name", "role"] stored once
// Value "user" stored once, referenced twice
println!("Compressed to {} unique values", values.len());
let restored = decompress((values, root));
assert_eq!(users, restored);§Clean Data Before Compression
use compress_json_rs::{compress, trim_undefined_recursively};
use serde_json::{json, Map, Value};
let mut data: Map<String, Value> = serde_json::from_value(json!({
"name": "Alice",
"middleName": null, // Will be removed
"profile": {
"bio": "Developer",
"website": null // Will be removed
}
})).unwrap();
// Remove all null values recursively
trim_undefined_recursively(&mut data);
// Now compress the cleaned data
let compressed = compress(&Value::Object(data));§Low-Level API Usage
For custom compression workflows:
use compress_json_rs::{make_memory, add_value, mem_to_values, decode};
use serde_json::json;
let mut mem = make_memory();
// Add values - duplicates return same key
let key1 = add_value(&mut mem, &json!("repeated"));
let key2 = add_value(&mut mem, &json!("repeated"));
assert_eq!(key1, key2); // Same key!
// Add more values
let key3 = add_value(&mut mem, &json!(42));
let key4 = add_value(&mut mem, &json!({"nested": "object"}));
// Extract final values
let values = mem_to_values(&mem);
// Decode any key
assert_eq!(decode(&values, &key1), json!("repeated"));
assert_eq!(decode(&values, &key3), json!(42));§Performance
§Best Use Cases
- API responses with arrays of similar objects
- Configuration files with repeated values
- Data exports with consistent schemas
- Cache storage where size matters
§Compression Ratios
| Data Type | Typical Ratio |
|---|---|
| Arrays of similar objects | 30-50% of original |
| Highly repetitive data | 20-40% of original |
| Mixed data | 50-70% of original |
| Unique values only | ~100% (no benefit) |
§Special Values (v3.4.0+)
This crate supports special floating-point values for cross-platform compatibility. Handling depends on configuration options:
| Config Option | Default | Effect |
|---|---|---|
preserve_nan | false | When true, NaN encoded as N|0 |
preserve_infinite | false | When true, ±Infinity encoded as N|+/N|- |
error_on_nan | false | When true (and preserve=false), panic on NaN |
error_on_infinite | false | When true (and preserve=false), panic on Infinity |
By default (preserve options = false), special values become null like JSON.stringify.
When preserved, the encoding is:
Infinity→N|+-Infinity→N|-NaN→N|0
Note: JSON doesn’t natively support these values, so they become null when
decompressed to serde_json::Value. The compressed representation preserves
them for compatibility with JavaScript and Python implementations that have
preserve_* enabled.
§Compatibility
This crate is a Rust port of the JavaScript compress-json library (v3.4.0+). Compressed data is compatible between implementations, allowing cross-platform data exchange.
§License
Licensed under BSD-2-Clause. See LICENSE.
Structs§
- Config
- Global configuration for compression behavior.
- Memory
- In-memory structure holding store and caches for compression.
Constants§
- CONFIG
- Default configuration matching the TypeScript implementation.
Functions§
- add_
value - Recursively add a JSON value to memory, returning its key.
- compress
- Compress a JSON value into its compressed representation.
- decode
- Decode a single key into a JSON Value.
- decode_
num - Decode a compressed number string to f64.
- decode_
special - Decode a special value string to f64.
- decompress
- Decompress a compressed representation back into JSON.
- encode_
num - Encode a regular number to compressed string with ‘n|’ prefix.
- is_
special_ value - Check if an encoded string represents a special value (Infinity/NaN).
- make_
memory - Create a new in-memory Memory instance.
- mem_
to_ values - Convert internal store to values array.
- trim_
undefined - Remove keys with null values from a JSON object (shallow).
- trim_
undefined_ recursively - Recursively remove keys with null values in nested JSON objects.
Type Aliases§
- Compressed
- Compressed representation: (values array, root key).
- Key
- Key type for compressed references.