1use chronix_core::config::FloatEncoding;
18
19use crate::alp::AlpDecoder;
20use crate::bitmap::{BitmapDecoder, BitmapEncoder};
21use crate::chimp::{Chimp128Decoder, ChimpDecoder};
22use crate::delta::{DeltaOfDeltaDecoder, DeltaOfDeltaEncoder};
23use crate::dictionary::{DictionaryDecoder, DictionaryEncoder};
24use crate::error::{EncodingError, Result};
25use crate::for_encoding::{ForDecoder, ForEncoder};
26use crate::gorilla::{GorillaDecoder, GorillaEncoder};
27use crate::integer::{IntegerDecoder, IntegerEncoder, VarintDecoder, VarintEncoder};
28use crate::patas::PatasDecoder;
29use crate::plain::{PlainDecoder, PlainEncoder};
30use crate::rle::{RleDecoder, RleEncoder};
31
32macro_rules! encoding_types {
48 ($(
49 $(#[$meta:meta])*
50 $variant:ident = $tag:literal, $name:literal;
51 )+) => {
52 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
54 #[repr(u8)]
55 pub enum EncodingType {
56 $(
57 $(#[$meta])*
58 $variant = $tag,
59 )+
60 }
61
62 impl EncodingType {
63 pub const ALL: &'static [Self] = &[$(Self::$variant),+];
69
70 pub fn from_tag(tag: u8) -> Result<Self> {
76 match tag {
77 $($tag => Ok(Self::$variant),)+
78 other => Err(EncodingError::UnsupportedEncoding { tag: other }),
79 }
80 }
81
82 #[must_use]
84 pub fn tag(self) -> u8 {
85 self as u8
86 }
87 }
88
89 impl std::fmt::Display for EncodingType {
90 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91 f.write_str(match self {
92 $(Self::$variant => $name,)+
93 })
94 }
95 }
96 };
97}
98
99encoding_types! {
100 DeltaOfDelta = 0, "delta-of-delta";
105 Chimp = 1, "chimp";
107 Gorilla = 2, "gorilla";
109 IntegerI64 = 3, "integer-i64";
111 IntegerU64 = 4, "integer-u64";
113 Dictionary = 5, "dictionary";
115 Bitmap = 6, "bitmap";
117 PlainF64 = 7, "plain-f64";
119 PlainI64 = 8, "plain-i64";
121 PlainU64 = 9, "plain-u64";
123 PlainBool = 10, "plain-bool";
125 PlainString = 11, "plain-string";
127 Nullable = 12, "nullable";
136 Rle = 13, "rle";
138 VarintI64 = 14, "varint-i64";
144 VarintU64 = 15, "varint-u64";
146 Chimp128 = 16, "chimp128";
148 ForI64 = 17, "for-i64";
150 ForU64 = 18, "for-u64";
152 Patas = 19, "patas";
154 Alp = 20, "alp";
160 Pco = 21, "pco";
163 PcoI64 = 22, "pco_i64";
165 PcoU64 = 23, "pco_u64";
167 DecimalI128 = 24, "decimal-i128";
173 Bytes = 25, "bytes";
182}
183
184#[derive(Debug, Clone)]
192pub struct EncodedBlock {
193 pub encoding: EncodingType,
195 pub payload: Vec<u8>,
197}
198
199impl EncodedBlock {
200 #[must_use]
202 pub fn to_bytes(&self) -> Vec<u8> {
203 let mut out = Vec::with_capacity(1 + self.payload.len());
204 out.push(self.encoding.tag());
205 out.extend_from_slice(&self.payload);
206 out
207 }
208
209 pub fn from_bytes(data: &[u8]) -> Result<Self> {
215 if data.is_empty() {
216 return Err(EncodingError::CorruptData {
217 detail: "empty encoded block".to_string(),
218 });
219 }
220 let encoding = EncodingType::from_tag(data[0])?;
221 let payload = data[1..].to_vec();
222 Ok(Self { encoding, payload })
223 }
224}
225
226const MIN_COMPRESSION_RATIO: f64 = 1.5;
233
234#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
247pub enum TimestampEncoding {
248 #[default]
250 Auto,
251 Pco,
253 DeltaOfDelta,
255 Plain,
257}
258
259#[derive(Debug, Clone, Copy)]
275pub struct ColumnEncoder;
276
277impl ColumnEncoder {
278 pub fn encode_timestamps(values: &[i64]) -> Result<EncodedBlock> {
288 Self::encode_timestamps_with(values, TimestampEncoding::Auto)
289 }
290
291 pub fn encode_timestamps_with(
326 values: &[i64],
327 strategy: TimestampEncoding,
328 ) -> Result<EncodedBlock> {
329 let raw_size = values.len() * 8;
330
331 let (encoding, payload) = match strategy {
332 TimestampEncoding::Plain => {
333 return Ok(EncodedBlock {
334 encoding: EncodingType::PlainI64,
335 payload: PlainEncoder::encode_i64(values)?,
336 });
337 }
338 TimestampEncoding::DeltaOfDelta => (
339 EncodingType::DeltaOfDelta,
340 DeltaOfDeltaEncoder::encode(values)?,
341 ),
342 TimestampEncoding::Pco => (
343 EncodingType::PcoI64,
344 crate::pco::PcoEncoder::encode_timestamps(values)?,
345 ),
346 TimestampEncoding::Auto => {
347 let pco = crate::pco::PcoEncoder::encode_timestamps(values)?;
348 let dod = DeltaOfDeltaEncoder::encode(values)?;
349 if dod.len() < pco.len() {
352 (EncodingType::DeltaOfDelta, dod)
353 } else {
354 (EncodingType::PcoI64, pco)
355 }
356 }
357 };
358
359 if should_use_specialized(&payload, raw_size) {
360 Ok(EncodedBlock { encoding, payload })
361 } else {
362 Ok(EncodedBlock {
363 encoding: EncodingType::PlainI64,
364 payload: PlainEncoder::encode_i64(values)?,
365 })
366 }
367 }
368
369 pub fn encode_f64(values: &[f64], strategy: FloatEncoding) -> Result<EncodedBlock> {
379 match strategy {
380 FloatEncoding::Chimp => {
381 let selector = crate::adaptive::AdaptiveSelector::new();
385 selector.encode_f64_adaptive(values)
386 }
387 FloatEncoding::Gorilla => {
388 let raw_size = values.len() * 8;
389 let gorilla_payload = GorillaEncoder::encode(values)?;
390 if should_use_specialized(&gorilla_payload, raw_size) {
391 return Ok(EncodedBlock {
392 encoding: EncodingType::Gorilla,
393 payload: gorilla_payload,
394 });
395 }
396 Ok(EncodedBlock {
397 encoding: EncodingType::PlainF64,
398 payload: PlainEncoder::encode_f64(values)?,
399 })
400 }
401 FloatEncoding::Plain => Ok(EncodedBlock {
402 encoding: EncodingType::PlainF64,
403 payload: PlainEncoder::encode_f64(values)?,
404 }),
405 }
406 }
407
408 pub fn encode_i64(values: &[i64]) -> Result<EncodedBlock> {
418 let selector = crate::adaptive::AdaptiveSelector::new();
419 let pattern = selector.analyze_integers(values);
420
421 if pattern == crate::adaptive::IntegerPattern::Constant {
423 let raw_size = values.len() * 8;
424 let rle_payload = RleEncoder::encode_i64(values)?;
425 if should_use_specialized(&rle_payload, raw_size) {
426 return Ok(EncodedBlock {
427 encoding: EncodingType::Rle,
428 payload: rle_payload,
429 });
430 }
431 }
432
433 let raw_size = values.len() * 8;
434
435 let fixed_payload = IntegerEncoder::encode_i64(values)?;
437 let varint_payload = VarintEncoder::encode_i64(values)?;
438 let for_payload = ForEncoder::encode_i64(values)?;
439 let pco_payload = crate::pco::PcoEncoder::encode_i64(values)?;
440
441 let mut best_enc = EncodingType::IntegerI64;
442 let mut best_payload = fixed_payload;
443
444 if varint_payload.len() < best_payload.len() {
445 best_enc = EncodingType::VarintI64;
446 best_payload = varint_payload;
447 }
448 if for_payload.len() < best_payload.len() {
449 best_enc = EncodingType::ForI64;
450 best_payload = for_payload;
451 }
452 if pco_payload.len() < best_payload.len() {
453 best_enc = EncodingType::PcoI64;
454 best_payload = pco_payload;
455 }
456
457 if should_use_specialized(&best_payload, raw_size) {
458 Ok(EncodedBlock {
459 encoding: best_enc,
460 payload: best_payload,
461 })
462 } else {
463 Ok(EncodedBlock {
464 encoding: EncodingType::PlainI64,
465 payload: PlainEncoder::encode_i64(values)?,
466 })
467 }
468 }
469
470 pub fn encode_u64(values: &[u64]) -> Result<EncodedBlock> {
480 let as_i64: Vec<i64> = values.iter().map(|&v| v as i64).collect();
482 let selector = crate::adaptive::AdaptiveSelector::new();
483 if selector.analyze_integers(&as_i64) == crate::adaptive::IntegerPattern::Constant {
484 let raw_size = values.len() * 8;
485 let rle_payload = RleEncoder::encode_u64(values)?;
486 if should_use_specialized(&rle_payload, raw_size) {
487 return Ok(EncodedBlock {
488 encoding: EncodingType::Rle,
489 payload: rle_payload,
490 });
491 }
492 }
493
494 let raw_size = values.len() * 8;
495 let fixed_payload = IntegerEncoder::encode_u64(values)?;
496 let varint_payload = VarintEncoder::encode_u64(values)?;
497 let for_payload = ForEncoder::encode_u64(values)?;
498 let pco_payload = crate::pco::PcoEncoder::encode_u64(values)?;
499
500 let mut best_enc = EncodingType::IntegerU64;
502 let mut best_payload = fixed_payload;
503
504 if varint_payload.len() < best_payload.len() {
505 best_enc = EncodingType::VarintU64;
506 best_payload = varint_payload;
507 }
508 if for_payload.len() < best_payload.len() {
509 best_enc = EncodingType::ForU64;
510 best_payload = for_payload;
511 }
512 if pco_payload.len() < best_payload.len() {
513 best_enc = EncodingType::PcoU64;
514 best_payload = pco_payload;
515 }
516
517 if should_use_specialized(&best_payload, raw_size) {
518 Ok(EncodedBlock {
519 encoding: best_enc,
520 payload: best_payload,
521 })
522 } else {
523 Ok(EncodedBlock {
524 encoding: EncodingType::PlainU64,
525 payload: PlainEncoder::encode_u64(values)?,
526 })
527 }
528 }
529
530 pub fn encode_string(values: &[&str]) -> Result<EncodedBlock> {
539 let raw_size: usize = values.iter().map(|s| 4 + s.len()).sum();
540
541 match DictionaryEncoder::encode(values) {
542 Ok(payload) if should_use_specialized(&payload, raw_size) => Ok(EncodedBlock {
543 encoding: EncodingType::Dictionary,
544 payload,
545 }),
546 Ok(_) | Err(EncodingError::DictionaryOverflow { .. }) => Ok(EncodedBlock {
548 encoding: EncodingType::PlainString,
549 payload: PlainEncoder::encode_string(values)?,
550 }),
551 Err(e) => Err(e),
553 }
554 }
555
556 pub fn encode_bool(values: &[bool]) -> Result<EncodedBlock> {
564 if !values.is_empty() {
566 let first = values[0];
567 if values.iter().all(|&v| v == first) {
568 let raw_size = values.len(); let rle_payload = RleEncoder::encode_bool(values)?;
570 if should_use_specialized(&rle_payload, raw_size) {
571 return Ok(EncodedBlock {
572 encoding: EncodingType::Rle,
573 payload: rle_payload,
574 });
575 }
576 }
577 }
578 Ok(EncodedBlock {
579 encoding: EncodingType::Bitmap,
580 payload: BitmapEncoder::encode(values)?,
581 })
582 }
583
584 pub fn encode_decimal(values: &[i128]) -> Result<EncodedBlock> {
597 Ok(EncodedBlock {
598 encoding: EncodingType::DecimalI128,
599 payload: crate::decimal::DecimalEncoder::encode(values)?,
600 })
601 }
602
603 pub fn encode_f64_nullable(
615 values: &[Option<f64>],
616 strategy: FloatEncoding,
617 ) -> Result<EncodedBlock> {
618 if values.is_empty() {
619 return Err(EncodingError::EmptyInput {
620 context: "nullable f64 encoder",
621 });
622 }
623 let (non_null, validity) = extract_non_null_f64(values);
624 if non_null.is_empty() {
625 return Ok(wrap_nullable(
627 EncodingType::PlainF64,
628 values.len(),
629 &validity,
630 &[],
631 ));
632 }
633 let inner = Self::encode_f64(&non_null, strategy)?;
634 Ok(wrap_nullable(
635 inner.encoding,
636 values.len(),
637 &validity,
638 &inner.payload,
639 ))
640 }
641
642 pub fn encode_i64_nullable(values: &[Option<i64>]) -> Result<EncodedBlock> {
648 if values.is_empty() {
649 return Err(EncodingError::EmptyInput {
650 context: "nullable i64 encoder",
651 });
652 }
653 let (non_null, validity) = extract_non_null_i64(values);
654 if non_null.is_empty() {
655 return Ok(wrap_nullable(
656 EncodingType::PlainI64,
657 values.len(),
658 &validity,
659 &[],
660 ));
661 }
662 let inner = Self::encode_i64(&non_null)?;
663 Ok(wrap_nullable(
664 inner.encoding,
665 values.len(),
666 &validity,
667 &inner.payload,
668 ))
669 }
670
671 pub fn encode_u64_nullable(values: &[Option<u64>]) -> Result<EncodedBlock> {
677 if values.is_empty() {
678 return Err(EncodingError::EmptyInput {
679 context: "nullable u64 encoder",
680 });
681 }
682 let (non_null, validity) = extract_non_null_u64(values);
683 if non_null.is_empty() {
684 return Ok(wrap_nullable(
685 EncodingType::PlainU64,
686 values.len(),
687 &validity,
688 &[],
689 ));
690 }
691 let inner = Self::encode_u64(&non_null)?;
692 Ok(wrap_nullable(
693 inner.encoding,
694 values.len(),
695 &validity,
696 &inner.payload,
697 ))
698 }
699
700 pub fn encode_string_nullable(values: &[Option<&str>]) -> Result<EncodedBlock> {
706 if values.is_empty() {
707 return Err(EncodingError::EmptyInput {
708 context: "nullable string encoder",
709 });
710 }
711 let (non_null, validity): (Vec<&str>, Vec<bool>) = values
712 .iter()
713 .map(|v| match v {
714 Some(s) => (*s, true),
715 None => ("", false),
716 })
717 .unzip();
718 let non_null_only: Vec<&str> = non_null
719 .into_iter()
720 .zip(validity.iter())
721 .filter(|(_, v)| **v)
722 .map(|(s, _)| s)
723 .collect();
724 if non_null_only.is_empty() {
725 return Ok(wrap_nullable(
726 EncodingType::PlainString,
727 values.len(),
728 &validity,
729 &[],
730 ));
731 }
732 let inner = Self::encode_string(&non_null_only)?;
733 Ok(wrap_nullable(
734 inner.encoding,
735 values.len(),
736 &validity,
737 &inner.payload,
738 ))
739 }
740
741 pub fn encode_decimal_nullable(values: &[Option<i128>]) -> Result<EncodedBlock> {
747 if values.is_empty() {
748 return Err(EncodingError::EmptyInput {
749 context: "nullable decimal encoder",
750 });
751 }
752 let validity: Vec<bool> = values.iter().map(std::option::Option::is_some).collect();
753 let non_null: Vec<i128> = values.iter().filter_map(|v| *v).collect();
754 if non_null.is_empty() {
755 return Ok(wrap_nullable(
756 EncodingType::DecimalI128,
757 values.len(),
758 &validity,
759 &[],
760 ));
761 }
762 let inner = Self::encode_decimal(&non_null)?;
763 Ok(wrap_nullable(
764 inner.encoding,
765 values.len(),
766 &validity,
767 &inner.payload,
768 ))
769 }
770
771 pub fn encode_bool_nullable(values: &[Option<bool>]) -> Result<EncodedBlock> {
777 if values.is_empty() {
778 return Err(EncodingError::EmptyInput {
779 context: "nullable bool encoder",
780 });
781 }
782 let validity: Vec<bool> = values.iter().map(std::option::Option::is_some).collect();
783 let non_null: Vec<bool> = values.iter().filter_map(|v| *v).collect();
784 if non_null.is_empty() {
785 return Ok(wrap_nullable(
786 EncodingType::Bitmap,
787 values.len(),
788 &validity,
789 &[],
790 ));
791 }
792 let inner = Self::encode_bool(&non_null)?;
793 Ok(wrap_nullable(
794 inner.encoding,
795 values.len(),
796 &validity,
797 &inner.payload,
798 ))
799 }
800}
801
802#[derive(Debug, Clone)]
814pub enum DecodedColumn {
815 I64(Vec<i64>),
817 U64(Vec<u64>),
819 F64(Vec<f64>),
821 Bool(Vec<bool>),
823 String(Vec<String>),
825 Decimal(Vec<i128>),
828 Bytes(Vec<Vec<u8>>),
830 NullableI64(Vec<Option<i64>>),
832 NullableU64(Vec<Option<u64>>),
834 NullableF64(Vec<Option<f64>>),
836 NullableBool(Vec<Option<bool>>),
838 NullableString(Vec<Option<String>>),
840 NullableDecimal(Vec<Option<i128>>),
842 NullableBytes(Vec<Option<Vec<u8>>>),
844}
845
846fn f64_slice_eq(a: &[f64], b: &[f64]) -> bool {
848 a.len() == b.len() && a.iter().zip(b).all(|(x, y)| x.to_bits() == y.to_bits())
849}
850
851fn opt_f64_slice_eq(a: &[Option<f64>], b: &[Option<f64>]) -> bool {
853 a.len() == b.len()
854 && a.iter().zip(b).all(|(x, y)| match (x, y) {
855 (Some(x), Some(y)) => x.to_bits() == y.to_bits(),
856 (None, None) => true,
857 _ => false,
858 })
859}
860
861impl PartialEq for DecodedColumn {
862 fn eq(&self, other: &Self) -> bool {
863 match (self, other) {
864 (Self::I64(a), Self::I64(b)) => a == b,
865 (Self::U64(a), Self::U64(b)) => a == b,
866 (Self::F64(a), Self::F64(b)) => f64_slice_eq(a, b),
867 (Self::Bool(a), Self::Bool(b)) => a == b,
868 (Self::String(a), Self::String(b)) => a == b,
869 (Self::NullableI64(a), Self::NullableI64(b)) => a == b,
870 (Self::NullableU64(a), Self::NullableU64(b)) => a == b,
871 (Self::NullableF64(a), Self::NullableF64(b)) => opt_f64_slice_eq(a, b),
872 (Self::NullableBool(a), Self::NullableBool(b)) => a == b,
873 (Self::NullableString(a), Self::NullableString(b)) => a == b,
874 (Self::Decimal(a), Self::Decimal(b)) => a == b,
875 (Self::NullableDecimal(a), Self::NullableDecimal(b)) => a == b,
876 _ => false,
877 }
878 }
879}
880
881impl DecodedColumn {
882 #[must_use]
884 pub fn len(&self) -> usize {
885 match self {
886 Self::I64(v) => v.len(),
887 Self::U64(v) => v.len(),
888 Self::F64(v) => v.len(),
889 Self::Bool(v) => v.len(),
890 Self::String(v) => v.len(),
891 Self::NullableI64(v) => v.len(),
892 Self::NullableU64(v) => v.len(),
893 Self::NullableF64(v) => v.len(),
894 Self::NullableBool(v) => v.len(),
895 Self::NullableString(v) => v.len(),
896 Self::Decimal(v) => v.len(),
897 Self::NullableDecimal(v) => v.len(),
898 Self::Bytes(v) => v.len(),
899 Self::NullableBytes(v) => v.len(),
900 }
901 }
902
903 #[must_use]
905 pub fn is_empty(&self) -> bool {
906 self.len() == 0
907 }
908}
909
910#[derive(Debug, Clone, Copy)]
918pub struct ColumnDecoder;
919
920impl ColumnDecoder {
921 pub fn decode(block: &EncodedBlock) -> Result<DecodedColumn> {
928 match block.encoding {
929 EncodingType::DeltaOfDelta => {
930 let values = DeltaOfDeltaDecoder::decode(&block.payload)?;
931 Ok(DecodedColumn::I64(values))
932 }
933 EncodingType::Chimp => {
934 let values = ChimpDecoder::decode(&block.payload)?;
935 Ok(DecodedColumn::F64(values))
936 }
937 EncodingType::Chimp128 => {
938 let values = Chimp128Decoder::decode(&block.payload)?;
939 Ok(DecodedColumn::F64(values))
940 }
941 EncodingType::Patas => {
942 let values = PatasDecoder::decode(&block.payload)?;
943 Ok(DecodedColumn::F64(values))
944 }
945 EncodingType::Alp => {
946 let values = AlpDecoder::decode(&block.payload)?;
947 Ok(DecodedColumn::F64(values))
948 }
949 EncodingType::Pco => {
950 let values = crate::pco::PcoDecoder::decode_f64(&block.payload)?;
951 Ok(DecodedColumn::F64(values))
952 }
953 EncodingType::PcoI64 => {
954 let values = crate::pco::PcoDecoder::decode_i64(&block.payload)?;
955 Ok(DecodedColumn::I64(values))
956 }
957 EncodingType::PcoU64 => {
958 let values = crate::pco::PcoDecoder::decode_u64(&block.payload)?;
959 Ok(DecodedColumn::U64(values))
960 }
961 EncodingType::Gorilla => {
962 let values = GorillaDecoder::decode(&block.payload)?;
963 Ok(DecodedColumn::F64(values))
964 }
965 EncodingType::IntegerI64 => {
966 let values = IntegerDecoder::decode_i64(&block.payload)?;
967 Ok(DecodedColumn::I64(values))
968 }
969 EncodingType::IntegerU64 => {
970 let values = IntegerDecoder::decode_u64(&block.payload)?;
971 Ok(DecodedColumn::U64(values))
972 }
973 EncodingType::Dictionary => {
974 let values = DictionaryDecoder::decode(&block.payload)?;
975 Ok(DecodedColumn::String(values))
976 }
977 EncodingType::Bitmap => {
978 let values = BitmapDecoder::decode(&block.payload)?;
979 Ok(DecodedColumn::Bool(values))
980 }
981 EncodingType::PlainF64 => {
982 let values = PlainDecoder::decode_f64(&block.payload)?;
983 Ok(DecodedColumn::F64(values))
984 }
985 EncodingType::PlainI64 => {
986 let values = PlainDecoder::decode_i64(&block.payload)?;
987 Ok(DecodedColumn::I64(values))
988 }
989 EncodingType::PlainU64 => {
990 let values = PlainDecoder::decode_u64(&block.payload)?;
991 Ok(DecodedColumn::U64(values))
992 }
993 EncodingType::PlainBool => {
994 let values = PlainDecoder::decode_bool(&block.payload)?;
995 Ok(DecodedColumn::Bool(values))
996 }
997 EncodingType::PlainString => {
998 let values = PlainDecoder::decode_string(&block.payload)?;
999 Ok(DecodedColumn::String(values))
1000 }
1001 EncodingType::Bytes => {
1002 let values = PlainDecoder::decode_bytes(&block.payload)?;
1003 Ok(DecodedColumn::Bytes(values))
1004 }
1005 EncodingType::Nullable => Self::decode_nullable(&block.payload),
1006 EncodingType::Rle => Self::decode_rle(&block.payload),
1007 EncodingType::VarintI64 => {
1008 let values = VarintDecoder::decode_i64(&block.payload)?;
1009 Ok(DecodedColumn::I64(values))
1010 }
1011 EncodingType::VarintU64 => {
1012 let values = VarintDecoder::decode_u64(&block.payload)?;
1013 Ok(DecodedColumn::U64(values))
1014 }
1015 EncodingType::ForI64 => {
1016 let values = ForDecoder::decode_i64(&block.payload)?;
1017 Ok(DecodedColumn::I64(values))
1018 }
1019 EncodingType::ForU64 => {
1020 let values = ForDecoder::decode_u64(&block.payload)?;
1021 Ok(DecodedColumn::U64(values))
1022 }
1023 EncodingType::DecimalI128 => {
1024 let values = crate::decimal::DecimalDecoder::decode(&block.payload)?;
1025 Ok(DecodedColumn::Decimal(values))
1026 }
1027 }
1028 }
1029
1030 fn decode_nullable(payload: &[u8]) -> Result<DecodedColumn> {
1038 if payload.len() < 5 {
1039 return Err(EncodingError::CorruptData {
1040 detail: "nullable payload too short".to_string(),
1041 });
1042 }
1043
1044 let inner_enc = EncodingType::from_tag(payload[0])?;
1045 let total_count = crate::coding::checked_decode_count(
1049 u32::from_le_bytes([payload[1], payload[2], payload[3], payload[4]]) as usize,
1050 "nullable",
1051 )?;
1052 let bitmap_bytes = total_count.div_ceil(8);
1053 let header_len = 5 + bitmap_bytes;
1054
1055 if payload.len() < header_len {
1056 return Err(EncodingError::CorruptData {
1057 detail: "nullable bitmap truncated".to_string(),
1058 });
1059 }
1060
1061 let bitmap = &payload[5..header_len];
1062 let inner_payload = &payload[header_len..];
1063
1064 let validity: Vec<bool> = (0..total_count)
1066 .map(|i| bitmap[i / 8] & (1 << (i % 8)) != 0)
1067 .collect();
1068
1069 let non_null_count = validity.iter().filter(|v| **v).count();
1070
1071 if non_null_count == 0 {
1073 return match inner_enc {
1074 EncodingType::PlainF64
1075 | EncodingType::Chimp
1076 | EncodingType::Chimp128
1077 | EncodingType::Gorilla
1078 | EncodingType::Patas
1079 | EncodingType::Alp
1080 | EncodingType::Pco => Ok(DecodedColumn::NullableF64(vec![None; total_count])),
1081 EncodingType::PlainI64
1082 | EncodingType::IntegerI64
1083 | EncodingType::VarintI64
1084 | EncodingType::ForI64
1085 | EncodingType::PcoI64
1086 | EncodingType::DeltaOfDelta => {
1087 Ok(DecodedColumn::NullableI64(vec![None; total_count]))
1088 }
1089 EncodingType::PlainU64
1090 | EncodingType::IntegerU64
1091 | EncodingType::VarintU64
1092 | EncodingType::ForU64
1093 | EncodingType::PcoU64 => Ok(DecodedColumn::NullableU64(vec![None; total_count])),
1094 EncodingType::PlainString | EncodingType::Dictionary => {
1095 Ok(DecodedColumn::NullableString(vec![None; total_count]))
1096 }
1097 EncodingType::Bitmap | EncodingType::PlainBool => {
1098 Ok(DecodedColumn::NullableBool(vec![None; total_count]))
1099 }
1100 EncodingType::DecimalI128 => {
1101 Ok(DecodedColumn::NullableDecimal(vec![None; total_count]))
1102 }
1103 _ => Err(EncodingError::CorruptData {
1104 detail: format!("unexpected inner encoding in nullable: {inner_enc}"),
1105 }),
1106 };
1107 }
1108
1109 let inner_block = EncodedBlock {
1111 encoding: inner_enc,
1112 payload: inner_payload.to_vec(),
1113 };
1114 let decoded = Self::decode(&inner_block)?;
1115
1116 match decoded {
1118 DecodedColumn::F64(vals) => Ok(DecodedColumn::NullableF64(scatter(vals, &validity))),
1119 DecodedColumn::I64(vals) => Ok(DecodedColumn::NullableI64(scatter(vals, &validity))),
1120 DecodedColumn::U64(vals) => Ok(DecodedColumn::NullableU64(scatter(vals, &validity))),
1121 DecodedColumn::Bool(vals) => Ok(DecodedColumn::NullableBool(scatter(vals, &validity))),
1122 DecodedColumn::String(vals) => {
1123 Ok(DecodedColumn::NullableString(scatter(vals, &validity)))
1124 }
1125 DecodedColumn::Decimal(vals) => {
1126 Ok(DecodedColumn::NullableDecimal(scatter(vals, &validity)))
1127 }
1128 _ => Err(EncodingError::CorruptData {
1129 detail: "unexpected decoded type in nullable wrapper".to_string(),
1130 }),
1131 }
1132 }
1133
1134 fn decode_rle(payload: &[u8]) -> Result<DecodedColumn> {
1136 let vtype = RleDecoder::value_type(payload)?;
1137 match vtype {
1138 0 => Ok(DecodedColumn::I64(RleDecoder::decode_i64(payload)?)),
1139 1 => Ok(DecodedColumn::U64(RleDecoder::decode_u64(payload)?)),
1140 2 => Ok(DecodedColumn::F64(RleDecoder::decode_f64(payload)?)),
1141 3 => Ok(DecodedColumn::Bool(RleDecoder::decode_bool(payload)?)),
1142 4 => Ok(DecodedColumn::String(RleDecoder::decode_string(payload)?)),
1143 other => Err(EncodingError::CorruptData {
1144 detail: format!("unknown RLE value type: {other}"),
1145 }),
1146 }
1147 }
1148
1149 pub fn decode_bytes(data: &[u8]) -> Result<DecodedColumn> {
1156 let block = EncodedBlock::from_bytes(data)?;
1157 Self::decode(&block)
1158 }
1159}
1160
1161pub(crate) fn should_use_specialized(encoded: &[u8], raw_size: usize) -> bool {
1168 if raw_size == 0 {
1169 return false;
1170 }
1171 #[allow(clippy::cast_precision_loss)]
1172 let ratio = raw_size as f64 / encoded.len() as f64;
1173 ratio >= MIN_COMPRESSION_RATIO
1174}
1175
1176fn encode_validity_bitmap(validity: &[bool]) -> Vec<u8> {
1184 let byte_count = validity.len().div_ceil(8);
1185 let mut bitmap = vec![0u8; byte_count];
1186 for (i, &valid) in validity.iter().enumerate() {
1187 if valid {
1188 bitmap[i / 8] |= 1 << (i % 8);
1189 }
1190 }
1191 bitmap
1192}
1193
1194fn wrap_nullable(
1196 inner_enc: EncodingType,
1197 total_count: usize,
1198 validity: &[bool],
1199 inner_payload: &[u8],
1200) -> EncodedBlock {
1201 let bitmap = encode_validity_bitmap(validity);
1202 let mut payload = Vec::with_capacity(1 + 4 + bitmap.len() + inner_payload.len());
1203 payload.push(inner_enc.tag());
1204 payload.extend_from_slice(&(total_count as u32).to_le_bytes());
1205 payload.extend_from_slice(&bitmap);
1206 payload.extend_from_slice(inner_payload);
1207 EncodedBlock {
1208 encoding: EncodingType::Nullable,
1209 payload,
1210 }
1211}
1212
1213fn extract_non_null_f64(values: &[Option<f64>]) -> (Vec<f64>, Vec<bool>) {
1215 let validity: Vec<bool> = values.iter().map(std::option::Option::is_some).collect();
1216 let non_null: Vec<f64> = values.iter().filter_map(|v| *v).collect();
1217 (non_null, validity)
1218}
1219
1220fn extract_non_null_i64(values: &[Option<i64>]) -> (Vec<i64>, Vec<bool>) {
1222 let validity: Vec<bool> = values.iter().map(std::option::Option::is_some).collect();
1223 let non_null: Vec<i64> = values.iter().filter_map(|v| *v).collect();
1224 (non_null, validity)
1225}
1226
1227fn extract_non_null_u64(values: &[Option<u64>]) -> (Vec<u64>, Vec<bool>) {
1229 let validity: Vec<bool> = values.iter().map(std::option::Option::is_some).collect();
1230 let non_null: Vec<u64> = values.iter().filter_map(|v| *v).collect();
1231 (non_null, validity)
1232}
1233
1234fn scatter<T: Default + Clone>(values: Vec<T>, validity: &[bool]) -> Vec<Option<T>> {
1239 let mut result = Vec::with_capacity(validity.len());
1240 let mut val_iter = values.into_iter();
1241 for &valid in validity {
1242 if valid {
1243 result.push(val_iter.next().map(Some).unwrap_or(None));
1244 } else {
1245 result.push(None);
1246 }
1247 }
1248 result
1249}
1250
1251#[cfg(test)]
1256mod tests {
1257 use super::*;
1258
1259 #[test]
1262 fn encoding_type_tag_roundtrip() {
1263 let all = [
1264 EncodingType::DeltaOfDelta,
1265 EncodingType::Chimp,
1266 EncodingType::Gorilla,
1267 EncodingType::IntegerI64,
1268 EncodingType::IntegerU64,
1269 EncodingType::Dictionary,
1270 EncodingType::Bitmap,
1271 EncodingType::PlainF64,
1272 EncodingType::PlainI64,
1273 EncodingType::PlainU64,
1274 EncodingType::PlainBool,
1275 EncodingType::PlainString,
1276 EncodingType::Nullable,
1277 EncodingType::Rle,
1278 ];
1279 for enc in &all {
1280 let tag = enc.tag();
1281 let recovered = EncodingType::from_tag(tag).unwrap();
1282 assert_eq!(*enc, recovered);
1283 }
1284 }
1285
1286 #[test]
1287 fn encoding_type_unknown_tag() {
1288 assert!(EncodingType::from_tag(255).is_err());
1289 }
1290
1291 #[test]
1296 fn all_lists_every_variant_and_agrees_with_from_tag() {
1297 let scanned: Vec<EncodingType> = (0..=u8::MAX)
1298 .filter_map(|t| EncodingType::from_tag(t).ok())
1299 .collect();
1300 assert_eq!(EncodingType::ALL, scanned.as_slice());
1301 for enc in EncodingType::ALL {
1302 assert_eq!(EncodingType::from_tag(enc.tag()).unwrap(), *enc);
1303 }
1304 for (i, enc) in EncodingType::ALL.iter().enumerate() {
1307 assert_eq!(usize::from(enc.tag()), i, "{enc} has a non-dense tag");
1308 }
1309 }
1310
1311 #[test]
1314 fn encoded_block_roundtrip() {
1315 let block = EncodedBlock {
1316 encoding: EncodingType::Chimp,
1317 payload: vec![1, 2, 3, 4],
1318 };
1319 let bytes = block.to_bytes();
1320 assert_eq!(bytes[0], EncodingType::Chimp.tag());
1321 let recovered = EncodedBlock::from_bytes(&bytes).unwrap();
1322 assert_eq!(recovered.encoding, block.encoding);
1323 assert_eq!(recovered.payload, block.payload);
1324 }
1325
1326 #[test]
1327 fn encoded_block_empty_error() {
1328 assert!(EncodedBlock::from_bytes(&[]).is_err());
1329 }
1330
1331 #[test]
1334 fn encode_timestamps_monotonic() {
1335 let ts: Vec<i64> = (0..1000).map(|i| 1_000_000 + i * 10_000).collect();
1336 let block = ColumnEncoder::encode_timestamps(&ts).unwrap();
1337 assert_eq!(block.encoding, EncodingType::PcoI64);
1341 let decoded = ColumnDecoder::decode(&block).unwrap();
1342 assert_eq!(decoded, DecodedColumn::I64(ts));
1343 }
1344
1345 #[test]
1346 fn encode_timestamps_honours_an_explicit_codec() {
1347 let ts: Vec<i64> = (0..1000).map(|i| 1_000_000 + i * 10_000).collect();
1348 for (strategy, expected) in [
1349 (TimestampEncoding::Pco, EncodingType::PcoI64),
1350 (TimestampEncoding::DeltaOfDelta, EncodingType::DeltaOfDelta),
1351 (TimestampEncoding::Plain, EncodingType::PlainI64),
1352 (TimestampEncoding::Auto, EncodingType::PcoI64),
1353 ] {
1354 let block = ColumnEncoder::encode_timestamps_with(&ts, strategy).unwrap();
1355 assert_eq!(block.encoding, expected, "{strategy:?}");
1356 assert_eq!(
1357 ColumnDecoder::decode(&block).unwrap(),
1358 DecodedColumn::I64(ts.clone())
1359 );
1360 }
1361 }
1362
1363 #[test]
1365 fn auto_timestamps_never_loses_to_delta_of_delta() {
1366 let mut seed = 7u64;
1369 let ts: Vec<i64> = (0..2000)
1370 .map(|_| {
1371 seed = seed.wrapping_mul(6_364_136_223_846_793_005).wrapping_add(1);
1372 (seed >> 20) as i64
1373 })
1374 .collect();
1375 let auto = ColumnEncoder::encode_timestamps_with(&ts, TimestampEncoding::Auto).unwrap();
1376 let dod =
1377 ColumnEncoder::encode_timestamps_with(&ts, TimestampEncoding::DeltaOfDelta).unwrap();
1378 let pco = ColumnEncoder::encode_timestamps_with(&ts, TimestampEncoding::Pco).unwrap();
1379 assert!(auto.payload.len() <= dod.payload.len().min(pco.payload.len()));
1380 assert_eq!(
1381 ColumnDecoder::decode(&auto).unwrap(),
1382 DecodedColumn::I64(ts)
1383 );
1384 }
1385
1386 #[test]
1387 fn encode_timestamps_bytes_roundtrip() {
1388 let ts: Vec<i64> = (0..100).map(|i| 1_000_000 + i * 10_000).collect();
1389 let block = ColumnEncoder::encode_timestamps(&ts).unwrap();
1390 let raw = block.to_bytes();
1391 let decoded = ColumnDecoder::decode_bytes(&raw).unwrap();
1392 assert_eq!(decoded, DecodedColumn::I64(ts));
1393 }
1394
1395 #[test]
1398 fn encode_f64_adaptive_strategy() {
1399 let values: Vec<f64> = (0..500).map(|i| 20.0 + (i as f64) * 0.01).collect();
1402 let block = ColumnEncoder::encode_f64(&values, FloatEncoding::Chimp).unwrap();
1403 assert_eq!(block.encoding, EncodingType::Pco);
1404 let decoded = ColumnDecoder::decode(&block).unwrap();
1405 assert_eq!(decoded, DecodedColumn::F64(values));
1406 }
1407
1408 #[test]
1409 fn encode_f64_gorilla_strategy() {
1410 let values: Vec<f64> = (0..500).map(|i| 20.0 + (i as f64) * 0.01).collect();
1411 let block = ColumnEncoder::encode_f64(&values, FloatEncoding::Gorilla).unwrap();
1412 assert!(
1413 block.encoding == EncodingType::Gorilla || block.encoding == EncodingType::PlainF64
1414 );
1415 let decoded = ColumnDecoder::decode(&block).unwrap();
1416 assert_eq!(decoded, DecodedColumn::F64(values));
1417 }
1418
1419 #[test]
1420 fn encode_f64_plain_strategy() {
1421 let values = vec![1.0, 2.0, 3.0];
1422 let block = ColumnEncoder::encode_f64(&values, FloatEncoding::Plain).unwrap();
1423 assert_eq!(block.encoding, EncodingType::PlainF64);
1424 let decoded = ColumnDecoder::decode(&block).unwrap();
1425 assert_eq!(decoded, DecodedColumn::F64(values));
1426 }
1427
1428 #[test]
1431 fn encode_i64_with_fallback() {
1432 let values: Vec<i64> = (0..1000).collect();
1433 let block = ColumnEncoder::encode_i64(&values).unwrap();
1434 assert!(
1435 block.encoding == EncodingType::PcoI64
1436 || block.encoding == EncodingType::IntegerI64
1437 || block.encoding == EncodingType::PlainI64
1438 );
1439 let decoded = ColumnDecoder::decode(&block).unwrap();
1440 assert_eq!(decoded, DecodedColumn::I64(values));
1441 }
1442
1443 #[test]
1444 fn encode_u64_with_fallback() {
1445 let values: Vec<u64> = (0..1000).collect();
1446 let block = ColumnEncoder::encode_u64(&values).unwrap();
1447 assert!(
1448 block.encoding == EncodingType::PcoU64
1449 || block.encoding == EncodingType::IntegerU64
1450 || block.encoding == EncodingType::PlainU64
1451 );
1452 let decoded = ColumnDecoder::decode(&block).unwrap();
1453 assert_eq!(decoded, DecodedColumn::U64(values));
1454 }
1455
1456 #[test]
1459 fn encode_string_low_cardinality() {
1460 let raw = vec!["us-east-1"; 500];
1461 let block = ColumnEncoder::encode_string(&raw).unwrap();
1462 assert_eq!(block.encoding, EncodingType::Dictionary);
1463 let decoded = ColumnDecoder::decode(&block).unwrap();
1464 let expected: Vec<String> = raw.iter().map(|s| (*s).to_owned()).collect();
1465 assert_eq!(decoded, DecodedColumn::String(expected));
1466 }
1467
1468 #[test]
1469 fn encode_string_high_cardinality_fallback() {
1470 let raw: Vec<String> = (0..200).map(|i| format!("uuid-{i}")).collect();
1472 let refs: Vec<&str> = raw.iter().map(String::as_str).collect();
1473 let block = ColumnEncoder::encode_string(&refs).unwrap();
1474 let decoded = ColumnDecoder::decode(&block).unwrap();
1475 assert_eq!(decoded, DecodedColumn::String(raw));
1476 }
1477
1478 #[test]
1481 fn encode_bool_bitmap() {
1482 let values: Vec<bool> = (0..100).map(|i| i % 3 == 0).collect();
1483 let block = ColumnEncoder::encode_bool(&values).unwrap();
1484 assert_eq!(block.encoding, EncodingType::Bitmap);
1485 let decoded = ColumnDecoder::decode(&block).unwrap();
1486 assert_eq!(decoded, DecodedColumn::Bool(values));
1487 }
1488
1489 #[test]
1492 fn empty_inputs_error() {
1493 assert!(ColumnEncoder::encode_timestamps(&[]).is_err());
1494 assert!(ColumnEncoder::encode_f64(&[], FloatEncoding::Chimp).is_err());
1495 assert!(ColumnEncoder::encode_i64(&[]).is_err());
1496 assert!(ColumnEncoder::encode_u64(&[]).is_err());
1497 let empty: &[&str] = &[];
1498 assert!(ColumnEncoder::encode_string(empty).is_err());
1499 assert!(ColumnEncoder::encode_bool(&[]).is_err());
1500 }
1501
1502 #[test]
1505 fn should_use_specialized_logic() {
1506 assert!(should_use_specialized(&[0u8; 50], 100));
1508 assert!(!should_use_specialized(&[0u8; 80], 100));
1510 assert!(!should_use_specialized(&[0u8; 10], 0));
1512 }
1513
1514 #[test]
1517 fn nullable_f64_mixed() {
1518 let values = vec![Some(1.0), None, Some(3.0), None, Some(5.0)];
1519 let block = ColumnEncoder::encode_f64_nullable(&values, FloatEncoding::Plain).unwrap();
1520 assert_eq!(block.encoding, EncodingType::Nullable);
1521 let decoded = ColumnDecoder::decode(&block).unwrap();
1522 assert_eq!(decoded, DecodedColumn::NullableF64(values));
1523 }
1524
1525 #[test]
1526 fn nullable_f64_all_present() {
1527 let values = vec![Some(1.0), Some(2.0), Some(3.0)];
1528 let block = ColumnEncoder::encode_f64_nullable(&values, FloatEncoding::Plain).unwrap();
1529 let decoded = ColumnDecoder::decode(&block).unwrap();
1530 assert_eq!(decoded, DecodedColumn::NullableF64(values));
1531 }
1532
1533 #[test]
1534 fn nullable_f64_all_null() {
1535 let values: Vec<Option<f64>> = vec![None, None, None];
1536 let block = ColumnEncoder::encode_f64_nullable(&values, FloatEncoding::Plain).unwrap();
1537 let decoded = ColumnDecoder::decode(&block).unwrap();
1538 assert_eq!(decoded, DecodedColumn::NullableF64(values));
1539 }
1540
1541 #[test]
1542 fn nullable_i64_mixed() {
1543 let values = vec![Some(10), None, Some(30), Some(40), None];
1544 let block = ColumnEncoder::encode_i64_nullable(&values).unwrap();
1545 assert_eq!(block.encoding, EncodingType::Nullable);
1546 let decoded = ColumnDecoder::decode(&block).unwrap();
1547 assert_eq!(decoded, DecodedColumn::NullableI64(values));
1548 }
1549
1550 #[test]
1551 fn nullable_u64_mixed() {
1552 let values = vec![None, Some(100u64), Some(200), None];
1553 let block = ColumnEncoder::encode_u64_nullable(&values).unwrap();
1554 let decoded = ColumnDecoder::decode(&block).unwrap();
1555 assert_eq!(decoded, DecodedColumn::NullableU64(values));
1556 }
1557
1558 #[test]
1559 fn nullable_string_mixed() {
1560 let values = vec![Some("hello"), None, Some("world"), None];
1561 let block = ColumnEncoder::encode_string_nullable(&values).unwrap();
1562 let decoded = ColumnDecoder::decode(&block).unwrap();
1563 let expected: Vec<Option<String>> =
1564 values.iter().map(|v| v.map(ToString::to_string)).collect();
1565 assert_eq!(decoded, DecodedColumn::NullableString(expected));
1566 }
1567
1568 #[test]
1569 fn nullable_f64_bytes_roundtrip() {
1570 let values = vec![Some(1.0), None, Some(3.0)];
1571 let block = ColumnEncoder::encode_f64_nullable(&values, FloatEncoding::Plain).unwrap();
1572 let raw = block.to_bytes();
1573 let decoded = ColumnDecoder::decode_bytes(&raw).unwrap();
1574 assert_eq!(decoded, DecodedColumn::NullableF64(values));
1575 }
1576
1577 #[test]
1578 fn nullable_empty_errors() {
1579 let empty_f64: &[Option<f64>] = &[];
1580 assert!(ColumnEncoder::encode_f64_nullable(empty_f64, FloatEncoding::Plain).is_err());
1581 let empty_i64: &[Option<i64>] = &[];
1582 assert!(ColumnEncoder::encode_i64_nullable(empty_i64).is_err());
1583 let empty_u64: &[Option<u64>] = &[];
1584 assert!(ColumnEncoder::encode_u64_nullable(empty_u64).is_err());
1585 let empty_str: &[Option<&str>] = &[];
1586 assert!(ColumnEncoder::encode_string_nullable(empty_str).is_err());
1587 let empty_bool: &[Option<bool>] = &[];
1588 assert!(ColumnEncoder::encode_bool_nullable(empty_bool).is_err());
1589 }
1590
1591 #[test]
1592 fn nullable_distinguishes_zero_from_null() {
1593 let values = vec![Some(0.0), None, Some(0.0), None];
1596 let block = ColumnEncoder::encode_f64_nullable(&values, FloatEncoding::Plain).unwrap();
1597 let decoded = ColumnDecoder::decode(&block).unwrap();
1598 match &decoded {
1599 DecodedColumn::NullableF64(vals) => {
1600 assert_eq!(vals[0], Some(0.0));
1601 assert_eq!(vals[1], None); assert_eq!(vals[2], Some(0.0));
1603 assert_eq!(vals[3], None); }
1605 other => panic!("Expected NullableF64, got {other:?}"),
1606 }
1607 }
1608
1609 #[test]
1610 fn nullable_i64_distinguishes_zero_from_null() {
1611 let values = vec![Some(0i64), None, Some(0), None, Some(42)];
1612 let block = ColumnEncoder::encode_i64_nullable(&values).unwrap();
1613 let decoded = ColumnDecoder::decode(&block).unwrap();
1614 match &decoded {
1615 DecodedColumn::NullableI64(vals) => {
1616 assert_eq!(vals[0], Some(0));
1617 assert_eq!(vals[1], None);
1618 assert_eq!(vals[2], Some(0));
1619 assert_eq!(vals[3], None);
1620 assert_eq!(vals[4], Some(42));
1621 }
1622 other => panic!("Expected NullableI64, got {other:?}"),
1623 }
1624 }
1625}
1626
1627#[cfg(test)]
1628mod proptests {
1629 use super::*;
1630 use proptest::prelude::*;
1631
1632 proptest! {
1633 #[test]
1634 fn roundtrip_timestamps(mut values in proptest::collection::vec(any::<i64>(), 1..300)) {
1635 values.sort_unstable();
1636 let block = ColumnEncoder::encode_timestamps(&values).unwrap();
1637 let decoded = ColumnDecoder::decode(&block).unwrap();
1638 prop_assert_eq!(DecodedColumn::I64(values), decoded);
1639 }
1640
1641 #[test]
1642 fn roundtrip_i64(values in proptest::collection::vec(any::<i64>(), 1..300)) {
1643 let block = ColumnEncoder::encode_i64(&values).unwrap();
1644 let decoded = ColumnDecoder::decode(&block).unwrap();
1645 prop_assert_eq!(DecodedColumn::I64(values), decoded);
1646 }
1647
1648 #[test]
1649 fn roundtrip_u64(values in proptest::collection::vec(any::<u64>(), 1..300)) {
1650 let block = ColumnEncoder::encode_u64(&values).unwrap();
1651 let decoded = ColumnDecoder::decode(&block).unwrap();
1652 prop_assert_eq!(DecodedColumn::U64(values), decoded);
1653 }
1654
1655 #[test]
1656 fn roundtrip_f64(values in proptest::collection::vec(any::<f64>(), 1..300)) {
1657 let block = ColumnEncoder::encode_f64(&values, FloatEncoding::Gorilla).unwrap();
1658 let decoded = ColumnDecoder::decode(&block).unwrap();
1659 prop_assert_eq!(DecodedColumn::F64(values), decoded);
1660 }
1661
1662 #[test]
1663 fn roundtrip_bool(values in proptest::collection::vec(any::<bool>(), 1..300)) {
1664 let block = ColumnEncoder::encode_bool(&values).unwrap();
1665 let decoded = ColumnDecoder::decode(&block).unwrap();
1666 prop_assert_eq!(DecodedColumn::Bool(values), decoded);
1667 }
1668
1669 #[test]
1670 fn roundtrip_string(values in proptest::collection::vec("[a-z]{0,8}", 1..100)) {
1671 let refs: Vec<&str> = values.iter().map(String::as_str).collect();
1672 let block = ColumnEncoder::encode_string(&refs).unwrap();
1673 let decoded = ColumnDecoder::decode(&block).unwrap();
1674 prop_assert_eq!(DecodedColumn::String(values), decoded);
1675 }
1676
1677 #[test]
1678 fn roundtrip_nullable_i64(values in proptest::collection::vec(any::<Option<i64>>(), 1..300)) {
1679 let block = ColumnEncoder::encode_i64_nullable(&values).unwrap();
1680 let decoded = ColumnDecoder::decode(&block).unwrap();
1681 prop_assert_eq!(DecodedColumn::NullableI64(values), decoded);
1682 }
1683
1684 #[test]
1685 fn roundtrip_nullable_u64(values in proptest::collection::vec(any::<Option<u64>>(), 1..300)) {
1686 let block = ColumnEncoder::encode_u64_nullable(&values).unwrap();
1687 let decoded = ColumnDecoder::decode(&block).unwrap();
1688 prop_assert_eq!(DecodedColumn::NullableU64(values), decoded);
1689 }
1690
1691 #[test]
1692 fn roundtrip_nullable_f64(values in proptest::collection::vec(any::<Option<f64>>(), 1..300)) {
1693 let block = ColumnEncoder::encode_f64_nullable(&values, FloatEncoding::Gorilla).unwrap();
1694 let decoded = ColumnDecoder::decode(&block).unwrap();
1695 prop_assert_eq!(DecodedColumn::NullableF64(values), decoded);
1696 }
1697
1698 #[test]
1699 fn roundtrip_nullable_bool(values in proptest::collection::vec(any::<Option<bool>>(), 1..300)) {
1700 let block = ColumnEncoder::encode_bool_nullable(&values).unwrap();
1701 let decoded = ColumnDecoder::decode(&block).unwrap();
1702 prop_assert_eq!(DecodedColumn::NullableBool(values), decoded);
1703 }
1704
1705 #[test]
1706 fn roundtrip_nullable_string(values in proptest::collection::vec(
1707 proptest::option::of("[a-z]{0,8}"), 1..100
1708 )) {
1709 let refs: Vec<Option<&str>> = values.iter().map(|o| o.as_deref()).collect();
1710 let block = ColumnEncoder::encode_string_nullable(&refs).unwrap();
1711 let decoded = ColumnDecoder::decode(&block).unwrap();
1712 let expected: Vec<Option<String>> = values.clone();
1713 prop_assert_eq!(DecodedColumn::NullableString(expected), decoded);
1714 }
1715 }
1716}