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_selected(bytes: &[u8], positions: &[usize]) -> Result<Vec<i64>> {
179 if positions.windows(2).any(|pair| pair[0] >= pair[1]) {
180 return Err(Error::internal("selected integer positions are not sorted and unique"));
181 }
182 let mut reader = Reader::new(bytes);
183 let values = with_decoding(|scratch| decode_selected_chunk(&mut reader, positions, scratch))?;
184 if reader.remaining() != 0 {
185 return Err(Error::internal(format!(
186 "{} bytes left over after decoding selected values",
187 reader.remaining()
188 )));
189 }
190 Ok(values)
191}
192
193pub fn decode_prefix(bytes: &[u8]) -> Result<(Vec<i64>, usize)> {
203 let mut reader = Reader::new(bytes);
204 let values = with_decoding(|scratch| decode_chunk(&mut reader, scratch))?;
205 Ok((values, reader.used()))
206}
207
208pub fn describe_prefix(bytes: &[u8]) -> Result<(String, usize)> {
214 let mut reader = Reader::new(bytes);
215 let text = describe_chunk(&mut reader)?;
216 Ok((text, reader.used()))
217}
218
219pub fn candidate_sizes(values: &[i64]) -> Result<Vec<(Kind, usize)>> {
226 let mut sizes = Vec::new();
227 for kind in candidates(values, 0, &EXHAUSTIVE) {
228 if let Some(bytes) = encode_as(kind, values, 0, &EXHAUSTIVE)? {
229 sizes.push((kind, bytes.len()));
230 }
231 }
232 Ok(sizes)
233}
234
235#[must_use]
242pub fn offered(values: &[i64]) -> Vec<Kind> {
243 candidates(values, 0, &EXHAUSTIVE)
244}
245
246pub fn encode_only(kind: Kind, values: &[i64]) -> Result<Option<Vec<u8>>> {
257 encode_as(kind, values, 0, &EXHAUSTIVE)
258}
259
260pub(crate) fn size_as(kind: Kind, values: &[i64], depth: u8) -> Result<Option<usize>> {
265 Ok(encode_as(kind, values, depth, &EXHAUSTIVE)?.map(|bytes| bytes.len()))
266}
267
268pub fn describe(bytes: &[u8]) -> Result<String> {
274 let mut reader = Reader::new(bytes);
275 describe_chunk(&mut reader)
276}
277
278fn encode_at(values: &[i64], depth: u8, chooser: &dyn Chooser) -> Result<Vec<u8>> {
279 let offered = candidates(values, depth, chooser);
280 let mut best: Option<Vec<u8>> = None;
281 for kind in chooser.narrow_integers(values, &offered, depth) {
282 let Some(bytes) = encode_as(kind, values, depth, chooser)? else {
283 continue;
284 };
285 if best.as_ref().is_none_or(|current| bytes.len() < current.len()) {
286 best = Some(bytes);
287 }
288 }
289 best.ok_or_else(|| Error::internal("no encoding applied to the chunk"))
292}
293
294fn candidates(values: &[i64], depth: u8, chooser: &dyn Chooser) -> Vec<Kind> {
305 let mut kinds = vec![Kind::Packed];
306 if depth >= MAX_DEPTH || values.is_empty() {
307 return kinds;
308 }
309 if values.iter().all(|value| *value == values[0]) {
310 return vec![Kind::Constant];
312 }
313 let considered = |kind| chooser.considers_integer(kind, depth);
314 if considered(Kind::Delta) && values.len() >= 2 && deltas_fit(values) {
315 kinds.push(Kind::Delta);
316 }
317 if considered(Kind::Rle) && run_count(values) * 4 <= values.len() * 3 {
318 kinds.push(Kind::Rle);
319 }
320 if considered(Kind::Dict) && spread_of(values).0 * 2 <= values.len() {
321 kinds.push(Kind::Dict);
322 }
323 if considered(Kind::Sparse)
324 && majority(values).is_some_and(|(_, count)| count * 10 >= values.len() * 8)
325 {
326 kinds.push(Kind::Sparse);
327 }
328 if considered(Kind::Strided) && stride_of(values).is_some() {
329 kinds.push(Kind::Strided);
330 }
331 kinds
332}
333
334fn encode_as(
337 kind: Kind,
338 values: &[i64],
339 depth: u8,
340 chooser: &dyn Chooser,
341) -> Result<Option<Vec<u8>>> {
342 let mut out = Vec::new();
343 put_u8(&mut out, kind.tag());
344 put_u32(&mut out, u32::try_from(values.len()).map_err(|_| too_long(values.len()))?);
345 match kind {
346 Kind::Constant => {
347 let Some(first) = values.first() else {
348 return Ok(None);
349 };
350 if values.iter().any(|value| value != first) {
351 return Ok(None);
352 }
353 put_i64(&mut out, *first);
354 }
355 Kind::Packed => encode_packed(values, &mut out)?,
356 Kind::Delta => {
357 let (Some(first), Some(deltas)) = (values.first(), deltas(values)) else {
361 return Ok(None);
362 };
363 put_i64(&mut out, *first);
364 out.extend_from_slice(&encode_at(&deltas, depth + 1, chooser)?);
365 }
366 Kind::Rle => {
367 let (run_values, run_lengths) = runs(values);
368 if run_values.is_empty() {
369 return Ok(None);
370 }
371 out.extend_from_slice(&encode_at(&run_values, depth + 1, chooser)?);
372 out.extend_from_slice(&encode_at(&run_lengths, depth + 1, chooser)?);
373 }
374 Kind::Dict => {
375 let dictionary = distinct_values(values);
376 if dictionary.is_empty() {
377 return Ok(None);
378 }
379 let codes = codes_over(values, &dictionary);
380 out.extend_from_slice(&encode_at(&dictionary, depth + 1, chooser)?);
381 out.extend_from_slice(&encode_at(&codes, depth + 1, chooser)?);
382 }
383 Kind::Sparse => {
384 let Some((value, _)) = majority(values).or_else(|| spread_of(values).1) else {
388 return Ok(None);
389 };
390 let mut positions = Vec::new();
391 let mut exceptions = Vec::new();
392 for (index, other) in values.iter().enumerate() {
393 if *other != value {
394 positions.push(index as i64);
395 exceptions.push(*other);
396 }
397 }
398 put_i64(&mut out, value);
399 put_u32(
400 &mut out,
401 u32::try_from(positions.len()).map_err(|_| too_long(positions.len()))?,
402 );
403 out.extend_from_slice(&encode_at(&positions, depth + 1, chooser)?);
404 out.extend_from_slice(&encode_at(&exceptions, depth + 1, chooser)?);
405 }
406 Kind::Strided => {
407 let (Some(base), Some(stride)) = (values.iter().min().copied(), stride_of(values))
408 else {
409 return Ok(None);
410 };
411 let mut steps = Vec::with_capacity(values.len());
412 for value in values {
413 let step = offset_from(*value, base) / stride;
414 let Ok(step) = i64::try_from(step) else {
419 return Ok(None);
420 };
421 steps.push(step);
422 }
423 put_i64(&mut out, base);
424 put_u64(&mut out, stride);
425 out.extend_from_slice(&encode_at(&steps, depth + 1, chooser)?);
426 }
427 }
428 Ok(Some(out))
429}
430
431fn encode_packed(values: &[i64], out: &mut Vec<u8>) -> Result<()> {
443 let mut offsets: Vec<u64> = Vec::with_capacity(VALUES);
447 let mut packed: Vec<u64> = vec![0; bitpack::packed_len::<u64>(64)];
450 let mut transposed = bitpack::Scratch::<u64>::new();
451 for unit in values.chunks(VALUES) {
452 let base = unit.iter().copied().min().unwrap_or(0);
453 offsets.clear();
454 offsets.extend(unit.iter().map(|value| offset_from(*value, base)));
455 let width = bitpack::required_width(&offsets);
456 put_i64(out, base);
457 put_u8(out, u8::try_from(width).map_err(|_| Error::internal("impossible width"))?);
458 if unit.len() == VALUES {
459 let words = bitpack::packed_len::<u64>(width);
460 bitpack::pack_with(&offsets, width, &mut packed[..words], &mut transposed)?;
461 for word in &packed[..words] {
462 put_u64(out, *word);
463 }
464 } else {
465 bitpack::pack_tail(&offsets, width, out)?;
466 }
467 }
468 Ok(())
469}
470
471struct Decoding {
498 packed: Vec<u64>,
501}
502
503thread_local! {
504 static DECODING: std::cell::RefCell<Decoding> =
506 const { std::cell::RefCell::new(Decoding::new()) };
507}
508
509fn with_decoding<T>(run: impl FnOnce(&mut Decoding) -> T) -> T {
516 DECODING.with(|cell| match cell.try_borrow_mut() {
517 Ok(mut scratch) => run(&mut scratch),
518 Err(_) => run(&mut Decoding::new()),
519 })
520}
521
522impl Decoding {
523 const fn new() -> Self {
525 Self { packed: Vec::new() }
526 }
527
528 fn ready(&mut self) {
530 if self.packed.len() != bitpack::packed_len::<u64>(64) {
531 self.packed.resize(bitpack::packed_len::<u64>(64), 0);
532 }
533 }
534}
535
536fn decode_chunk(reader: &mut Reader<'_>, scratch: &mut Decoding) -> Result<Vec<i64>> {
537 let kind = Kind::from_tag(reader.u8()?)?;
538 let count = reader.u32()? as usize;
539 match kind {
540 Kind::Constant => Ok(vec![reader.i64()?; count]),
541 Kind::Packed => {
542 let mut values = vec![0i64; count];
546 scratch.ready();
547 let mut done = 0;
548 while done < count {
549 let base = reader.i64()?;
550 let width = reader.u8()? as usize;
551 let wanted = (count - done).min(VALUES);
552 let into = &mut values[done..done + wanted];
553 if wanted == VALUES {
554 let words = bitpack::packed_len::<u64>(width);
555 for word in &mut scratch.packed[..words] {
556 *word = reader.u64()?;
557 }
558 bitpack::unpack_mapped(&scratch.packed[..words], width, into, |offset| {
559 value_from(offset, base)
560 })?;
561 } else {
562 let bytes = reader.bytes(bitpack::tail_len(wanted, width))?;
563 bitpack::unpack_tail_into(bytes, width, into, |offset| {
564 value_from(offset, base)
565 })?;
566 }
567 done += wanted;
568 }
569 Ok(values)
570 }
571 Kind::Delta => {
572 let first = reader.i64()?;
573 let deltas = decode_chunk(reader, scratch)?;
574 let mut values = Vec::with_capacity(count);
575 values.push(first);
576 let mut current = first;
577 for delta in deltas {
578 current = current.wrapping_add(unzigzag(delta as u64));
579 values.push(current);
580 }
581 check_count(values.len(), count)?;
582 Ok(values)
583 }
584 Kind::Rle => {
585 let run_values = decode_chunk(reader, scratch)?;
586 let run_lengths = decode_chunk(reader, scratch)?;
587 if run_values.len() != run_lengths.len() {
588 return Err(Error::internal("an RLE chunk has more runs than run lengths"));
589 }
590 let mut values = vec![0; count + RUN];
593 let mut at = 0usize;
594 for (value, length) in run_values.into_iter().zip(run_lengths) {
595 let length = usize::try_from(length)
596 .map_err(|_| Error::internal("a negative RLE run length"))?;
597 let end = at
598 .checked_add(length)
599 .filter(|end| *end <= count)
600 .ok_or_else(|| Error::internal("an RLE run ends past its chunk"))?;
601 let short =
602 if length <= RUN { values[at..].first_chunk_mut::<RUN>() } else { None };
603 match short {
604 Some(window) => window.fill(value),
605 None => values[at..end].fill(value),
606 }
607 at = end;
608 }
609 check_count(at, count)?;
610 values.truncate(count);
611 Ok(values)
612 }
613 Kind::Dict => {
614 let dictionary = decode_chunk(reader, scratch)?;
615 let codes = decode_chunk(reader, scratch)?;
616 let mut values = Vec::with_capacity(count);
617 for code in codes {
618 let index =
619 usize::try_from(code).ok().and_then(|index| dictionary.get(index)).ok_or_else(
620 || Error::internal(format!("code {code} is not in the dictionary")),
621 )?;
622 values.push(*index);
623 }
624 check_count(values.len(), count)?;
625 Ok(values)
626 }
627 Kind::Sparse => {
628 let value = reader.i64()?;
629 let exception_count = reader.u32()? as usize;
630 let positions = decode_chunk(reader, scratch)?;
631 let exceptions = decode_chunk(reader, scratch)?;
632 if positions.len() != exception_count || exceptions.len() != exception_count {
633 return Err(Error::internal("a sparse chunk disagrees about its exception count"));
634 }
635 let mut values = vec![value; count];
636 for (position, exception) in positions.into_iter().zip(exceptions) {
637 let position = usize::try_from(position)
638 .ok()
639 .filter(|position| *position < count)
640 .ok_or_else(|| {
641 Error::internal(format!("exception at {position} is outside the chunk"))
642 })?;
643 values[position] = exception;
644 }
645 Ok(values)
646 }
647 Kind::Strided => {
648 let base = reader.i64()?;
649 let stride = reader.u64()?;
650 let steps = decode_chunk(reader, scratch)?;
651 check_count(steps.len(), count)?;
652 let mut values = Vec::with_capacity(count);
653 for step in steps {
654 let step = u64::try_from(step)
655 .map_err(|_| Error::internal("a negative number of strides"))?;
656 values.push(value_from(step.wrapping_mul(stride), base));
657 }
658 Ok(values)
659 }
660 }
661}
662
663fn decode_selected_chunk(
664 reader: &mut Reader<'_>,
665 positions: &[usize],
666 scratch: &mut Decoding,
667) -> Result<Vec<i64>> {
668 let Some(&tag) = reader.rest().first() else {
669 return Err(Error::internal("a chunk ended before its encoding tag"));
670 };
671 let kind = Kind::from_tag(tag)?;
672 if !matches!(kind, Kind::Constant | Kind::Packed | Kind::Rle) {
673 let values = decode_chunk(reader, scratch)?;
674 return positions
675 .iter()
676 .map(|&position| {
677 values.get(position).copied().ok_or_else(|| {
678 Error::internal(format!(
679 "selected integer position {position} is outside {} values",
680 values.len()
681 ))
682 })
683 })
684 .collect();
685 }
686
687 let decoded = Kind::from_tag(reader.u8()?)?;
688 debug_assert_eq!(decoded, kind);
689 let count = reader.u32()? as usize;
690 if positions.last().is_some_and(|&position| position >= count) {
691 return Err(Error::internal(format!(
692 "selected integer position {} is outside {count} values",
693 positions.last().expect("a last position exists")
694 )));
695 }
696 match kind {
697 Kind::Constant => {
698 let value = reader.i64()?;
699 Ok(vec![value; positions.len()])
700 }
701 Kind::Packed => {
702 let mut out = Vec::with_capacity(positions.len());
703 let mut from = 0;
704 let mut done = 0;
705 while done < count {
706 let base = reader.i64()?;
707 let width = reader.u8()? as usize;
708 let wanted = (count - done).min(VALUES);
709 let upto = positions.partition_point(|&position| position < done + wanted);
710 if wanted == VALUES {
711 let bytes = reader.bytes(bitpack::packed_len::<u64>(width) * 8)?;
712 for &position in &positions[from..upto] {
713 let offset = bitpack::unpack_u64_at(bytes, width, position - done)?;
714 out.push(value_from(offset, base));
715 }
716 } else {
717 let bytes = reader.bytes(bitpack::tail_len(wanted, width))?;
718 for &position in &positions[from..upto] {
719 let offset = bitpack::tail_at(bytes, width, position - done)?;
720 out.push(value_from(offset, base));
721 }
722 }
723 from = upto;
724 done += wanted;
725 }
726 Ok(out)
727 }
728 Kind::Rle => {
729 let run_value_bytes = reader.rest();
730 let mut run_value_reader = Reader::new(run_value_bytes);
731 let run_value_count = skip_chunk(&mut run_value_reader)?;
732 let run_value_len = run_value_reader.used();
733 reader.skip(run_value_len)?;
734 let run_lengths = decode_chunk(reader, scratch)?;
735 if run_value_count != run_lengths.len() {
736 return Err(Error::internal("an RLE chunk has more runs than run lengths"));
737 }
738 let mut wanted_runs = Vec::new();
739 let mut selected_per_run = Vec::new();
740 let mut selected = 0;
741 let mut at = 0usize;
742 for (run, length) in run_lengths.into_iter().enumerate() {
743 let length = usize::try_from(length)
744 .map_err(|_| Error::internal("a negative RLE run length"))?;
745 let end = at
746 .checked_add(length)
747 .filter(|end| *end <= count)
748 .ok_or_else(|| Error::internal("an RLE run ends past its chunk"))?;
749 let before = selected;
750 while selected < positions.len() && positions[selected] < end {
751 if positions[selected] < at {
752 return Err(Error::internal("selected integer positions went backwards"));
753 }
754 selected += 1;
755 }
756 if selected != before {
757 wanted_runs.push(run);
758 selected_per_run.push(selected - before);
759 }
760 at = end;
761 }
762 check_count(at, count)?;
763 if selected != positions.len() {
764 return Err(Error::internal("an RLE chunk ended before a selected position"));
765 }
766 let run_values = decode_selected(&run_value_bytes[..run_value_len], &wanted_runs)?;
767 let mut out = Vec::with_capacity(positions.len());
768 for (value, repeat) in run_values.into_iter().zip(selected_per_run) {
769 out.extend(std::iter::repeat_n(value, repeat));
770 }
771 Ok(out)
772 }
773 _ => unreachable!("unsupported kinds used the full decoder"),
774 }
775}
776
777fn skip_chunk(reader: &mut Reader<'_>) -> Result<usize> {
779 let kind = Kind::from_tag(reader.u8()?)?;
780 let count = reader.u32()? as usize;
781 match kind {
782 Kind::Constant => reader.skip(8)?,
783 Kind::Packed => {
784 let mut done = 0;
785 while done < count {
786 reader.skip(8)?;
787 let width = reader.u8()? as usize;
788 if width > 64 {
789 return Err(Error::internal(format!(
790 "a packed integer width of {width} is past 64"
791 )));
792 }
793 let wanted = (count - done).min(VALUES);
794 let bytes = if wanted == VALUES {
795 bitpack::packed_len::<u64>(width)
796 .checked_mul(8)
797 .ok_or_else(|| Error::internal("packed integer size overflow"))?
798 } else {
799 bitpack::tail_len(wanted, width)
800 };
801 reader.skip(bytes)?;
802 done += wanted;
803 }
804 }
805 Kind::Delta => {
806 reader.skip(8)?;
807 skip_chunk(reader)?;
808 }
809 Kind::Rle | Kind::Dict => {
810 skip_chunk(reader)?;
811 skip_chunk(reader)?;
812 }
813 Kind::Sparse => {
814 reader.skip(12)?;
815 skip_chunk(reader)?;
816 skip_chunk(reader)?;
817 }
818 Kind::Strided => {
819 reader.skip(16)?;
820 skip_chunk(reader)?;
821 }
822 }
823 Ok(count)
824}
825
826fn describe_chunk(reader: &mut Reader<'_>) -> Result<String> {
827 let kind = Kind::from_tag(reader.u8()?)?;
828 let count = reader.u32()? as usize;
829 Ok(match kind {
830 Kind::Constant => {
831 reader.i64()?;
832 "CONSTANT".to_string()
833 }
834 Kind::Packed => {
835 let mut widths = Vec::new();
836 let mut seen = 0;
837 while seen < count {
838 reader.i64()?;
839 let width = reader.u8()? as usize;
840 let wanted = (count - seen).min(VALUES);
841 if wanted == VALUES {
842 for _ in 0..bitpack::packed_len::<u64>(width) {
843 reader.u64()?;
844 }
845 } else {
846 reader.bytes(bitpack::tail_len(wanted, width))?;
847 }
848 widths.push(width);
849 seen += wanted;
850 }
851 let low = widths.iter().copied().min().unwrap_or(0);
852 let high = widths.iter().copied().max().unwrap_or(0);
853 if low == high {
856 format!("FOR+BITPACK[{low}]")
857 } else {
858 format!("FOR+BITPACK[{low}..{high}]")
859 }
860 }
861 Kind::Delta => {
862 reader.i64()?;
863 format!("DELTA({})", describe_chunk(reader)?)
864 }
865 Kind::Rle => {
866 let values = describe_chunk(reader)?;
867 let lengths = describe_chunk(reader)?;
868 format!("RLE({values}, {lengths})")
869 }
870 Kind::Dict => {
871 let dictionary = describe_chunk(reader)?;
872 let codes = describe_chunk(reader)?;
873 format!("DICT({dictionary}, {codes})")
874 }
875 Kind::Sparse => {
876 reader.i64()?;
877 reader.u32()?;
878 let positions = describe_chunk(reader)?;
879 let exceptions = describe_chunk(reader)?;
880 format!("SPARSE({positions}, {exceptions})")
881 }
882 Kind::Strided => {
883 reader.i64()?;
884 let stride = reader.u64()?;
885 format!("STRIDE[{stride}]({})", describe_chunk(reader)?)
886 }
887 })
888}
889
890fn stride_of(values: &[i64]) -> Option<u64> {
902 let base = values.iter().min().copied()?;
903 let mut divisor = 0u64;
904 for value in values {
905 divisor = gcd(divisor, offset_from(*value, base));
906 if divisor == 1 {
907 return None;
908 }
909 }
910 (divisor > 1).then_some(divisor)
913}
914
915fn gcd(mut left: u64, mut right: u64) -> u64 {
917 if left == 0 {
918 return right;
919 }
920 if right == 0 {
921 return left;
922 }
923 let shift = (left | right).trailing_zeros();
924 left >>= left.trailing_zeros();
925 loop {
926 right >>= right.trailing_zeros();
927 if left > right {
928 std::mem::swap(&mut left, &mut right);
929 }
930 right -= left;
931 if right == 0 {
932 return left << shift;
933 }
934 }
935}
936
937fn offset_from(value: i64, base: i64) -> u64 {
940 (i128::from(value) - i128::from(base)) as u64
941}
942
943fn value_from(offset: u64, base: i64) -> i64 {
944 (i128::from(base) + i128::from(offset)) as i64
945}
946
947fn zigzag(value: i64) -> u64 {
950 ((value << 1) ^ (value >> 63)) as u64
951}
952
953fn unzigzag(value: u64) -> i64 {
954 ((value >> 1) as i64) ^ -((value & 1) as i64)
955}
956
957fn deltas_fit(values: &[i64]) -> bool {
969 values.windows(2).all(|pair| i64::try_from(i128::from(pair[1]) - i128::from(pair[0])).is_ok())
970}
971
972fn deltas(values: &[i64]) -> Option<Vec<i64>> {
973 let mut deltas = Vec::with_capacity(values.len().saturating_sub(1));
974 for pair in values.windows(2) {
975 let difference = i128::from(pair[1]) - i128::from(pair[0]);
976 let difference = i64::try_from(difference).ok()?;
977 deltas.push(zigzag(difference) as i64);
978 }
979 Some(deltas)
980}
981
982fn run_count(values: &[i64]) -> usize {
983 let mut runs = 0;
984 let mut previous = None;
985 for value in values {
986 if previous != Some(value) {
987 runs += 1;
988 previous = Some(value);
989 }
990 }
991 runs
992}
993
994fn runs(values: &[i64]) -> (Vec<i64>, Vec<i64>) {
995 let mut run_values: Vec<i64> = Vec::new();
996 let mut run_lengths: Vec<i64> = Vec::new();
997 for value in values {
998 if run_values.last() == Some(value) {
999 *run_lengths.last_mut().expect("a run length exists beside every run value") += 1;
1000 } else {
1001 run_values.push(*value);
1002 run_lengths.push(1);
1003 }
1004 }
1005 (run_values, run_lengths)
1006}
1007
1008fn spread_of(values: &[i64]) -> (usize, Option<(i64, usize)>) {
1023 let mut sorted = values.to_vec();
1024 sorted.sort_unstable();
1025 let mut distinct = 0;
1026 let mut best: Option<(i64, usize)> = None;
1027 let mut index = 0;
1028 while index < sorted.len() {
1029 let value = sorted[index];
1030 let mut end = index;
1031 while end < sorted.len() && sorted[end] == value {
1032 end += 1;
1033 }
1034 distinct += 1;
1035 let count = end - index;
1036 if best.is_none_or(|(_, seen)| count > seen) {
1037 best = Some((value, count));
1038 }
1039 index = end;
1040 }
1041 (distinct, best)
1042}
1043
1044fn majority(values: &[i64]) -> Option<(i64, usize)> {
1052 let mut candidate = *values.first()?;
1053 let mut lead = 0usize;
1054 for value in values {
1055 if lead == 0 {
1056 candidate = *value;
1057 lead = 1;
1058 } else if *value == candidate {
1059 lead += 1;
1060 } else {
1061 lead -= 1;
1062 }
1063 }
1064 let count = values.iter().filter(|value| **value == candidate).count();
1065 (count * 2 > values.len()).then_some((candidate, count))
1066}
1067
1068fn distinct_values(values: &[i64]) -> Vec<i64> {
1071 let mut distinct = values.to_vec();
1072 distinct.sort_unstable();
1073 distinct.dedup();
1074 distinct
1075}
1076
1077fn codes_over(values: &[i64], dictionary: &[i64]) -> Vec<i64> {
1087 values
1088 .iter()
1089 .map(|value| {
1090 dictionary
1091 .binary_search(value)
1092 .expect("the dictionary is the distinct values of this chunk") as i64
1093 })
1094 .collect()
1095}
1096
1097fn check_count(actual: usize, expected: usize) -> Result<()> {
1098 if actual == expected {
1099 Ok(())
1100 } else {
1101 Err(Error::internal(format!(
1102 "a chunk says it holds {expected} values and decoded to {actual}"
1103 )))
1104 }
1105}
1106
1107fn too_long(len: usize) -> Error {
1108 Error::internal(format!("a chunk of {len} values is longer than the format allows"))
1109}
1110
1111fn put_u8(out: &mut Vec<u8>, value: u8) {
1112 out.push(value);
1113}
1114
1115fn put_u32(out: &mut Vec<u8>, value: u32) {
1116 out.extend_from_slice(&value.to_le_bytes());
1117}
1118
1119fn put_u64(out: &mut Vec<u8>, value: u64) {
1120 out.extend_from_slice(&value.to_le_bytes());
1121}
1122
1123fn put_i64(out: &mut Vec<u8>, value: i64) {
1124 out.extend_from_slice(&value.to_le_bytes());
1125}
1126
1127#[cfg(test)]
1128mod tests {
1129 use super::*;
1130
1131 fn round_trip(values: &[i64]) -> Vec<u8> {
1132 let bytes = encode(values).unwrap();
1133 assert_eq!(decode(&bytes).unwrap(), values, "{}", describe(&bytes).unwrap());
1134 bytes
1135 }
1136
1137 fn kind_of(bytes: &[u8]) -> Kind {
1138 Kind::from_tag(bytes[0]).unwrap()
1139 }
1140
1141 struct Random(u64);
1143
1144 impl Random {
1145 fn new() -> Self {
1146 Self(0x9e37_79b9_7f4a_7c15)
1147 }
1148
1149 fn next(&mut self) -> u64 {
1150 self.0 ^= self.0 << 13;
1151 self.0 ^= self.0 >> 7;
1152 self.0 ^= self.0 << 17;
1153 self.0
1154 }
1155 }
1156
1157 #[test]
1158 fn the_dictionary_is_sorted_and_the_codes_point_back_at_the_values() {
1159 let values = vec![30i64, 10, 30, 20, 10, -5];
1160 let dictionary = distinct_values(&values);
1161 let codes = codes_over(&values, &dictionary);
1162 assert_eq!(dictionary, vec![-5, 10, 20, 30]);
1163 assert_eq!(codes, vec![3, 1, 3, 2, 1, 0]);
1164 for (code, value) in codes.iter().zip(&values) {
1165 assert_eq!(dictionary[*code as usize], *value);
1166 }
1167 }
1168
1169 #[test]
1170 fn one_sort_gives_the_distinct_count_and_the_most_frequent_value() {
1171 let values = vec![7i64, 7, 7, 1, 2, 2];
1172 assert_eq!(spread_of(&values), (3, Some((7, 3))));
1173 assert_eq!(spread_of(&[]), (0, None));
1174 assert_eq!(spread_of(&[9]), (1, Some((9, 1))));
1175
1176 assert_eq!(spread_of(&[4i64, 4, 8, 8]), (2, Some((4, 2))));
1179 }
1180
1181 #[test]
1182 fn the_majority_is_the_most_frequent_value_whenever_there_is_one() {
1183 let chunks: Vec<Vec<i64>> = vec![
1184 vec![],
1185 vec![3],
1186 vec![1, 2],
1187 vec![1, 1, 2],
1188 vec![2, 1, 1],
1189 vec![4, 4, 8, 8],
1190 vec![7, 1, 7, 2, 7, 3, 7],
1191 vec![1, 2, 3, 9, 9, 9, 9],
1192 (0..1000).map(|index| if index % 5 == 0 { index } else { -4 }).collect(),
1193 (0..1000).map(|index| index % 3).collect(),
1194 ];
1195 for chunk in chunks {
1196 let (_, dominant) = spread_of(&chunk);
1197 let expected = dominant.filter(|(_, count)| count * 2 > chunk.len());
1198 assert_eq!(majority(&chunk), expected, "{chunk:?}");
1199 }
1200 }
1201
1202 #[test]
1203 fn deltas_that_do_not_fit_are_refused_before_they_are_built() {
1204 assert!(deltas_fit(&[1i64, 2, 3]));
1205 assert!(deltas_fit(&[i64::MAX, i64::MAX]));
1206 assert!(!deltas_fit(&[i64::MIN, i64::MAX]));
1207 assert_eq!(deltas_fit(&[i64::MIN, i64::MAX]), deltas(&[i64::MIN, i64::MAX]).is_some());
1208 assert_eq!(deltas_fit(&[1i64, 2, 3]), deltas(&[1i64, 2, 3]).is_some());
1209 }
1210
1211 #[test]
1212 fn what_the_chooser_returns_is_the_smallest_of_what_it_was_offered() {
1213 let mut random = Random::new();
1217 let noise: Vec<i64> = (0..2000).map(|_| (random.next() % 5000) as i64).collect();
1218 let runs: Vec<i64> = (0..2000).map(|index: i64| index / 100).collect();
1219 let climbing: Vec<i64> = (0..2000).map(|index| 1_700_000_000 + index).collect();
1220 for values in [noise, runs, climbing, vec![7; 300], Vec::new()] {
1221 let chosen = encode(&values).unwrap();
1222 let mut smallest: Option<Vec<u8>> = None;
1223 for kind in offered(&values) {
1224 let Some(bytes) = encode_only(kind, &values).unwrap() else {
1225 continue;
1226 };
1227 if smallest.as_ref().is_none_or(|best| bytes.len() < best.len()) {
1228 smallest = Some(bytes);
1229 }
1230 }
1231 assert_eq!(smallest.as_deref(), Some(chosen.as_slice()), "{}", values.len());
1232 }
1233 }
1234
1235 #[test]
1236 fn a_column_of_whole_seconds_in_microseconds_pays_nothing_for_the_zeroes() {
1237 let mut random = Random::new();
1241 let day = 1_374_000_000_000_000i64;
1242 let values: Vec<i64> =
1243 (0..100_000).map(|_| day + (random.next() % 68_400) as i64 * 1_000_000).collect();
1244 let bytes = round_trip(&values);
1245 assert_eq!(kind_of(&bytes), Kind::Strided);
1246 assert!(describe(&bytes).unwrap().starts_with("STRIDE[1000000]"), "{:?}", describe(&bytes));
1247 let strided = 100_000 * 17 / 8;
1249 assert!(bytes.len() < strided + 2000, "{} bytes for {strided} of payload", bytes.len());
1250
1251 let plain = encode_only(Kind::Packed, &values).unwrap().expect("packing always applies");
1252 assert!(
1253 bytes.len() * 2 < plain.len(),
1254 "{} strided against {} packed",
1255 bytes.len(),
1256 plain.len()
1257 );
1258 }
1259
1260 #[test]
1261 fn a_stride_is_the_common_factor_of_the_distances_from_the_smallest_value() {
1262 assert_eq!(stride_of(&[10i64, 20, 40]), Some(10));
1263 assert_eq!(stride_of(&[7i64, 17, 37]), Some(10));
1266 assert_eq!(stride_of(&[10i64, 20, 23]), None);
1267 assert_eq!(stride_of(&[5i64; 100]), None);
1270 assert_eq!(stride_of(&[]), None);
1271 assert_eq!(stride_of(&[i64::MIN, i64::MAX]), Some(u64::MAX));
1273 }
1274
1275 #[test]
1276 fn a_stride_across_the_whole_of_the_type_round_trips() {
1277 for values in [vec![i64::MIN, i64::MAX], vec![i64::MIN, 0, i64::MAX]] {
1280 let bytes = round_trip(&values);
1281 assert_eq!(decode(&bytes).unwrap(), values);
1282 }
1283 }
1284
1285 #[test]
1286 fn a_column_with_no_common_factor_is_not_offered_a_stride() {
1287 let mut random = Random::new();
1288 let values: Vec<i64> = (0..2000).map(|_| (random.next() % 1_000_000) as i64).collect();
1289 assert!(!offered(&values).contains(&Kind::Strided));
1290 assert!(encode_only(Kind::Strided, &values).unwrap().is_none());
1291 }
1292
1293 #[test]
1294 fn an_empty_chunk_round_trips() {
1295 let bytes = round_trip(&[]);
1296 assert_eq!(bytes.len(), 5);
1297 }
1298
1299 #[test]
1300 fn a_constant_column_costs_thirteen_bytes_however_long_it_is() {
1301 let bytes = round_trip(&vec![42; 1_000_000]);
1302 assert_eq!(kind_of(&bytes), Kind::Constant);
1303 assert_eq!(bytes.len(), 13);
1304 }
1305
1306 #[test]
1307 fn a_narrow_range_is_packed_at_the_width_of_the_range_and_not_of_the_type() {
1308 let mut random = Random::new();
1310 let values: Vec<i64> = (0..100_000).map(|_| 1000 + (random.next() % 64) as i64).collect();
1311 let bytes = round_trip(&values);
1312 assert_eq!(kind_of(&bytes), Kind::Packed);
1313 let packed = 100_000 * 6 / 8;
1314 assert!(bytes.len() < packed + 2000, "{} bytes for {packed} of payload", bytes.len());
1315 assert!(bytes.len() > packed, "{} bytes cannot hold {packed}", bytes.len());
1316 }
1317
1318 #[test]
1319 fn a_counter_becomes_deltas_and_then_a_constant() {
1320 let values: Vec<i64> = (0..1_000_000).collect();
1323 let bytes = round_trip(&values);
1324 assert_eq!(kind_of(&bytes), Kind::Delta);
1325 assert_eq!(describe(&bytes).unwrap(), "DELTA(CONSTANT)");
1326 assert!(bytes.len() < 40, "{} bytes for a counter", bytes.len());
1327 }
1328
1329 #[test]
1330 fn a_column_that_counts_down_is_as_cheap_as_one_that_counts_up() {
1331 let up: Vec<i64> = (0..100_000).collect();
1333 let down: Vec<i64> = (0..100_000).rev().collect();
1334 assert_eq!(round_trip(&up).len(), round_trip(&down).len());
1335 }
1336
1337 #[test]
1338 fn long_runs_become_rle() {
1339 let mut values = Vec::new();
1340 for run in 0..1000 {
1341 values.extend(std::iter::repeat_n(run % 7, 200));
1342 }
1343 let bytes = round_trip(&values);
1344 assert_eq!(kind_of(&bytes), Kind::Rle);
1345 assert!(bytes.len() < 2000, "{} bytes for 1000 runs", bytes.len());
1346 }
1347
1348 #[test]
1349 fn a_low_cardinality_column_becomes_a_dictionary() {
1350 let mut random = Random::new();
1356 let dictionary: Vec<i64> =
1357 (0..40).map(|_| 1_000_000_000 + (random.next() % (1 << 30)) as i64).collect();
1358 let values: Vec<i64> =
1359 (0..100_000).map(|_| dictionary[(random.next() % 40) as usize]).collect();
1360 let bytes = round_trip(&values);
1361 assert_eq!(kind_of(&bytes), Kind::Dict);
1362 assert!(bytes.len() < 100_000, "{} bytes", bytes.len());
1363 }
1364
1365 #[test]
1366 fn a_nearly_constant_column_becomes_sparse() {
1367 let mut values = vec![0i64; 100_000];
1368 for index in 0..300 {
1369 values[index * 331] = 1 << 40;
1370 }
1371 let bytes = round_trip(&values);
1372 assert_eq!(kind_of(&bytes), Kind::Sparse);
1373 assert!(bytes.len() < 3000, "{} bytes for 300 exceptions", bytes.len());
1374 }
1375
1376 #[test]
1377 fn the_cascade_goes_more_than_one_level_deep() {
1378 let mut values = Vec::new();
1381 for index in 0..2000i64 {
1382 values.extend(std::iter::repeat_n(1_000_000 + (index % 5) * 104_729, 100));
1383 }
1384 let bytes = round_trip(&values);
1385 let shape = describe(&bytes).unwrap();
1386 assert!(shape.contains('('), "{shape} is not a cascade");
1387 assert!(bytes.len() < 4000, "{} bytes: {shape}", bytes.len());
1388 }
1389
1390 #[test]
1391 fn random_data_is_packed_at_full_width_and_costs_what_it_costs() {
1392 let mut random = Random::new();
1395 let values: Vec<i64> = (0..10_000).map(|_| random.next() as i64).collect();
1396 let bytes = round_trip(&values);
1397 assert_eq!(kind_of(&bytes), Kind::Packed);
1398 assert!(bytes.len() < 10_000 * 8 + 1000, "{} bytes", bytes.len());
1399 }
1400
1401 #[test]
1402 fn the_extremes_of_the_type_survive() {
1403 let values = vec![i64::MIN, i64::MAX, 0, -1, i64::MIN, i64::MAX];
1406 round_trip(&values);
1407 round_trip(&[i64::MIN; 3]);
1408 round_trip(&[i64::MIN, i64::MIN + 1]);
1409 }
1410
1411 #[test]
1412 fn a_chunk_that_is_not_a_multiple_of_the_unit_round_trips() {
1413 for len in [1, 2, 1023, 1024, 1025, 2047, 2049] {
1414 let values: Vec<i64> = (0..len).map(|index| (index * 31 % 97) as i64).collect();
1415 round_trip(&values);
1416 }
1417 }
1418
1419 #[test]
1420 fn units_of_different_widths_in_one_chunk_do_not_read_each_others_leftovers() {
1421 let mut random = Random::new();
1433 let mut values = Vec::new();
1434 for width in [40u32, 3, 61, 1, 17, 40] {
1435 for _ in 0..1024 {
1436 values.push((random.next() & ((1u64 << width) - 1)) as i64);
1437 }
1438 }
1439 let bytes = encode(&values).unwrap();
1440 let described = describe(&bytes).unwrap();
1441 assert!(described.starts_with("FOR+BITPACK"), "expected one packed chunk, got {described}");
1442 assert_eq!(decode(&bytes).unwrap(), values, "{described}");
1443 }
1444
1445 #[test]
1446 fn a_cascade_decodes_the_same_through_a_shared_scratch_as_through_its_own() {
1447 let mut values = Vec::new();
1452 for index in 0..8192i64 {
1453 values.push(1_600_000_000 + index / 4 + (index % 7) * 1_000);
1454 }
1455 let bytes = encode(&values).unwrap();
1456 let described = describe(&bytes).unwrap();
1457 assert!(described.contains('('), "expected a cascade, got {described}");
1458 assert_eq!(decode(&bytes).unwrap(), values, "{described}");
1459 }
1460
1461 #[test]
1462 fn selected_positions_agree_with_a_full_decode_for_packed_and_run_length_chunks() {
1463 let positions = [0, 1, 17, 1023, 1024, 4097, 8191];
1464 let packed: Vec<i64> = (0..8192).map(|index| index * 31 % 1_000_003).collect();
1465 let mut runs = Vec::new();
1466 for run in 0..160i64 {
1467 runs.extend(std::iter::repeat_n(run * 13, (run as usize % 71) + 2));
1468 }
1469 runs.resize(8192, -7);
1470
1471 for (kind, values) in [(Kind::Packed, packed), (Kind::Rle, runs)] {
1472 let bytes = encode_only(kind, &values).unwrap().expect("encoding applies");
1473 let selected = decode_selected(&bytes, &positions).unwrap();
1474 let expected = positions.iter().map(|&position| values[position]).collect::<Vec<_>>();
1475 assert_eq!(selected, expected, "{}", kind.name());
1476 }
1477 }
1478
1479 #[test]
1480 fn selected_positions_must_be_ordered_and_inside_the_chunk() {
1481 let bytes = encode_only(Kind::Packed, &(0..2048).collect::<Vec<_>>())
1482 .unwrap()
1483 .expect("packed applies");
1484 assert!(decode_selected(&bytes, &[7, 7]).is_err());
1485 assert!(decode_selected(&bytes, &[8, 3]).is_err());
1486 assert!(decode_selected(&bytes, &[2048]).is_err());
1487 }
1488
1489 #[test]
1490 fn a_partial_unit_costs_its_own_values_and_not_a_whole_unit() {
1491 let values = vec![1i64 << 39, (1 << 39) + 7, 1 << 38];
1495 let bytes = encode_only(Kind::Packed, &values).unwrap().unwrap();
1496 assert_eq!(bytes.len(), 5 + 9 + 15);
1497 assert_eq!(decode(&bytes).unwrap(), values);
1498 }
1499
1500 #[test]
1501 fn the_frame_of_reference_is_per_unit_and_not_per_chunk() {
1502 let values: Vec<i64> =
1506 (0..4096i64).map(|index| (index / 1024) * 1_000_000 + (index % 1024)).collect();
1507 let bytes = encode_only(Kind::Packed, &values).unwrap().unwrap();
1508 assert_eq!(describe(&bytes).unwrap(), "FOR+BITPACK[10]");
1509 assert_eq!(decode(&bytes).unwrap(), values);
1510 }
1511
1512 #[test]
1513 fn every_candidate_that_applies_decodes_to_the_input() {
1514 let mut values = vec![5i64; 3000];
1518 for (index, value) in values.iter_mut().enumerate() {
1519 if index % 500 == 0 {
1520 *value = index as i64;
1521 }
1522 }
1523 let applicable = candidates(&values, 0, &EXHAUSTIVE);
1524 assert!(applicable.len() >= 4, "{applicable:?}");
1525 for kind in applicable {
1526 let bytes = encode_only(kind, &values).unwrap().unwrap();
1527 assert_eq!(decode(&bytes).unwrap(), values, "{}", kind.name());
1528 }
1529 }
1530
1531 #[test]
1536 fn every_kind_that_applies_decodes_to_what_it_was_given() {
1537 let shapes: Vec<Vec<i64>> = vec![
1538 Vec::new(),
1539 vec![5; 1024],
1540 vec![i64::MIN, i64::MAX, 0, -1],
1541 (0..1024).map(|at| at * 7).collect(),
1542 (0..1024).map(|at| at % 17).collect(),
1543 (0..1024).map(|at| if at % 100 == 0 { at } else { 3 }).collect(),
1544 (0..1024).map(|at| -at * 1_000_003).collect(),
1545 (0..1024_i64)
1546 .map(|at| {
1547 at.wrapping_mul(6_364_136_223_846_793_005)
1548 .wrapping_add(1_442_695_040_888_963_407)
1549 })
1550 .collect(),
1551 ];
1552 let kinds =
1553 [Kind::Constant, Kind::Packed, Kind::Delta, Kind::Rle, Kind::Dict, Kind::Sparse];
1554 for values in &shapes {
1555 for kind in kinds {
1556 let Some(bytes) = encode_only(kind, values).unwrap() else {
1557 continue;
1558 };
1559 assert_eq!(
1560 &decode(&bytes).unwrap(),
1561 values,
1562 "{} over {} values",
1563 kind.name(),
1564 values.len()
1565 );
1566 }
1567 }
1568 }
1569
1570 #[test]
1571 fn the_chooser_picks_the_smallest_candidate_rather_than_the_first_that_applies() {
1572 let mut values = vec![5i64; 3000];
1573 values[1500] = 9;
1574 let chosen = encode(&values).unwrap();
1575 for (_, size) in candidate_sizes(&values).unwrap() {
1576 assert!(chosen.len() <= size);
1577 }
1578 }
1579
1580 #[test]
1581 fn a_truncated_chunk_is_an_error_and_not_a_panic() {
1582 let bytes = encode(&[1, 2, 3, 4, 5]).unwrap();
1583 for len in 0..bytes.len() {
1584 let error = decode(&bytes[..len]).unwrap_err();
1585 assert!(error.message().contains("chunk"), "{error}");
1586 }
1587 }
1588
1589 #[test]
1590 fn trailing_bytes_are_an_error() {
1591 let mut bytes = encode(&[1, 2, 3]).unwrap();
1592 bytes.push(0);
1593 let error = decode(&bytes).unwrap_err();
1594 assert!(error.message().contains("left over"), "{error}");
1595 }
1596
1597 #[test]
1598 fn an_unknown_tag_is_an_error() {
1599 let error = decode(&[99, 0, 0, 0, 0]).unwrap_err();
1600 assert!(error.message().contains("unknown encoding tag"), "{error}");
1601 }
1602
1603 #[test]
1604 fn a_dictionary_code_outside_the_dictionary_is_an_error() {
1605 let mut bytes = vec![Kind::Dict.tag()];
1610 put_u32(&mut bytes, 1);
1611 bytes.extend_from_slice(&encode(&[10]).unwrap());
1612 bytes.extend_from_slice(&encode(&[5]).unwrap());
1613 let error = decode(&bytes).unwrap_err();
1614 assert!(error.message().contains("not in the dictionary"), "{error}");
1615 }
1616
1617 #[test]
1618 fn a_negative_run_length_is_an_error() {
1619 let mut bytes = vec![Kind::Rle.tag()];
1622 put_u32(&mut bytes, 4);
1623 bytes.extend_from_slice(&encode(&[7]).unwrap());
1624 bytes.extend_from_slice(&encode(&[-4]).unwrap());
1625 let error = decode(&bytes).unwrap_err();
1626 assert!(error.message().contains("negative"), "{error}");
1627 }
1628
1629 #[test]
1631 fn a_run_that_runs_past_its_chunk_is_an_error() {
1632 let mut bytes = vec![Kind::Rle.tag()];
1637 put_u32(&mut bytes, 4);
1638 bytes.extend_from_slice(&encode(&[7]).unwrap());
1639 bytes.extend_from_slice(&encode(&[9]).unwrap());
1640 let error = decode(&bytes).unwrap_err();
1641 assert!(error.message().contains("past its chunk"), "{error}");
1642 }
1643
1644 #[test]
1646 fn runs_shorter_and_longer_than_the_width_they_are_written_in_all_come_back() {
1647 let lengths = [1, 3, 7, 8, 9, 40, 2, 1];
1652 let mut values = Vec::new();
1653 for (at, length) in lengths.iter().enumerate() {
1654 let value = i64::try_from(at).expect("eight runs") * 1000 - 3;
1655 values.extend(std::iter::repeat_n(value, *length));
1656 }
1657 let bytes = encode(&values).expect("encodes");
1658 assert_eq!(decode(&bytes).expect("decodes"), values, "runs around the write width");
1659 let singles: Vec<i64> = (0..300).map(|index| index * 7 % 11).collect();
1662 let bytes = encode(&singles).expect("encodes");
1663 assert_eq!(decode(&bytes).expect("decodes"), singles, "no run longer than one");
1664 }
1665
1666 #[test]
1667 fn the_cascade_depth_is_bounded() {
1668 let values: Vec<i64> = (0..50_000).map(|index| (index / 100) % 250).collect();
1672 let bytes = round_trip(&values);
1673 let shape = describe(&bytes).unwrap();
1674 let depth = shape.matches('(').count();
1675 assert!(depth <= MAX_DEPTH as usize, "{shape} is {depth} deep");
1676 }
1677
1678 #[test]
1679 fn candidate_sizes_reports_what_the_chooser_looked_at() {
1680 let values: Vec<i64> = (0..5000).map(|index| index % 17).collect();
1681 let sizes = candidate_sizes(&values).unwrap();
1682 assert!(sizes.iter().any(|(kind, _)| *kind == Kind::Dict));
1683 assert!(sizes.iter().any(|(kind, _)| *kind == Kind::Packed));
1684 assert!(sizes.iter().all(|(_, size)| *size > 0));
1685 }
1686
1687 #[test]
1688 fn a_chunk_can_be_read_from_the_front_of_a_longer_buffer() {
1689 let first = encode(&[1, 2, 3]).unwrap();
1692 let second: Vec<i64> = (0..3000).map(|index| index % 11).collect();
1693 let second_bytes = encode(&second).unwrap();
1694 let mut joined = first.clone();
1695 joined.extend_from_slice(&second_bytes);
1696 joined.extend_from_slice(b"and then something else");
1697
1698 let (values, used) = decode_prefix(&joined).unwrap();
1699 assert_eq!(values, vec![1, 2, 3]);
1700 assert_eq!(used, first.len());
1701 let (more, used_again) = decode_prefix(&joined[used..]).unwrap();
1702 assert_eq!(more, second);
1703 assert_eq!(used_again, second_bytes.len());
1704
1705 let (text, described) = describe_prefix(&joined).unwrap();
1706 assert_eq!(described, first.len());
1707 assert_eq!(text, describe(&first).unwrap());
1708 }
1709
1710 #[test]
1711 fn a_truncated_chunk_is_still_an_error_when_read_as_a_prefix() {
1712 let bytes = encode(&(0..2000).collect::<Vec<i64>>()).unwrap();
1713 for len in 0..bytes.len() {
1714 assert!(decode_prefix(&bytes[..len]).is_err(), "{len} bytes decoded");
1715 }
1716 }
1717}