#![allow(clippy::unwrap_used, clippy::expect_used)]
use chronix::chronix_core::config::FloatEncoding;
use chronix::chronix_encoding::{
AdaptiveSelector, AlpDecoder, AlpEncoder, BitmapDecoder, BitmapEncoder, ChimpDecoder,
ChimpEncoder, ColumnDecoder, ColumnEncoder, DecodedColumn, DeltaOfDeltaDecoder,
DeltaOfDeltaEncoder, DictionaryDecoder, DictionaryEncoder, GorillaDecoder, GorillaEncoder,
IntegerDecoder, IntegerEncoder,
};
fn main() {
println!("=== Chronix Column Encoding ===\n");
println!("--- Timestamp Encoding ---");
let regular: Vec<i64> = (0..1000)
.map(|i| 1_700_000_000_000_000_000i64 + i * 1_000_000_000)
.collect();
let jittered: Vec<i64> = (0..1000)
.map(|i| 1_700_000_000_000_000_000i64 + i * 1_000_000_000 + (i * 137 % 500) * 1_000_000)
.collect();
let raw_size = regular.len() * 8;
println!(" {:<22} {:>10} {:>10}", "shape", "DoD", "pco");
for (label, series) in [("regular 1 s", ®ular), ("1 s ± 250 ms", &jittered)] {
let dod = DeltaOfDeltaEncoder::encode(series).expect("DoD encode failed");
assert_eq!(
&DeltaOfDeltaDecoder::decode(&dod).expect("DoD decode failed"),
series,
"delta-of-delta round-trip failed"
);
let block = ColumnEncoder::encode_timestamps(series).expect("timestamp encode failed");
match ColumnDecoder::decode(&block).expect("timestamp decode failed") {
DecodedColumn::I64(back) => assert_eq!(&back, series, "timestamp round-trip failed"),
other => unreachable!("timestamps decoded to {other:?}"),
}
println!(
" {:<22} {:>9.1}x {:>9.1}x (chose {})",
label,
raw_size as f64 / dod.len() as f64,
raw_size as f64 / (block.payload.len() + 1) as f64,
block.encoding,
);
}
println!(" ✓ Round-trips verified for both codecs and both shapes");
println!("\n--- Float Encoding ---");
let slow_data: Vec<f64> = (0..1000)
.map(|i| 50.0 + (i as f64 * 0.01).sin() * 2.0)
.collect();
let raw_f64_size = slow_data.len() * 8;
let gorilla_enc = GorillaEncoder::encode(&slow_data).expect("Gorilla encode failed");
let chimp_enc = ChimpEncoder::encode(&slow_data).expect("Chimp encode failed");
println!(
"Slowly varying data ({} values, {} raw bytes):",
slow_data.len(),
raw_f64_size
);
println!(
" Gorilla: {} bytes ({:.1}x)",
gorilla_enc.len(),
raw_f64_size as f64 / gorilla_enc.len() as f64
);
println!(
" Chimp: {} bytes ({:.1}x)",
chimp_enc.len(),
raw_f64_size as f64 / chimp_enc.len() as f64
);
let gorilla_dec = GorillaDecoder::decode(&gorilla_enc).expect("Gorilla decode failed");
let chimp_dec = ChimpDecoder::decode(&chimp_enc).expect("Chimp decode failed");
assert_eq!(slow_data, gorilla_dec, "Gorilla round-trip failed");
assert_eq!(slow_data, chimp_dec, "Chimp round-trip failed");
println!(" ✓ Both round-trips verified");
let random_data: Vec<f64> = (0..1000)
.map(|i| ((i * 7919 + 104729) % 100000) as f64 / 1000.0)
.collect();
let gorilla_rand = GorillaEncoder::encode(&random_data).expect("Gorilla encode random failed");
let chimp_rand = ChimpEncoder::encode(&random_data).expect("Chimp encode random failed");
println!("\nRandom data ({} values):", random_data.len());
println!(
" Gorilla: {} bytes ({:.1}x)",
gorilla_rand.len(),
raw_f64_size as f64 / gorilla_rand.len() as f64
);
println!(
" Chimp: {} bytes ({:.1}x)",
chimp_rand.len(),
raw_f64_size as f64 / chimp_rand.len() as f64
);
println!("\n--- ALP (decimal metric data) ---");
let meter_data: Vec<f64> = (0..1000)
.map(|i| {
let raw = 200.0 + ((i * 37) % 5000) as f64 / 100.0;
(raw * 100.0).round() / 100.0
})
.collect();
let alp_enc = AlpEncoder::encode(&meter_data).expect("ALP encode failed");
let gorilla_meter = GorillaEncoder::encode(&meter_data).expect("Gorilla encode failed");
let chimp_meter = ChimpEncoder::encode(&meter_data).expect("Chimp encode failed");
println!(
"Power meter, 2 dp ({} values, {} raw bytes):",
meter_data.len(),
raw_f64_size
);
println!(
" ALP: {} bytes ({:.1}x)",
alp_enc.len(),
raw_f64_size as f64 / alp_enc.len() as f64
);
println!(
" Gorilla: {} bytes ({:.1}x)",
gorilla_meter.len(),
raw_f64_size as f64 / gorilla_meter.len() as f64
);
println!(
" Chimp: {} bytes ({:.1}x)",
chimp_meter.len(),
raw_f64_size as f64 / chimp_meter.len() as f64
);
let alp_dec = AlpDecoder::decode(&alp_enc).expect("ALP decode failed");
assert_eq!(meter_data, alp_dec, "ALP round-trip failed");
println!(" ✓ ALP round-trip verified (bit-exact)");
println!("\n--- Integer Encoding ---");
let int_data: Vec<i64> = (0..1000).map(|i| 42_000 + i * 3).collect();
let raw_int_size = int_data.len() * 8;
let int_encoded = IntegerEncoder::encode_i64(&int_data).expect("Integer encode failed");
println!(
" i64 data: {} bytes → {} bytes ({:.1}x)",
raw_int_size,
int_encoded.len(),
raw_int_size as f64 / int_encoded.len() as f64
);
let int_decoded = IntegerDecoder::decode_i64(&int_encoded).expect("Integer decode failed");
assert_eq!(int_data, int_decoded, "Integer round-trip failed");
println!(" ✓ Round-trip verified");
let u64_data: Vec<u64> = (0..1000).map(|i| 1_000_000 + i * 7).collect();
let u64_encoded = IntegerEncoder::encode_u64(&u64_data).expect("u64 encode failed");
println!(
" u64 data: {} bytes → {} bytes ({:.1}x)",
u64_data.len() * 8,
u64_encoded.len(),
(u64_data.len() * 8) as f64 / u64_encoded.len() as f64
);
println!("\n--- Dictionary Encoding (Strings) ---");
let tags: Vec<&str> = (0..1000)
.map(|i| match i % 5 {
0 => "us-east-1",
1 => "us-west-2",
2 => "eu-west-1",
3 => "ap-southeast-1",
_ => "eu-central-1",
})
.collect();
let raw_str_size: usize = tags.iter().map(|s| s.len() + 8).sum(); let dict_encoded = DictionaryEncoder::encode(&tags).expect("Dictionary encode failed");
println!(
" {} strings (5 unique): ~{} bytes → {} bytes ({:.1}x)",
tags.len(),
raw_str_size,
dict_encoded.len(),
raw_str_size as f64 / dict_encoded.len() as f64
);
let dict_decoded = DictionaryDecoder::decode(&dict_encoded).expect("Dictionary decode failed");
let tags_owned: Vec<String> = tags.iter().map(std::string::ToString::to_string).collect();
assert_eq!(tags_owned, dict_decoded, "Dictionary round-trip failed");
println!(" ✓ Round-trip verified");
println!("\n--- Bitmap Encoding (Booleans) ---");
let bools: Vec<bool> = (0..1000).map(|i| i % 3 == 0).collect();
let raw_bool_size = bools.len();
let bitmap_encoded = BitmapEncoder::encode(&bools).expect("Bitmap encode failed");
println!(
" {} bools: {} bytes → {} bytes ({:.1}x)",
bools.len(),
raw_bool_size,
bitmap_encoded.len(),
raw_bool_size as f64 / bitmap_encoded.len() as f64
);
let bitmap_decoded = BitmapDecoder::decode(&bitmap_encoded).expect("Bitmap decode failed");
assert_eq!(bools, bitmap_decoded, "Bitmap round-trip failed");
println!(" ✓ Round-trip verified");
println!("\n--- Unified ColumnEncoder ---");
let ts_block = ColumnEncoder::encode_timestamps(®ular).expect("encode_timestamps failed");
println!(
" Timestamps: encoding={:?}, {} bytes",
ts_block.encoding,
ts_block.payload.len()
);
let mut f64_block = None;
for hint in [FloatEncoding::Gorilla, FloatEncoding::Chimp] {
let block = ColumnEncoder::encode_f64(&slow_data, hint).expect("encode_f64 failed");
println!(
" Floats (hint {hint:?}): chose {:?}, {} bytes",
block.encoding,
block.payload.len()
);
f64_block = Some(block);
}
let f64_block = f64_block.expect("at least one encoding was tried");
let str_block = ColumnEncoder::encode_string(&tags).expect("encode_string failed");
println!(
" Strings: encoding={:?}, {} bytes",
str_block.encoding,
str_block.payload.len()
);
let bool_block = ColumnEncoder::encode_bool(&bools).expect("encode_bool failed");
println!(
" Bools: encoding={:?}, {} bytes",
bool_block.encoding,
bool_block.payload.len()
);
match ColumnDecoder::decode(&ts_block).expect("decode timestamps failed") {
DecodedColumn::I64(vals) => println!(" Decoded timestamps: {} i64 values", vals.len()),
other => println!(
" Unexpected decode type: {:?}",
std::mem::discriminant(&other)
),
}
match ColumnDecoder::decode(&f64_block).expect("decode floats failed") {
DecodedColumn::F64(vals) => println!(" Decoded floats: {} f64 values", vals.len()),
other => println!(
" Unexpected decode type: {:?}",
std::mem::discriminant(&other)
),
}
println!("\n--- Adaptive Encoding Selection ---");
let selector = AdaptiveSelector::new();
let pattern_slow = selector.analyze_floats(&slow_data);
println!(" Slowly varying data → {:?}", pattern_slow);
let pattern_random = selector.analyze_floats(&random_data);
println!(" Random data → {:?}", pattern_random);
let constant_data: Vec<f64> = vec![42.0; 1000];
let pattern_const = selector.analyze_floats(&constant_data);
println!(" Constant data → {:?}", pattern_const);
println!("\n✓ Encoding showcase complete");
}