Crate compress_json_rs

Crate compress_json_rs 

Source
Expand description

§compress-json-rs

Crates.io Documentation License

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

FeatureDescription
Full JSON SupportObjects, arrays, strings, numbers, booleans, and null
Value DeduplicationRepeated values stored once with reference keys
Schema DeduplicationObjects with identical keys share schemas
Compact KeysBase-62 encoding for minimal key size
UTF-8 SafeFull Unicode support for all string values
Zero DependenciesOnly 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

FunctionDescription
compressCompress a JSON value into Compressed format
decompressRestore original JSON from Compressed format
decodeDecode a single key from the values array

§Types

TypeDescription
CompressedTuple type (Vec<String>, String) for compressed data
KeyString type alias for base-62 encoded references
CONFIGGlobal configuration constants

§Helper Functions

FunctionDescription
trim_undefinedRemove null values from object (shallow)
trim_undefined_recursivelyRemove null values from nested objects

§Low-Level API

FunctionDescription
make_memoryCreate a new compression memory store
add_valueAdd a value to memory, get its key
mem_to_valuesExtract 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:

PrefixTypeExample EncodedOriginal Value
b|TBooleanb|Ttrue
b|FBooleanb|Ffalse
n|Numbern|42.542.5
N|+InfinityN|+Infinity
N|--InfinityN|--Infinity
N|0NaNN|0NaN
s|Escaped strings|n|foo"n|foo"
a|Arraya|0|1|2[val0, val1, val2]
o|Objecto|0|1|2{schema0: val1, ...}
(none)Stringhello"hello"
"" / _Nullnull

§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 TypeTypical Ratio
Arrays of similar objects30-50% of original
Highly repetitive data20-40% of original
Mixed data50-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 OptionDefaultEffect
preserve_nanfalseWhen true, NaN encoded as N|0
preserve_infinitefalseWhen true, ±Infinity encoded as N|+/N|-
error_on_nanfalseWhen true (and preserve=false), panic on NaN
error_on_infinitefalseWhen true (and preserve=false), panic on Infinity

By default (preserve options = false), special values become null like JSON.stringify.

When preserved, the encoding is:

  • InfinityN|+
  • -InfinityN|-
  • NaNN|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.