1use rudb_common::{Error, Result};
45
46use crate::chooser::{Chooser, EXHAUSTIVE};
47use crate::reader::Reader;
48
49use crate::bitpack::{self, VALUES};
50
51const MAX_DEPTH: u8 = 3;
58
59const RUN: usize = 8;
69
70#[derive(Debug, Clone, Copy, PartialEq, Eq)]
73pub enum Kind {
74 Constant = 0,
76 Packed = 1,
79 Delta = 2,
82 Rle = 3,
84 Dict = 4,
87 Sparse = 5,
89 Strided = 6,
92}
93
94impl Kind {
95 fn tag(self) -> u8 {
96 self as u8
97 }
98
99 fn from_tag(tag: u8) -> Result<Self> {
100 match tag {
101 0 => Ok(Self::Constant),
102 1 => Ok(Self::Packed),
103 2 => Ok(Self::Delta),
104 3 => Ok(Self::Rle),
105 4 => Ok(Self::Dict),
106 5 => Ok(Self::Sparse),
107 6 => Ok(Self::Strided),
108 other => Err(Error::internal(format!("unknown encoding tag {other}"))),
109 }
110 }
111
112 #[must_use]
114 pub fn name(self) -> &'static str {
115 match self {
116 Self::Constant => "CONSTANT",
117 Self::Packed => "FOR+BITPACK",
118 Self::Delta => "DELTA",
119 Self::Rle => "RLE",
120 Self::Dict => "DICT",
121 Self::Sparse => "SPARSE",
122 Self::Strided => "STRIDE",
123 }
124 }
125}
126
127pub fn encode(values: &[i64]) -> Result<Vec<u8>> {
134 encode_with(values, &EXHAUSTIVE)
135}
136
137pub fn encode_with(values: &[i64], chooser: &dyn Chooser) -> Result<Vec<u8>> {
147 encode_at(values, 0, chooser)
148}
149
150pub fn decode(bytes: &[u8]) -> Result<Vec<i64>> {
157 let mut reader = Reader::new(bytes);
158 let values = with_decoding(|scratch| decode_chunk(&mut reader, scratch))?;
159 if reader.remaining() != 0 {
160 return Err(Error::internal(format!(
161 "{} bytes left over after decoding a chunk",
162 reader.remaining()
163 )));
164 }
165 Ok(values)
166}
167
168pub fn decode_prefix(bytes: &[u8]) -> Result<(Vec<i64>, usize)> {
178 let mut reader = Reader::new(bytes);
179 let values = with_decoding(|scratch| decode_chunk(&mut reader, scratch))?;
180 Ok((values, reader.used()))
181}
182
183pub fn describe_prefix(bytes: &[u8]) -> Result<(String, usize)> {
189 let mut reader = Reader::new(bytes);
190 let text = describe_chunk(&mut reader)?;
191 Ok((text, reader.used()))
192}
193
194pub fn candidate_sizes(values: &[i64]) -> Result<Vec<(Kind, usize)>> {
201 let mut sizes = Vec::new();
202 for kind in candidates(values, 0) {
203 if let Some(bytes) = encode_as(kind, values, 0, &EXHAUSTIVE)? {
204 sizes.push((kind, bytes.len()));
205 }
206 }
207 Ok(sizes)
208}
209
210#[must_use]
217pub fn offered(values: &[i64]) -> Vec<Kind> {
218 candidates(values, 0)
219}
220
221pub fn encode_only(kind: Kind, values: &[i64]) -> Result<Option<Vec<u8>>> {
232 encode_as(kind, values, 0, &EXHAUSTIVE)
233}
234
235pub(crate) fn size_as(kind: Kind, values: &[i64], depth: u8) -> Result<Option<usize>> {
240 Ok(encode_as(kind, values, depth, &EXHAUSTIVE)?.map(|bytes| bytes.len()))
241}
242
243pub fn describe(bytes: &[u8]) -> Result<String> {
249 let mut reader = Reader::new(bytes);
250 describe_chunk(&mut reader)
251}
252
253fn encode_at(values: &[i64], depth: u8, chooser: &dyn Chooser) -> Result<Vec<u8>> {
254 let offered = candidates(values, depth);
255 let mut best: Option<Vec<u8>> = None;
256 for kind in chooser.narrow_integers(values, &offered, depth) {
257 let Some(bytes) = encode_as(kind, values, depth, chooser)? else {
258 continue;
259 };
260 if best.as_ref().is_none_or(|current| bytes.len() < current.len()) {
261 best = Some(bytes);
262 }
263 }
264 best.ok_or_else(|| Error::internal("no encoding applied to the chunk"))
267}
268
269fn candidates(values: &[i64], depth: u8) -> Vec<Kind> {
276 let mut kinds = vec![Kind::Packed];
277 if depth >= MAX_DEPTH || values.is_empty() {
278 return kinds;
279 }
280 if values.iter().all(|value| *value == values[0]) {
281 return vec![Kind::Constant];
283 }
284 if values.len() >= 2 && deltas_fit(values) {
285 kinds.push(Kind::Delta);
286 }
287 if run_count(values) * 4 <= values.len() * 3 {
288 kinds.push(Kind::Rle);
289 }
290 let (distinct, dominant) = spread_of(values);
294 if distinct * 2 <= values.len() {
295 kinds.push(Kind::Dict);
296 }
297 match dominant {
300 Some((_, count)) if count * 10 >= values.len() * 8 => kinds.push(Kind::Sparse),
301 _ => {}
302 }
303 if stride_of(values).is_some() {
304 kinds.push(Kind::Strided);
305 }
306 kinds
307}
308
309fn encode_as(
312 kind: Kind,
313 values: &[i64],
314 depth: u8,
315 chooser: &dyn Chooser,
316) -> Result<Option<Vec<u8>>> {
317 let mut out = Vec::new();
318 put_u8(&mut out, kind.tag());
319 put_u32(&mut out, u32::try_from(values.len()).map_err(|_| too_long(values.len()))?);
320 match kind {
321 Kind::Constant => {
322 let Some(first) = values.first() else {
323 return Ok(None);
324 };
325 if values.iter().any(|value| value != first) {
326 return Ok(None);
327 }
328 put_i64(&mut out, *first);
329 }
330 Kind::Packed => encode_packed(values, &mut out)?,
331 Kind::Delta => {
332 let (Some(first), Some(deltas)) = (values.first(), deltas(values)) else {
336 return Ok(None);
337 };
338 put_i64(&mut out, *first);
339 out.extend_from_slice(&encode_at(&deltas, depth + 1, chooser)?);
340 }
341 Kind::Rle => {
342 let (run_values, run_lengths) = runs(values);
343 if run_values.is_empty() {
344 return Ok(None);
345 }
346 out.extend_from_slice(&encode_at(&run_values, depth + 1, chooser)?);
347 out.extend_from_slice(&encode_at(&run_lengths, depth + 1, chooser)?);
348 }
349 Kind::Dict => {
350 let dictionary = distinct_values(values);
351 if dictionary.is_empty() {
352 return Ok(None);
353 }
354 let codes = codes_over(values, &dictionary);
355 out.extend_from_slice(&encode_at(&dictionary, depth + 1, chooser)?);
356 out.extend_from_slice(&encode_at(&codes, depth + 1, chooser)?);
357 }
358 Kind::Sparse => {
359 let Some((value, _)) = spread_of(values).1 else {
360 return Ok(None);
361 };
362 let mut positions = Vec::new();
363 let mut exceptions = Vec::new();
364 for (index, other) in values.iter().enumerate() {
365 if *other != value {
366 positions.push(index as i64);
367 exceptions.push(*other);
368 }
369 }
370 put_i64(&mut out, value);
371 put_u32(
372 &mut out,
373 u32::try_from(positions.len()).map_err(|_| too_long(positions.len()))?,
374 );
375 out.extend_from_slice(&encode_at(&positions, depth + 1, chooser)?);
376 out.extend_from_slice(&encode_at(&exceptions, depth + 1, chooser)?);
377 }
378 Kind::Strided => {
379 let (Some(base), Some(stride)) = (values.iter().min().copied(), stride_of(values))
380 else {
381 return Ok(None);
382 };
383 let mut steps = Vec::with_capacity(values.len());
384 for value in values {
385 let step = offset_from(*value, base) / stride;
386 let Ok(step) = i64::try_from(step) else {
391 return Ok(None);
392 };
393 steps.push(step);
394 }
395 put_i64(&mut out, base);
396 put_u64(&mut out, stride);
397 out.extend_from_slice(&encode_at(&steps, depth + 1, chooser)?);
398 }
399 }
400 Ok(Some(out))
401}
402
403fn encode_packed(values: &[i64], out: &mut Vec<u8>) -> Result<()> {
415 let mut offsets: Vec<u64> = Vec::with_capacity(VALUES);
419 let mut packed: Vec<u64> = vec![0; bitpack::packed_len::<u64>(64)];
422 let mut transposed = bitpack::Scratch::<u64>::new();
423 for unit in values.chunks(VALUES) {
424 let base = unit.iter().copied().min().unwrap_or(0);
425 offsets.clear();
426 offsets.extend(unit.iter().map(|value| offset_from(*value, base)));
427 let width = bitpack::required_width(&offsets);
428 put_i64(out, base);
429 put_u8(out, u8::try_from(width).map_err(|_| Error::internal("impossible width"))?);
430 if unit.len() == VALUES {
431 let words = bitpack::packed_len::<u64>(width);
432 bitpack::pack_with(&offsets, width, &mut packed[..words], &mut transposed)?;
433 for word in &packed[..words] {
434 put_u64(out, *word);
435 }
436 } else {
437 bitpack::pack_tail(&offsets, width, out)?;
438 }
439 }
440 Ok(())
441}
442
443struct Decoding {
466 packed: Vec<u64>,
469 unit: Vec<u64>,
471}
472
473thread_local! {
474 static DECODING: std::cell::RefCell<Decoding> =
476 const { std::cell::RefCell::new(Decoding::new()) };
477}
478
479fn with_decoding<T>(run: impl FnOnce(&mut Decoding) -> T) -> T {
486 DECODING.with(|cell| match cell.try_borrow_mut() {
487 Ok(mut scratch) => run(&mut scratch),
488 Err(_) => run(&mut Decoding::new()),
489 })
490}
491
492impl Decoding {
493 const fn new() -> Self {
495 Self { packed: Vec::new(), unit: Vec::new() }
496 }
497
498 fn ready(&mut self) {
500 if self.unit.len() != VALUES {
501 self.unit.resize(VALUES, 0);
502 self.packed.resize(bitpack::packed_len::<u64>(64), 0);
503 }
504 }
505}
506
507fn decode_chunk(reader: &mut Reader<'_>, scratch: &mut Decoding) -> Result<Vec<i64>> {
508 let kind = Kind::from_tag(reader.u8()?)?;
509 let count = reader.u32()? as usize;
510 match kind {
511 Kind::Constant => Ok(vec![reader.i64()?; count]),
512 Kind::Packed => {
513 let mut values = Vec::with_capacity(count);
514 scratch.ready();
515 while values.len() < count {
516 let base = reader.i64()?;
517 let width = reader.u8()? as usize;
518 let wanted = (count - values.len()).min(VALUES);
519 if wanted == VALUES {
520 let words = bitpack::packed_len::<u64>(width);
521 for word in &mut scratch.packed[..words] {
522 *word = reader.u64()?;
523 }
524 bitpack::unpack(&scratch.packed[..words], width, &mut scratch.unit)?;
525 values.extend(scratch.unit.iter().map(|offset| value_from(*offset, base)));
526 } else {
527 let bytes = reader.bytes(bitpack::tail_len(wanted, width))?;
528 let unit = bitpack::unpack_tail(bytes, width, wanted)?;
529 values.extend(unit.iter().map(|offset| value_from(*offset, base)));
530 }
531 }
532 Ok(values)
533 }
534 Kind::Delta => {
535 let first = reader.i64()?;
536 let deltas = decode_chunk(reader, scratch)?;
537 let mut values = Vec::with_capacity(count);
538 values.push(first);
539 let mut current = first;
540 for delta in deltas {
541 current = current.wrapping_add(unzigzag(delta as u64));
542 values.push(current);
543 }
544 check_count(values.len(), count)?;
545 Ok(values)
546 }
547 Kind::Rle => {
548 let run_values = decode_chunk(reader, scratch)?;
549 let run_lengths = decode_chunk(reader, scratch)?;
550 if run_values.len() != run_lengths.len() {
551 return Err(Error::internal("an RLE chunk has more runs than run lengths"));
552 }
553 let mut values = vec![0; count + RUN];
556 let mut at = 0usize;
557 for (value, length) in run_values.into_iter().zip(run_lengths) {
558 let length = usize::try_from(length)
559 .map_err(|_| Error::internal("a negative RLE run length"))?;
560 let end = at
561 .checked_add(length)
562 .filter(|end| *end <= count)
563 .ok_or_else(|| Error::internal("an RLE run ends past its chunk"))?;
564 let short =
565 if length <= RUN { values[at..].first_chunk_mut::<RUN>() } else { None };
566 match short {
567 Some(window) => window.fill(value),
568 None => values[at..end].fill(value),
569 }
570 at = end;
571 }
572 check_count(at, count)?;
573 values.truncate(count);
574 Ok(values)
575 }
576 Kind::Dict => {
577 let dictionary = decode_chunk(reader, scratch)?;
578 let codes = decode_chunk(reader, scratch)?;
579 let mut values = Vec::with_capacity(count);
580 for code in codes {
581 let index =
582 usize::try_from(code).ok().and_then(|index| dictionary.get(index)).ok_or_else(
583 || Error::internal(format!("code {code} is not in the dictionary")),
584 )?;
585 values.push(*index);
586 }
587 check_count(values.len(), count)?;
588 Ok(values)
589 }
590 Kind::Sparse => {
591 let value = reader.i64()?;
592 let exception_count = reader.u32()? as usize;
593 let positions = decode_chunk(reader, scratch)?;
594 let exceptions = decode_chunk(reader, scratch)?;
595 if positions.len() != exception_count || exceptions.len() != exception_count {
596 return Err(Error::internal("a sparse chunk disagrees about its exception count"));
597 }
598 let mut values = vec![value; count];
599 for (position, exception) in positions.into_iter().zip(exceptions) {
600 let position = usize::try_from(position)
601 .ok()
602 .filter(|position| *position < count)
603 .ok_or_else(|| {
604 Error::internal(format!("exception at {position} is outside the chunk"))
605 })?;
606 values[position] = exception;
607 }
608 Ok(values)
609 }
610 Kind::Strided => {
611 let base = reader.i64()?;
612 let stride = reader.u64()?;
613 let steps = decode_chunk(reader, scratch)?;
614 check_count(steps.len(), count)?;
615 let mut values = Vec::with_capacity(count);
616 for step in steps {
617 let step = u64::try_from(step)
618 .map_err(|_| Error::internal("a negative number of strides"))?;
619 values.push(value_from(step.wrapping_mul(stride), base));
620 }
621 Ok(values)
622 }
623 }
624}
625
626fn describe_chunk(reader: &mut Reader<'_>) -> Result<String> {
627 let kind = Kind::from_tag(reader.u8()?)?;
628 let count = reader.u32()? as usize;
629 Ok(match kind {
630 Kind::Constant => {
631 reader.i64()?;
632 "CONSTANT".to_string()
633 }
634 Kind::Packed => {
635 let mut widths = Vec::new();
636 let mut seen = 0;
637 while seen < count {
638 reader.i64()?;
639 let width = reader.u8()? as usize;
640 let wanted = (count - seen).min(VALUES);
641 if wanted == VALUES {
642 for _ in 0..bitpack::packed_len::<u64>(width) {
643 reader.u64()?;
644 }
645 } else {
646 reader.bytes(bitpack::tail_len(wanted, width))?;
647 }
648 widths.push(width);
649 seen += wanted;
650 }
651 let low = widths.iter().copied().min().unwrap_or(0);
652 let high = widths.iter().copied().max().unwrap_or(0);
653 if low == high {
656 format!("FOR+BITPACK[{low}]")
657 } else {
658 format!("FOR+BITPACK[{low}..{high}]")
659 }
660 }
661 Kind::Delta => {
662 reader.i64()?;
663 format!("DELTA({})", describe_chunk(reader)?)
664 }
665 Kind::Rle => {
666 let values = describe_chunk(reader)?;
667 let lengths = describe_chunk(reader)?;
668 format!("RLE({values}, {lengths})")
669 }
670 Kind::Dict => {
671 let dictionary = describe_chunk(reader)?;
672 let codes = describe_chunk(reader)?;
673 format!("DICT({dictionary}, {codes})")
674 }
675 Kind::Sparse => {
676 reader.i64()?;
677 reader.u32()?;
678 let positions = describe_chunk(reader)?;
679 let exceptions = describe_chunk(reader)?;
680 format!("SPARSE({positions}, {exceptions})")
681 }
682 Kind::Strided => {
683 reader.i64()?;
684 let stride = reader.u64()?;
685 format!("STRIDE[{stride}]({})", describe_chunk(reader)?)
686 }
687 })
688}
689
690fn stride_of(values: &[i64]) -> Option<u64> {
702 let base = values.iter().min().copied()?;
703 let mut divisor = 0u64;
704 for value in values {
705 divisor = gcd(divisor, offset_from(*value, base));
706 if divisor == 1 {
707 return None;
708 }
709 }
710 (divisor > 1).then_some(divisor)
713}
714
715fn gcd(mut left: u64, mut right: u64) -> u64 {
717 if left == 0 {
718 return right;
719 }
720 if right == 0 {
721 return left;
722 }
723 let shift = (left | right).trailing_zeros();
724 left >>= left.trailing_zeros();
725 loop {
726 right >>= right.trailing_zeros();
727 if left > right {
728 std::mem::swap(&mut left, &mut right);
729 }
730 right -= left;
731 if right == 0 {
732 return left << shift;
733 }
734 }
735}
736
737fn offset_from(value: i64, base: i64) -> u64 {
740 (i128::from(value) - i128::from(base)) as u64
741}
742
743fn value_from(offset: u64, base: i64) -> i64 {
744 (i128::from(base) + i128::from(offset)) as i64
745}
746
747fn zigzag(value: i64) -> u64 {
750 ((value << 1) ^ (value >> 63)) as u64
751}
752
753fn unzigzag(value: u64) -> i64 {
754 ((value >> 1) as i64) ^ -((value & 1) as i64)
755}
756
757fn deltas_fit(values: &[i64]) -> bool {
769 values.windows(2).all(|pair| i64::try_from(i128::from(pair[1]) - i128::from(pair[0])).is_ok())
770}
771
772fn deltas(values: &[i64]) -> Option<Vec<i64>> {
773 let mut deltas = Vec::with_capacity(values.len().saturating_sub(1));
774 for pair in values.windows(2) {
775 let difference = i128::from(pair[1]) - i128::from(pair[0]);
776 let difference = i64::try_from(difference).ok()?;
777 deltas.push(zigzag(difference) as i64);
778 }
779 Some(deltas)
780}
781
782fn run_count(values: &[i64]) -> usize {
783 let mut runs = 0;
784 let mut previous = None;
785 for value in values {
786 if previous != Some(value) {
787 runs += 1;
788 previous = Some(value);
789 }
790 }
791 runs
792}
793
794fn runs(values: &[i64]) -> (Vec<i64>, Vec<i64>) {
795 let mut run_values: Vec<i64> = Vec::new();
796 let mut run_lengths: Vec<i64> = Vec::new();
797 for value in values {
798 if run_values.last() == Some(value) {
799 *run_lengths.last_mut().expect("a run length exists beside every run value") += 1;
800 } else {
801 run_values.push(*value);
802 run_lengths.push(1);
803 }
804 }
805 (run_values, run_lengths)
806}
807
808fn spread_of(values: &[i64]) -> (usize, Option<(i64, usize)>) {
823 let mut sorted = values.to_vec();
824 sorted.sort_unstable();
825 let mut distinct = 0;
826 let mut best: Option<(i64, usize)> = None;
827 let mut index = 0;
828 while index < sorted.len() {
829 let value = sorted[index];
830 let mut end = index;
831 while end < sorted.len() && sorted[end] == value {
832 end += 1;
833 }
834 distinct += 1;
835 let count = end - index;
836 if best.is_none_or(|(_, seen)| count > seen) {
837 best = Some((value, count));
838 }
839 index = end;
840 }
841 (distinct, best)
842}
843
844fn distinct_values(values: &[i64]) -> Vec<i64> {
847 let mut distinct = values.to_vec();
848 distinct.sort_unstable();
849 distinct.dedup();
850 distinct
851}
852
853fn codes_over(values: &[i64], dictionary: &[i64]) -> Vec<i64> {
863 values
864 .iter()
865 .map(|value| {
866 dictionary
867 .binary_search(value)
868 .expect("the dictionary is the distinct values of this chunk") as i64
869 })
870 .collect()
871}
872
873fn check_count(actual: usize, expected: usize) -> Result<()> {
874 if actual == expected {
875 Ok(())
876 } else {
877 Err(Error::internal(format!(
878 "a chunk says it holds {expected} values and decoded to {actual}"
879 )))
880 }
881}
882
883fn too_long(len: usize) -> Error {
884 Error::internal(format!("a chunk of {len} values is longer than the format allows"))
885}
886
887fn put_u8(out: &mut Vec<u8>, value: u8) {
888 out.push(value);
889}
890
891fn put_u32(out: &mut Vec<u8>, value: u32) {
892 out.extend_from_slice(&value.to_le_bytes());
893}
894
895fn put_u64(out: &mut Vec<u8>, value: u64) {
896 out.extend_from_slice(&value.to_le_bytes());
897}
898
899fn put_i64(out: &mut Vec<u8>, value: i64) {
900 out.extend_from_slice(&value.to_le_bytes());
901}
902
903#[cfg(test)]
904mod tests {
905 use super::*;
906
907 fn round_trip(values: &[i64]) -> Vec<u8> {
908 let bytes = encode(values).unwrap();
909 assert_eq!(decode(&bytes).unwrap(), values, "{}", describe(&bytes).unwrap());
910 bytes
911 }
912
913 fn kind_of(bytes: &[u8]) -> Kind {
914 Kind::from_tag(bytes[0]).unwrap()
915 }
916
917 struct Random(u64);
919
920 impl Random {
921 fn new() -> Self {
922 Self(0x9e37_79b9_7f4a_7c15)
923 }
924
925 fn next(&mut self) -> u64 {
926 self.0 ^= self.0 << 13;
927 self.0 ^= self.0 >> 7;
928 self.0 ^= self.0 << 17;
929 self.0
930 }
931 }
932
933 #[test]
934 fn the_dictionary_is_sorted_and_the_codes_point_back_at_the_values() {
935 let values = vec![30i64, 10, 30, 20, 10, -5];
936 let dictionary = distinct_values(&values);
937 let codes = codes_over(&values, &dictionary);
938 assert_eq!(dictionary, vec![-5, 10, 20, 30]);
939 assert_eq!(codes, vec![3, 1, 3, 2, 1, 0]);
940 for (code, value) in codes.iter().zip(&values) {
941 assert_eq!(dictionary[*code as usize], *value);
942 }
943 }
944
945 #[test]
946 fn one_sort_gives_the_distinct_count_and_the_most_frequent_value() {
947 let values = vec![7i64, 7, 7, 1, 2, 2];
948 assert_eq!(spread_of(&values), (3, Some((7, 3))));
949 assert_eq!(spread_of(&[]), (0, None));
950 assert_eq!(spread_of(&[9]), (1, Some((9, 1))));
951
952 assert_eq!(spread_of(&[4i64, 4, 8, 8]), (2, Some((4, 2))));
955 }
956
957 #[test]
958 fn deltas_that_do_not_fit_are_refused_before_they_are_built() {
959 assert!(deltas_fit(&[1i64, 2, 3]));
960 assert!(deltas_fit(&[i64::MAX, i64::MAX]));
961 assert!(!deltas_fit(&[i64::MIN, i64::MAX]));
962 assert_eq!(deltas_fit(&[i64::MIN, i64::MAX]), deltas(&[i64::MIN, i64::MAX]).is_some());
963 assert_eq!(deltas_fit(&[1i64, 2, 3]), deltas(&[1i64, 2, 3]).is_some());
964 }
965
966 #[test]
967 fn what_the_chooser_returns_is_the_smallest_of_what_it_was_offered() {
968 let mut random = Random::new();
972 let noise: Vec<i64> = (0..2000).map(|_| (random.next() % 5000) as i64).collect();
973 let runs: Vec<i64> = (0..2000).map(|index: i64| index / 100).collect();
974 let climbing: Vec<i64> = (0..2000).map(|index| 1_700_000_000 + index).collect();
975 for values in [noise, runs, climbing, vec![7; 300], Vec::new()] {
976 let chosen = encode(&values).unwrap();
977 let mut smallest: Option<Vec<u8>> = None;
978 for kind in offered(&values) {
979 let Some(bytes) = encode_only(kind, &values).unwrap() else {
980 continue;
981 };
982 if smallest.as_ref().is_none_or(|best| bytes.len() < best.len()) {
983 smallest = Some(bytes);
984 }
985 }
986 assert_eq!(smallest.as_deref(), Some(chosen.as_slice()), "{}", values.len());
987 }
988 }
989
990 #[test]
991 fn a_column_of_whole_seconds_in_microseconds_pays_nothing_for_the_zeroes() {
992 let mut random = Random::new();
996 let day = 1_374_000_000_000_000i64;
997 let values: Vec<i64> =
998 (0..100_000).map(|_| day + (random.next() % 68_400) as i64 * 1_000_000).collect();
999 let bytes = round_trip(&values);
1000 assert_eq!(kind_of(&bytes), Kind::Strided);
1001 assert!(describe(&bytes).unwrap().starts_with("STRIDE[1000000]"), "{:?}", describe(&bytes));
1002 let strided = 100_000 * 17 / 8;
1004 assert!(bytes.len() < strided + 2000, "{} bytes for {strided} of payload", bytes.len());
1005
1006 let plain = encode_only(Kind::Packed, &values).unwrap().expect("packing always applies");
1007 assert!(
1008 bytes.len() * 2 < plain.len(),
1009 "{} strided against {} packed",
1010 bytes.len(),
1011 plain.len()
1012 );
1013 }
1014
1015 #[test]
1016 fn a_stride_is_the_common_factor_of_the_distances_from_the_smallest_value() {
1017 assert_eq!(stride_of(&[10i64, 20, 40]), Some(10));
1018 assert_eq!(stride_of(&[7i64, 17, 37]), Some(10));
1021 assert_eq!(stride_of(&[10i64, 20, 23]), None);
1022 assert_eq!(stride_of(&[5i64; 100]), None);
1025 assert_eq!(stride_of(&[]), None);
1026 assert_eq!(stride_of(&[i64::MIN, i64::MAX]), Some(u64::MAX));
1028 }
1029
1030 #[test]
1031 fn a_stride_across_the_whole_of_the_type_round_trips() {
1032 for values in [vec![i64::MIN, i64::MAX], vec![i64::MIN, 0, i64::MAX]] {
1035 let bytes = round_trip(&values);
1036 assert_eq!(decode(&bytes).unwrap(), values);
1037 }
1038 }
1039
1040 #[test]
1041 fn a_column_with_no_common_factor_is_not_offered_a_stride() {
1042 let mut random = Random::new();
1043 let values: Vec<i64> = (0..2000).map(|_| (random.next() % 1_000_000) as i64).collect();
1044 assert!(!offered(&values).contains(&Kind::Strided));
1045 assert!(encode_only(Kind::Strided, &values).unwrap().is_none());
1046 }
1047
1048 #[test]
1049 fn an_empty_chunk_round_trips() {
1050 let bytes = round_trip(&[]);
1051 assert_eq!(bytes.len(), 5);
1052 }
1053
1054 #[test]
1055 fn a_constant_column_costs_thirteen_bytes_however_long_it_is() {
1056 let bytes = round_trip(&vec![42; 1_000_000]);
1057 assert_eq!(kind_of(&bytes), Kind::Constant);
1058 assert_eq!(bytes.len(), 13);
1059 }
1060
1061 #[test]
1062 fn a_narrow_range_is_packed_at_the_width_of_the_range_and_not_of_the_type() {
1063 let mut random = Random::new();
1065 let values: Vec<i64> = (0..100_000).map(|_| 1000 + (random.next() % 64) as i64).collect();
1066 let bytes = round_trip(&values);
1067 assert_eq!(kind_of(&bytes), Kind::Packed);
1068 let packed = 100_000 * 6 / 8;
1069 assert!(bytes.len() < packed + 2000, "{} bytes for {packed} of payload", bytes.len());
1070 assert!(bytes.len() > packed, "{} bytes cannot hold {packed}", bytes.len());
1071 }
1072
1073 #[test]
1074 fn a_counter_becomes_deltas_and_then_a_constant() {
1075 let values: Vec<i64> = (0..1_000_000).collect();
1078 let bytes = round_trip(&values);
1079 assert_eq!(kind_of(&bytes), Kind::Delta);
1080 assert_eq!(describe(&bytes).unwrap(), "DELTA(CONSTANT)");
1081 assert!(bytes.len() < 40, "{} bytes for a counter", bytes.len());
1082 }
1083
1084 #[test]
1085 fn a_column_that_counts_down_is_as_cheap_as_one_that_counts_up() {
1086 let up: Vec<i64> = (0..100_000).collect();
1088 let down: Vec<i64> = (0..100_000).rev().collect();
1089 assert_eq!(round_trip(&up).len(), round_trip(&down).len());
1090 }
1091
1092 #[test]
1093 fn long_runs_become_rle() {
1094 let mut values = Vec::new();
1095 for run in 0..1000 {
1096 values.extend(std::iter::repeat_n(run % 7, 200));
1097 }
1098 let bytes = round_trip(&values);
1099 assert_eq!(kind_of(&bytes), Kind::Rle);
1100 assert!(bytes.len() < 2000, "{} bytes for 1000 runs", bytes.len());
1101 }
1102
1103 #[test]
1104 fn a_low_cardinality_column_becomes_a_dictionary() {
1105 let mut random = Random::new();
1111 let dictionary: Vec<i64> =
1112 (0..40).map(|_| 1_000_000_000 + (random.next() % (1 << 30)) as i64).collect();
1113 let values: Vec<i64> =
1114 (0..100_000).map(|_| dictionary[(random.next() % 40) as usize]).collect();
1115 let bytes = round_trip(&values);
1116 assert_eq!(kind_of(&bytes), Kind::Dict);
1117 assert!(bytes.len() < 100_000, "{} bytes", bytes.len());
1118 }
1119
1120 #[test]
1121 fn a_nearly_constant_column_becomes_sparse() {
1122 let mut values = vec![0i64; 100_000];
1123 for index in 0..300 {
1124 values[index * 331] = 1 << 40;
1125 }
1126 let bytes = round_trip(&values);
1127 assert_eq!(kind_of(&bytes), Kind::Sparse);
1128 assert!(bytes.len() < 3000, "{} bytes for 300 exceptions", bytes.len());
1129 }
1130
1131 #[test]
1132 fn the_cascade_goes_more_than_one_level_deep() {
1133 let mut values = Vec::new();
1136 for index in 0..2000i64 {
1137 values.extend(std::iter::repeat_n(1_000_000 + (index % 5) * 104_729, 100));
1138 }
1139 let bytes = round_trip(&values);
1140 let shape = describe(&bytes).unwrap();
1141 assert!(shape.contains('('), "{shape} is not a cascade");
1142 assert!(bytes.len() < 4000, "{} bytes: {shape}", bytes.len());
1143 }
1144
1145 #[test]
1146 fn random_data_is_packed_at_full_width_and_costs_what_it_costs() {
1147 let mut random = Random::new();
1150 let values: Vec<i64> = (0..10_000).map(|_| random.next() as i64).collect();
1151 let bytes = round_trip(&values);
1152 assert_eq!(kind_of(&bytes), Kind::Packed);
1153 assert!(bytes.len() < 10_000 * 8 + 1000, "{} bytes", bytes.len());
1154 }
1155
1156 #[test]
1157 fn the_extremes_of_the_type_survive() {
1158 let values = vec![i64::MIN, i64::MAX, 0, -1, i64::MIN, i64::MAX];
1161 round_trip(&values);
1162 round_trip(&[i64::MIN; 3]);
1163 round_trip(&[i64::MIN, i64::MIN + 1]);
1164 }
1165
1166 #[test]
1167 fn a_chunk_that_is_not_a_multiple_of_the_unit_round_trips() {
1168 for len in [1, 2, 1023, 1024, 1025, 2047, 2049] {
1169 let values: Vec<i64> = (0..len).map(|index| (index * 31 % 97) as i64).collect();
1170 round_trip(&values);
1171 }
1172 }
1173
1174 #[test]
1175 fn units_of_different_widths_in_one_chunk_do_not_read_each_others_leftovers() {
1176 let mut random = Random::new();
1188 let mut values = Vec::new();
1189 for width in [40u32, 3, 61, 1, 17, 40] {
1190 for _ in 0..1024 {
1191 values.push((random.next() & ((1u64 << width) - 1)) as i64);
1192 }
1193 }
1194 let bytes = encode(&values).unwrap();
1195 let described = describe(&bytes).unwrap();
1196 assert!(described.starts_with("FOR+BITPACK"), "expected one packed chunk, got {described}");
1197 assert_eq!(decode(&bytes).unwrap(), values, "{described}");
1198 }
1199
1200 #[test]
1201 fn a_cascade_decodes_the_same_through_a_shared_scratch_as_through_its_own() {
1202 let mut values = Vec::new();
1207 for index in 0..8192i64 {
1208 values.push(1_600_000_000 + index / 4 + (index % 7) * 1_000);
1209 }
1210 let bytes = encode(&values).unwrap();
1211 let described = describe(&bytes).unwrap();
1212 assert!(described.contains('('), "expected a cascade, got {described}");
1213 assert_eq!(decode(&bytes).unwrap(), values, "{described}");
1214 }
1215
1216 #[test]
1217 fn a_partial_unit_costs_its_own_values_and_not_a_whole_unit() {
1218 let values = vec![1i64 << 39, (1 << 39) + 7, 1 << 38];
1222 let bytes = encode_only(Kind::Packed, &values).unwrap().unwrap();
1223 assert_eq!(bytes.len(), 5 + 9 + 15);
1224 assert_eq!(decode(&bytes).unwrap(), values);
1225 }
1226
1227 #[test]
1228 fn the_frame_of_reference_is_per_unit_and_not_per_chunk() {
1229 let values: Vec<i64> =
1233 (0..4096i64).map(|index| (index / 1024) * 1_000_000 + (index % 1024)).collect();
1234 let bytes = encode_only(Kind::Packed, &values).unwrap().unwrap();
1235 assert_eq!(describe(&bytes).unwrap(), "FOR+BITPACK[10]");
1236 assert_eq!(decode(&bytes).unwrap(), values);
1237 }
1238
1239 #[test]
1240 fn every_candidate_that_applies_decodes_to_the_input() {
1241 let mut values = vec![5i64; 3000];
1245 for (index, value) in values.iter_mut().enumerate() {
1246 if index % 500 == 0 {
1247 *value = index as i64;
1248 }
1249 }
1250 let applicable = candidates(&values, 0);
1251 assert!(applicable.len() >= 4, "{applicable:?}");
1252 for kind in applicable {
1253 let bytes = encode_only(kind, &values).unwrap().unwrap();
1254 assert_eq!(decode(&bytes).unwrap(), values, "{}", kind.name());
1255 }
1256 }
1257
1258 #[test]
1263 fn every_kind_that_applies_decodes_to_what_it_was_given() {
1264 let shapes: Vec<Vec<i64>> = vec![
1265 Vec::new(),
1266 vec![5; 1024],
1267 vec![i64::MIN, i64::MAX, 0, -1],
1268 (0..1024).map(|at| at * 7).collect(),
1269 (0..1024).map(|at| at % 17).collect(),
1270 (0..1024).map(|at| if at % 100 == 0 { at } else { 3 }).collect(),
1271 (0..1024).map(|at| -at * 1_000_003).collect(),
1272 (0..1024_i64)
1273 .map(|at| {
1274 at.wrapping_mul(6_364_136_223_846_793_005)
1275 .wrapping_add(1_442_695_040_888_963_407)
1276 })
1277 .collect(),
1278 ];
1279 let kinds =
1280 [Kind::Constant, Kind::Packed, Kind::Delta, Kind::Rle, Kind::Dict, Kind::Sparse];
1281 for values in &shapes {
1282 for kind in kinds {
1283 let Some(bytes) = encode_only(kind, values).unwrap() else {
1284 continue;
1285 };
1286 assert_eq!(
1287 &decode(&bytes).unwrap(),
1288 values,
1289 "{} over {} values",
1290 kind.name(),
1291 values.len()
1292 );
1293 }
1294 }
1295 }
1296
1297 #[test]
1298 fn the_chooser_picks_the_smallest_candidate_rather_than_the_first_that_applies() {
1299 let mut values = vec![5i64; 3000];
1300 values[1500] = 9;
1301 let chosen = encode(&values).unwrap();
1302 for (_, size) in candidate_sizes(&values).unwrap() {
1303 assert!(chosen.len() <= size);
1304 }
1305 }
1306
1307 #[test]
1308 fn a_truncated_chunk_is_an_error_and_not_a_panic() {
1309 let bytes = encode(&[1, 2, 3, 4, 5]).unwrap();
1310 for len in 0..bytes.len() {
1311 let error = decode(&bytes[..len]).unwrap_err();
1312 assert!(error.message().contains("chunk"), "{error}");
1313 }
1314 }
1315
1316 #[test]
1317 fn trailing_bytes_are_an_error() {
1318 let mut bytes = encode(&[1, 2, 3]).unwrap();
1319 bytes.push(0);
1320 let error = decode(&bytes).unwrap_err();
1321 assert!(error.message().contains("left over"), "{error}");
1322 }
1323
1324 #[test]
1325 fn an_unknown_tag_is_an_error() {
1326 let error = decode(&[99, 0, 0, 0, 0]).unwrap_err();
1327 assert!(error.message().contains("unknown encoding tag"), "{error}");
1328 }
1329
1330 #[test]
1331 fn a_dictionary_code_outside_the_dictionary_is_an_error() {
1332 let mut bytes = vec![Kind::Dict.tag()];
1337 put_u32(&mut bytes, 1);
1338 bytes.extend_from_slice(&encode(&[10]).unwrap());
1339 bytes.extend_from_slice(&encode(&[5]).unwrap());
1340 let error = decode(&bytes).unwrap_err();
1341 assert!(error.message().contains("not in the dictionary"), "{error}");
1342 }
1343
1344 #[test]
1345 fn a_negative_run_length_is_an_error() {
1346 let mut bytes = vec![Kind::Rle.tag()];
1349 put_u32(&mut bytes, 4);
1350 bytes.extend_from_slice(&encode(&[7]).unwrap());
1351 bytes.extend_from_slice(&encode(&[-4]).unwrap());
1352 let error = decode(&bytes).unwrap_err();
1353 assert!(error.message().contains("negative"), "{error}");
1354 }
1355
1356 #[test]
1358 fn a_run_that_runs_past_its_chunk_is_an_error() {
1359 let mut bytes = vec![Kind::Rle.tag()];
1364 put_u32(&mut bytes, 4);
1365 bytes.extend_from_slice(&encode(&[7]).unwrap());
1366 bytes.extend_from_slice(&encode(&[9]).unwrap());
1367 let error = decode(&bytes).unwrap_err();
1368 assert!(error.message().contains("past its chunk"), "{error}");
1369 }
1370
1371 #[test]
1373 fn runs_shorter_and_longer_than_the_width_they_are_written_in_all_come_back() {
1374 let lengths = [1, 3, 7, 8, 9, 40, 2, 1];
1379 let mut values = Vec::new();
1380 for (at, length) in lengths.iter().enumerate() {
1381 let value = i64::try_from(at).expect("eight runs") * 1000 - 3;
1382 values.extend(std::iter::repeat_n(value, *length));
1383 }
1384 let bytes = encode(&values).expect("encodes");
1385 assert_eq!(decode(&bytes).expect("decodes"), values, "runs around the write width");
1386 let singles: Vec<i64> = (0..300).map(|index| index * 7 % 11).collect();
1389 let bytes = encode(&singles).expect("encodes");
1390 assert_eq!(decode(&bytes).expect("decodes"), singles, "no run longer than one");
1391 }
1392
1393 #[test]
1394 fn the_cascade_depth_is_bounded() {
1395 let values: Vec<i64> = (0..50_000).map(|index| (index / 100) % 250).collect();
1399 let bytes = round_trip(&values);
1400 let shape = describe(&bytes).unwrap();
1401 let depth = shape.matches('(').count();
1402 assert!(depth <= MAX_DEPTH as usize, "{shape} is {depth} deep");
1403 }
1404
1405 #[test]
1406 fn candidate_sizes_reports_what_the_chooser_looked_at() {
1407 let values: Vec<i64> = (0..5000).map(|index| index % 17).collect();
1408 let sizes = candidate_sizes(&values).unwrap();
1409 assert!(sizes.iter().any(|(kind, _)| *kind == Kind::Dict));
1410 assert!(sizes.iter().any(|(kind, _)| *kind == Kind::Packed));
1411 assert!(sizes.iter().all(|(_, size)| *size > 0));
1412 }
1413
1414 #[test]
1415 fn a_chunk_can_be_read_from_the_front_of_a_longer_buffer() {
1416 let first = encode(&[1, 2, 3]).unwrap();
1419 let second: Vec<i64> = (0..3000).map(|index| index % 11).collect();
1420 let second_bytes = encode(&second).unwrap();
1421 let mut joined = first.clone();
1422 joined.extend_from_slice(&second_bytes);
1423 joined.extend_from_slice(b"and then something else");
1424
1425 let (values, used) = decode_prefix(&joined).unwrap();
1426 assert_eq!(values, vec![1, 2, 3]);
1427 assert_eq!(used, first.len());
1428 let (more, used_again) = decode_prefix(&joined[used..]).unwrap();
1429 assert_eq!(more, second);
1430 assert_eq!(used_again, second_bytes.len());
1431
1432 let (text, described) = describe_prefix(&joined).unwrap();
1433 assert_eq!(described, first.len());
1434 assert_eq!(text, describe(&first).unwrap());
1435 }
1436
1437 #[test]
1438 fn a_truncated_chunk_is_still_an_error_when_read_as_a_prefix() {
1439 let bytes = encode(&(0..2000).collect::<Vec<i64>>()).unwrap();
1440 for len in 0..bytes.len() {
1441 assert!(decode_prefix(&bytes[..len]).is_err(), "{len} bytes decoded");
1442 }
1443 }
1444}