1use std::collections::BTreeMap;
45use std::time::Instant;
46
47use rudb_common::{Error, Result};
48
49use crate::chooser::{Chooser, EXHAUSTIVE};
50use crate::reader::Reader;
51use crate::tally::{self, Family};
52
53use crate::bitpack::{self, VALUES};
54
55const MAX_DEPTH: u8 = 3;
62
63const RUN: usize = 8;
73
74const LONG_RUN: usize = 64;
78
79#[derive(Debug, Clone, Copy, PartialEq, Eq)]
82pub enum Kind {
83 Constant = 0,
85 Packed = 1,
88 Delta = 2,
91 Rle = 3,
93 Dict = 4,
96 Sparse = 5,
98 Strided = 6,
101}
102
103impl Kind {
104 pub const ALL: [Self; 7] = [
106 Self::Constant,
107 Self::Packed,
108 Self::Delta,
109 Self::Rle,
110 Self::Dict,
111 Self::Sparse,
112 Self::Strided,
113 ];
114
115 fn tag(self) -> u8 {
116 self as u8
117 }
118
119 fn from_tag(tag: u8) -> Result<Self> {
120 match tag {
121 0 => Ok(Self::Constant),
122 1 => Ok(Self::Packed),
123 2 => Ok(Self::Delta),
124 3 => Ok(Self::Rle),
125 4 => Ok(Self::Dict),
126 5 => Ok(Self::Sparse),
127 6 => Ok(Self::Strided),
128 other => Err(Error::internal(format!("unknown encoding tag {other}"))),
129 }
130 }
131
132 #[must_use]
134 pub fn name(self) -> &'static str {
135 match self {
136 Self::Constant => "CONSTANT",
137 Self::Packed => "FOR+BITPACK",
138 Self::Delta => "DELTA",
139 Self::Rle => "RLE",
140 Self::Dict => "DICT",
141 Self::Sparse => "SPARSE",
142 Self::Strided => "STRIDE",
143 }
144 }
145}
146
147pub fn encode(values: &[i64]) -> Result<Vec<u8>> {
154 encode_with(values, &EXHAUSTIVE)
155}
156
157pub fn encode_with(values: &[i64], chooser: &dyn Chooser) -> Result<Vec<u8>> {
167 encode_at(values, 0, chooser)
168}
169
170pub fn decode(bytes: &[u8]) -> Result<Vec<i64>> {
177 let mut reader = Reader::new(bytes);
178 let values = decode_chunk(&mut reader)?;
179 if reader.remaining() != 0 {
180 return Err(Error::internal(format!(
181 "{} bytes left over after decoding a chunk",
182 reader.remaining()
183 )));
184 }
185 Ok(values)
186}
187
188pub fn decode_as<T: Lane>(bytes: &[u8]) -> Result<Vec<T>> {
201 let mut reader = Reader::new(bytes);
202 let values = decode_chunk_as(&mut reader)?;
203 if reader.remaining() != 0 {
204 return Err(Error::internal(format!(
205 "{} bytes left over after decoding a chunk",
206 reader.remaining()
207 )));
208 }
209 Ok(values)
210}
211
212pub trait Lane: Copy + Default {
214 fn fit(value: i64) -> Option<Self>;
216
217 fn wrap(value: i64) -> Self;
219}
220
221macro_rules! lanes {
222 ($($ty:ty),* $(,)?) => {$(
223 impl Lane for $ty {
224 fn fit(value: i64) -> Option<Self> {
225 Self::try_from(value).ok()
226 }
227
228 #[allow(
229 clippy::cast_possible_truncation,
230 clippy::cast_sign_loss,
231 clippy::unnecessary_cast,
232 reason = "only called on a value the caller has checked fits"
233 )]
234 fn wrap(value: i64) -> Self {
235 value as Self
236 }
237 }
238 )*};
239}
240
241lanes!(i8, u8, i16, u16, i32, u32, i64, u64);
242
243fn lane<T: Lane>(value: i64) -> Result<T> {
245 T::fit(value).ok_or_else(|| Error::internal(format!("{value} is outside the chunk's type")))
246}
247
248pub fn tally(bytes: &[u8]) -> Result<(usize, Vec<(i64, u64)>)> {
257 let mut counts = BTreeMap::<i64, u64>::new();
258 let rows = fold(bytes, |value, count| {
259 *counts.entry(value).or_default() += count;
260 Ok(())
261 })?;
262 Ok((rows, counts.into_iter().collect()))
263}
264
265pub fn fold(bytes: &[u8], mut emit: impl FnMut(i64, u64) -> Result<()>) -> Result<usize> {
273 let mut reader = Reader::new(bytes);
274 let kind = Kind::from_tag(reader.u8()?)?;
275 let count = reader.u32()? as usize;
276 match kind {
277 Kind::Constant => {
278 let value = reader.i64()?;
279 if count != 0 {
280 emit(value, count as u64)?;
281 }
282 }
283 Kind::Sparse => {
284 let dominant = reader.i64()?;
285 let exception_count = reader.u32()? as usize;
286 let positions = decode_chunk(&mut reader)?;
287 let values = decode_chunk(&mut reader)?;
288 if positions.len() != exception_count || values.len() != exception_count {
289 return Err(Error::internal("a sparse chunk disagrees about its exception count"));
290 }
291 let mut ordered = true;
292 let mut previous = None;
293 for &position in &positions {
294 let position = usize::try_from(position)
295 .ok()
296 .filter(|&position| position < count)
297 .ok_or_else(|| Error::internal("a sparse exception is outside the chunk"))?;
298 if previous.is_some_and(|last| position <= last) {
299 ordered = false;
300 }
301 previous = Some(position);
302 }
303 if ordered {
304 if count != exception_count {
305 emit(dominant, (count - exception_count) as u64)?;
306 }
307 for value in values {
308 emit(value, 1)?;
309 }
310 } else {
311 let mut exceptions = BTreeMap::<usize, i64>::new();
314 for (position, value) in positions.into_iter().zip(values) {
315 exceptions.insert(position as usize, value);
316 }
317 if count != exceptions.len() {
318 emit(dominant, (count - exceptions.len()) as u64)?;
319 }
320 for value in exceptions.into_values() {
321 emit(value, 1)?;
322 }
323 }
324 }
325 Kind::Rle => {
326 let values = decode_chunk(&mut reader)?;
327 let lengths = decode_chunk(&mut reader)?;
328 if values.len() != lengths.len() {
329 return Err(Error::internal("an RLE chunk has more runs than run lengths"));
330 }
331 let mut rows = 0_usize;
332 for (value, length) in values.into_iter().zip(lengths) {
333 let length = usize::try_from(length)
334 .map_err(|_| Error::internal("a negative RLE run length"))?;
335 rows = rows
336 .checked_add(length)
337 .filter(|&rows| rows <= count)
338 .ok_or_else(|| Error::internal("an RLE run ends past its chunk"))?;
339 if length != 0 {
340 emit(value, length as u64)?;
341 }
342 }
343 check_count(rows, count)?;
344 }
345 _ => {
346 reader = Reader::new(bytes);
348 let values = decode_chunk(&mut reader)?;
349 check_count(values.len(), count)?;
350 for value in values {
351 emit(value, 1)?;
352 }
353 }
354 }
355 if reader.remaining() != 0 {
356 return Err(Error::internal(format!(
357 "{} bytes left over after counting a chunk",
358 reader.remaining()
359 )));
360 }
361 Ok(count)
362}
363
364const SPARSE: usize = 32;
367
368pub fn decode_selected(bytes: &[u8], positions: &[usize]) -> Result<Vec<i64>> {
379 if positions.windows(2).any(|pair| pair[0] >= pair[1]) {
380 return Err(Error::internal("selected integer positions are not sorted and unique"));
381 }
382 let mut reader = Reader::new(bytes);
383 let values = decode_selected_chunk(&mut reader, positions)?;
384 if reader.remaining() != 0 {
385 return Err(Error::internal(format!(
386 "{} bytes left over after decoding selected values",
387 reader.remaining()
388 )));
389 }
390 Ok(values)
391}
392
393#[must_use]
400pub fn pointed(bytes: &[u8]) -> bool {
401 let simple = |bytes: &[u8]| {
402 bytes
403 .first()
404 .and_then(|&tag| Kind::from_tag(tag).ok())
405 .is_some_and(|kind| matches!(kind, Kind::Constant | Kind::Packed))
406 };
407 match bytes.first().and_then(|&tag| Kind::from_tag(tag).ok()) {
408 Some(Kind::Constant | Kind::Packed) => true,
409 Some(Kind::Strided) => bytes.get(1 + 4 + 8 + 8..).is_some_and(simple),
411 Some(Kind::Dict) => {
413 let mut reader = Reader::new(bytes.get(1 + 4..).unwrap_or_default());
414 skip_chunk(&mut reader).is_ok() && simple(reader.rest())
415 }
416 _ => false,
417 }
418}
419
420#[must_use]
426pub fn run_length(bytes: &[u8]) -> bool {
427 bytes.first().and_then(|&tag| Kind::from_tag(tag).ok()) == Some(Kind::Rle)
428}
429
430pub fn decode_prefix(bytes: &[u8]) -> Result<(Vec<i64>, usize)> {
440 let mut reader = Reader::new(bytes);
441 let values = decode_chunk(&mut reader)?;
442 Ok((values, reader.used()))
443}
444
445pub fn describe_prefix(bytes: &[u8]) -> Result<(String, usize)> {
451 let mut reader = Reader::new(bytes);
452 let text = describe_chunk(&mut reader)?;
453 Ok((text, reader.used()))
454}
455
456pub fn candidate_sizes(values: &[i64]) -> Result<Vec<(Kind, usize)>> {
463 let mut sizes = Vec::new();
464 for kind in candidates(values, 0, &EXHAUSTIVE) {
465 if let Some(bytes) = encode_as(kind, values, 0, &EXHAUSTIVE)? {
466 sizes.push((kind, bytes.len()));
467 }
468 }
469 Ok(sizes)
470}
471
472#[must_use]
479pub fn offered(values: &[i64]) -> Vec<Kind> {
480 candidates(values, 0, &EXHAUSTIVE)
481}
482
483pub fn encode_only(kind: Kind, values: &[i64]) -> Result<Option<Vec<u8>>> {
494 encode_as(kind, values, 0, &EXHAUSTIVE)
495}
496
497pub(crate) fn size_as(kind: Kind, values: &[i64], depth: u8) -> Result<Option<usize>> {
502 Ok(encode_as(kind, values, depth, &EXHAUSTIVE)?.map(|bytes| bytes.len()))
503}
504
505pub fn shape(bytes: &[u8]) -> Result<Vec<Kind>> {
517 let mut reader = Reader::new(bytes);
518 let mut kinds = Vec::new();
519 shape_chunk(&mut reader, &mut kinds)?;
520 Ok(kinds)
521}
522
523pub fn describe(bytes: &[u8]) -> Result<String> {
529 let mut reader = Reader::new(bytes);
530 describe_chunk(&mut reader)
531}
532
533fn encode_at(values: &[i64], depth: u8, chooser: &dyn Chooser) -> Result<Vec<u8>> {
534 let started = Instant::now();
535 let offered = candidates(values, depth, chooser);
536 let narrowed = chooser.narrow_integers(values, &offered, depth);
537 let counted = depth == 0;
539 if counted {
540 tally::chose(Family::Integer, started);
541 }
542 let mut best: Option<(Kind, Vec<u8>)> = None;
543 for kind in narrowed {
544 let encoded = if counted {
545 tally::offer(Family::Integer, kind.tag(), || encode_as(kind, values, depth, chooser))?
546 } else {
547 encode_as(kind, values, depth, chooser)?
548 };
549 let Some(bytes) = encoded else {
550 continue;
551 };
552 if best.as_ref().is_none_or(|(_, current)| bytes.len() < current.len()) {
553 best = Some((kind, bytes));
554 }
555 }
556 let (kind, bytes) = best.ok_or_else(|| Error::internal("no encoding applied to the chunk"))?;
559 if counted {
560 tally::kept(Family::Integer, kind.tag());
561 }
562 Ok(bytes)
563}
564
565fn candidates(values: &[i64], depth: u8, chooser: &dyn Chooser) -> Vec<Kind> {
576 let mut kinds = vec![Kind::Packed];
577 if depth >= MAX_DEPTH {
578 return kinds;
579 }
580 let Some(profile) = Profile::of(values) else {
581 return kinds;
582 };
583 if profile.runs == 1 {
584 return vec![Kind::Constant];
586 }
587 let considered = |kind| chooser.considers_integer(kind, depth);
588 let fits = profile.max.checked_sub(profile.min).is_some();
591 if considered(Kind::Delta)
592 && (if fits { profile.deltas_pay(values) } else { deltas_fit(values) })
593 {
594 kinds.push(Kind::Delta);
595 }
596 if considered(Kind::Rle) && profile.runs * 4 <= values.len() * 3 {
597 kinds.push(Kind::Rle);
598 }
599 if considered(Kind::Dict) && profile.width() > 1 {
603 let distinct = spread_of(values).0;
604 if distinct * 2 <= values.len() && width_of(distinct as u64 - 1) < profile.width() {
605 kinds.push(Kind::Dict);
606 }
607 }
608 if considered(Kind::Sparse)
612 && (profile.runs - 1) * 5 <= values.len() * 2
613 && majority(values).is_some_and(|(_, count)| count * 10 >= values.len() * 8)
614 {
615 kinds.push(Kind::Sparse);
616 }
617 if considered(Kind::Strided) && stride_from(values, profile.min).is_some() {
618 kinds.push(Kind::Strided);
619 }
620 kinds
621}
622
623struct Profile {
637 min: i64,
638 max: i64,
639 runs: usize,
641 delta_low: u64,
644 delta_high: u64,
645 delta_runs: usize,
647}
648
649impl Profile {
650 fn of(values: &[i64]) -> Option<Self> {
651 let first = *values.first()?;
652 let (mut min, mut max, mut breaks) = (first, first, 0usize);
653 let mut last = values.get(1).map_or(0, |second| second.wrapping_sub(first));
654 let (mut delta_low, mut delta_high, mut turns) = (u64::MAX, 0u64, 0usize);
655 for (before, after) in values.iter().zip(&values[1..]) {
656 min = min.min(*after);
657 max = max.max(*after);
658 breaks += usize::from(before != after);
659 let delta = after.wrapping_sub(*before);
660 let zigzagged = zigzag(delta);
661 delta_low = delta_low.min(zigzagged);
662 delta_high = delta_high.max(zigzagged);
663 turns += usize::from(delta != last);
664 last = delta;
665 }
666 Some(Self { min, max, runs: breaks + 1, delta_low, delta_high, delta_runs: turns + 1 })
667 }
668
669 fn width(&self) -> u32 {
671 width_of(self.max.wrapping_sub(self.min) as u64)
672 }
673
674 fn deltas_pay(&self, values: &[i64]) -> bool {
682 let len = values.len();
683 let narrower = width_of(self.delta_high.wrapping_sub(self.delta_low)) < self.width();
684 let unruly = self.runs * 4 > len * 3;
687 let repeat = self.delta_runs * 4 <= len.saturating_sub(1) * 3;
688 narrower || (unruly && (repeat || few_deltas(values)))
689 }
690}
691
692fn few_deltas(values: &[i64]) -> bool {
697 let mut seen = [0i64; FEW_DELTAS];
698 let mut count = 0;
699 for pair in values.windows(2).take(FEW_DELTAS_SEEN) {
700 let delta = pair[1].wrapping_sub(pair[0]);
701 if seen[..count].contains(&delta) {
702 continue;
703 }
704 if count == FEW_DELTAS {
705 return false;
706 }
707 seen[count] = delta;
708 count += 1;
709 }
710 true
711}
712
713const FEW_DELTAS: usize = 4;
715
716const FEW_DELTAS_SEEN: usize = 64;
718
719fn width_of(range: u64) -> u32 {
721 u64::BITS - range.leading_zeros()
722}
723
724fn encode_as(
727 kind: Kind,
728 values: &[i64],
729 depth: u8,
730 chooser: &dyn Chooser,
731) -> Result<Option<Vec<u8>>> {
732 let mut out = Vec::new();
733 put_u8(&mut out, kind.tag());
734 put_u32(&mut out, u32::try_from(values.len()).map_err(|_| too_long(values.len()))?);
735 match kind {
736 Kind::Constant => {
737 let Some(first) = values.first() else {
738 return Ok(None);
739 };
740 if values.iter().any(|value| value != first) {
741 return Ok(None);
742 }
743 put_i64(&mut out, *first);
744 }
745 Kind::Packed => encode_packed(values, &mut out)?,
746 Kind::Delta => {
747 let (Some(first), Some(deltas)) = (values.first(), deltas(values)) else {
751 return Ok(None);
752 };
753 put_i64(&mut out, *first);
754 out.extend_from_slice(&encode_at(&deltas, depth + 1, chooser)?);
755 }
756 Kind::Rle => {
757 let (run_values, run_lengths) = runs(values);
758 if run_values.is_empty() {
759 return Ok(None);
760 }
761 out.extend_from_slice(&encode_at(&run_values, depth + 1, chooser)?);
762 out.extend_from_slice(&encode_at(&run_lengths, depth + 1, chooser)?);
763 }
764 Kind::Dict => {
765 let dictionary = distinct_values(values);
766 if dictionary.is_empty() {
767 return Ok(None);
768 }
769 let codes = codes_over(values, &dictionary);
770 out.extend_from_slice(&encode_at(&dictionary, depth + 1, chooser)?);
771 out.extend_from_slice(&encode_at(&codes, depth + 1, chooser)?);
772 }
773 Kind::Sparse => {
774 let Some((value, _)) = majority(values).or_else(|| spread_of(values).1) else {
778 return Ok(None);
779 };
780 let mut positions = Vec::new();
781 let mut exceptions = Vec::new();
782 for (index, other) in values.iter().enumerate() {
783 if *other != value {
784 positions.push(index as i64);
785 exceptions.push(*other);
786 }
787 }
788 put_i64(&mut out, value);
789 put_u32(
790 &mut out,
791 u32::try_from(positions.len()).map_err(|_| too_long(positions.len()))?,
792 );
793 out.extend_from_slice(&encode_at(&positions, depth + 1, chooser)?);
794 out.extend_from_slice(&encode_at(&exceptions, depth + 1, chooser)?);
795 }
796 Kind::Strided => {
797 let (Some(base), Some(stride)) = (values.iter().min().copied(), stride_of(values))
798 else {
799 return Ok(None);
800 };
801 let mut steps = Vec::with_capacity(values.len());
802 for value in values {
803 let step = offset_from(*value, base) / stride;
804 let Ok(step) = i64::try_from(step) else {
809 return Ok(None);
810 };
811 steps.push(step);
812 }
813 put_i64(&mut out, base);
814 put_u64(&mut out, stride);
815 out.extend_from_slice(&encode_at(&steps, depth + 1, chooser)?);
816 }
817 }
818 Ok(Some(out))
819}
820
821fn encode_packed(values: &[i64], out: &mut Vec<u8>) -> Result<()> {
833 let mut offsets: Vec<u64> = Vec::with_capacity(VALUES);
836 let mut packed: Vec<u64> = vec![0; bitpack::packed_len::<u64>(64)];
839 let mut transposed = bitpack::Scratch::<u64>::new();
840 for unit in values.chunks(VALUES) {
841 let base = unit.iter().copied().min().unwrap_or(0);
842 offsets.clear();
843 offsets.extend(unit.iter().map(|value| offset_from(*value, base)));
844 let width = bitpack::required_width(&offsets);
845 put_i64(out, base);
846 put_u8(out, u8::try_from(width).map_err(|_| Error::internal("impossible width"))?);
847 if unit.len() == VALUES {
848 let words = bitpack::packed_len::<u64>(width);
849 bitpack::pack_with(&offsets, width, &mut packed[..words], &mut transposed)?;
850 for word in &packed[..words] {
851 put_u64(out, *word);
852 }
853 } else {
854 bitpack::pack_tail(&offsets, width, out)?;
855 }
856 }
857 Ok(())
858}
859
860fn decode_chunk(reader: &mut Reader<'_>) -> Result<Vec<i64>> {
861 let kind = Kind::from_tag(reader.u8()?)?;
862 let count = reader.u32()? as usize;
863 match kind {
864 Kind::Constant => Ok(vec![reader.i64()?; count]),
865 Kind::Packed => {
866 let mut values = vec![0i64; count];
871 let mut done = 0;
872 while done < count {
873 let base = reader.i64()?;
874 let width = reader.u8()? as usize;
875 let wanted = (count - done).min(VALUES);
876 let into = &mut values[done..done + wanted];
877 if wanted == VALUES {
878 let unit = reader.bytes(bitpack::unit_len(width))?;
879 bitpack::unpack_unit_into(unit, width, into, |offset| {
880 value_from(offset, base)
881 })?;
882 } else {
883 let bytes = reader.bytes(bitpack::tail_len(wanted, width))?;
884 bitpack::unpack_tail_into(bytes, width, into, |offset| {
885 value_from(offset, base)
886 })?;
887 }
888 done += wanted;
889 }
890 Ok(values)
891 }
892 Kind::Delta => {
893 let first = reader.i64()?;
894 let mut values = decode_chunk(reader)?;
895 check_count(values.len() + 1, count)?;
896 let mut current = first;
900 for value in &mut values {
901 let delta = unzigzag(*value as u64);
902 *value = current;
903 current = current.wrapping_add(delta);
904 }
905 values.push(current);
906 Ok(values)
907 }
908 Kind::Rle => {
909 let run_values = decode_chunk(reader)?;
910 let run_lengths = decode_chunk(reader)?;
911 expanded(&run_values, &run_lengths, count)
912 }
913 Kind::Dict => {
914 let dictionary = decode_chunk(reader)?;
915 let codes = decode_chunk(reader)?;
916 let mut values = Vec::with_capacity(count);
917 for code in codes {
918 let index =
919 usize::try_from(code).ok().and_then(|index| dictionary.get(index)).ok_or_else(
920 || Error::internal(format!("code {code} is not in the dictionary")),
921 )?;
922 values.push(*index);
923 }
924 check_count(values.len(), count)?;
925 Ok(values)
926 }
927 Kind::Sparse => {
928 let value = reader.i64()?;
929 let exception_count = reader.u32()? as usize;
930 let positions = decode_chunk(reader)?;
931 let exceptions = decode_chunk(reader)?;
932 if positions.len() != exception_count || exceptions.len() != exception_count {
933 return Err(Error::internal("a sparse chunk disagrees about its exception count"));
934 }
935 let mut values = vec![value; count];
936 for (position, exception) in positions.into_iter().zip(exceptions) {
937 let position = usize::try_from(position)
938 .ok()
939 .filter(|position| *position < count)
940 .ok_or_else(|| {
941 Error::internal(format!("exception at {position} is outside the chunk"))
942 })?;
943 values[position] = exception;
944 }
945 Ok(values)
946 }
947 Kind::Strided => {
948 let base = reader.i64()?;
949 let stride = reader.u64()?;
950 let steps = decode_chunk(reader)?;
951 check_count(steps.len(), count)?;
952 strided(steps, stride, base)
953 }
954 }
955}
956
957fn strided(mut steps: Vec<i64>, stride: u64, base: i64) -> Result<Vec<i64>> {
965 if steps.iter().fold(0, |held, &step| held | step) < 0 {
967 return Err(Error::internal("a negative number of strides"));
968 }
969 for step in &mut steps {
970 *step = base.wrapping_add((*step as u64).wrapping_mul(stride) as i64);
971 }
972 Ok(steps)
973}
974
975fn expanded<T: Lane>(run_values: &[i64], run_lengths: &[i64], count: usize) -> Result<Vec<T>> {
991 if run_values.len() != run_lengths.len() {
992 return Err(Error::internal("an RLE chunk has more runs than run lengths"));
993 }
994 let (signs, longest, total) =
995 run_lengths.iter().fold((0, 0, 0u128), |(signs, longest, total), &length| {
996 (signs | length, longest.max(length), total + u128::from(length as u64))
997 });
998 if signs < 0 {
999 return Err(Error::internal("a negative RLE run length"));
1000 }
1001 if total > count as u128 {
1002 return Err(Error::internal("an RLE run ends past its chunk"));
1003 }
1004 check_count(total as usize, count)?;
1005 let wide = T::fit(i64::MIN).is_some() && T::fit(i64::MAX).is_some();
1007 if !wide {
1008 let (low, high) = run_values
1009 .iter()
1010 .fold((i64::MAX, i64::MIN), |(low, high), &value| (low.min(value), high.max(value)));
1011 if !run_values.is_empty() {
1012 lane::<T>(low)?;
1013 lane::<T>(high)?;
1014 }
1015 }
1016 let runs = run_values.iter().zip(run_lengths);
1017 if run_values.len().saturating_mul(LONG_RUN) <= count {
1018 let mut values = Vec::with_capacity(count);
1019 for (&value, &length) in runs {
1020 values.resize(values.len() + length as usize, T::wrap(value));
1021 }
1022 return Ok(values);
1023 }
1024 let mut values = vec![T::default(); count + RUN];
1025 let mut at = 0;
1026 if longest as usize <= RUN {
1027 for (&value, &length) in runs {
1028 values[at..at + RUN].fill(T::wrap(value));
1029 at += length as usize;
1030 }
1031 } else {
1032 for (&value, &length) in runs {
1033 let length = length as usize;
1034 values[at..at + length.max(RUN)].fill(T::wrap(value));
1035 at += length;
1036 }
1037 }
1038 values.truncate(count);
1039 Ok(values)
1040}
1041
1042fn decode_chunk_as<T: Lane>(reader: &mut Reader<'_>) -> Result<Vec<T>> {
1044 let Some(&tag) = reader.rest().first() else {
1045 return Err(Error::internal("a chunk ended before its encoding tag"));
1046 };
1047 match Kind::from_tag(tag)? {
1048 Kind::Constant | Kind::Packed | Kind::Sparse | Kind::Rle => {}
1049 _ => {
1059 let values = decode_chunk(reader)?;
1060 let (low, high) = values.iter().fold((i64::MAX, i64::MIN), |(low, high), &value| {
1061 (low.min(value), high.max(value))
1062 });
1063 if values.is_empty() || T::fit(low).is_some() && T::fit(high).is_some() {
1064 return Ok(values.into_iter().map(T::wrap).collect());
1065 }
1066 return values.into_iter().map(lane).collect();
1067 }
1068 }
1069 let kind = Kind::from_tag(reader.u8()?)?;
1070 let count = reader.u32()? as usize;
1071 match kind {
1072 Kind::Constant => Ok(vec![lane(reader.i64()?)?; count]),
1073 Kind::Packed => {
1074 let mut values = vec![T::default(); count];
1075 let mut wide = [0i64; VALUES];
1076 let mut done = 0;
1077 while done < count {
1078 let base = reader.i64()?;
1079 let width = reader.u8()? as usize;
1080 let wanted = (count - done).min(VALUES);
1081 let into = &mut values[done..done + wanted];
1082 let whole = wanted == VALUES;
1083 let bytes = if whole {
1084 reader.bytes(bitpack::unit_len(width))?
1085 } else {
1086 reader.bytes(bitpack::tail_len(wanted, width))?
1087 };
1088 let mask = if width >= 64 { u64::MAX } else { (1u64 << width) - 1 };
1093 let top = i64::try_from(i128::from(base) + i128::from(mask)).ok();
1094 if T::fit(base).is_some() && top.and_then(T::fit).is_some() {
1095 let map = |offset| T::wrap(value_from(offset, base));
1096 if whole {
1097 bitpack::unpack_unit_into(bytes, width, into, map)?;
1098 } else {
1099 bitpack::unpack_tail_into(bytes, width, into, map)?;
1100 }
1101 } else {
1102 let wide = &mut wide[..wanted];
1103 let map = |offset| value_from(offset, base);
1104 if whole {
1105 bitpack::unpack_unit_into(bytes, width, wide, map)?;
1106 } else {
1107 bitpack::unpack_tail_into(bytes, width, wide, map)?;
1108 }
1109 for (value, &held) in into.iter_mut().zip(wide.iter()) {
1110 *value = lane(held)?;
1111 }
1112 }
1113 done += wanted;
1114 }
1115 Ok(values)
1116 }
1117 Kind::Rle => {
1118 let run_values = decode_chunk(reader)?;
1119 let run_lengths = decode_chunk(reader)?;
1120 expanded(&run_values, &run_lengths, count)
1121 }
1122 Kind::Sparse => {
1123 let value = lane::<T>(reader.i64()?)?;
1124 let exception_count = reader.u32()? as usize;
1125 let positions = decode_chunk(reader)?;
1126 let exceptions = decode_chunk(reader)?;
1127 if positions.len() != exception_count || exceptions.len() != exception_count {
1128 return Err(Error::internal("a sparse chunk disagrees about its exception count"));
1129 }
1130 let mut values = vec![value; count];
1131 for (position, exception) in positions.into_iter().zip(exceptions) {
1132 let position = usize::try_from(position)
1133 .ok()
1134 .filter(|position| *position < count)
1135 .ok_or_else(|| {
1136 Error::internal(format!("exception at {position} is outside the chunk"))
1137 })?;
1138 values[position] = lane(exception)?;
1139 }
1140 Ok(values)
1141 }
1142 Kind::Delta | Kind::Dict | Kind::Strided => {
1143 Err(Error::internal("a chunk kind that decodes wide reached the narrow decoder"))
1144 }
1145 }
1146}
1147
1148fn decode_selected_chunk(reader: &mut Reader<'_>, positions: &[usize]) -> Result<Vec<i64>> {
1149 let Some(&tag) = reader.rest().first() else {
1150 return Err(Error::internal("a chunk ended before its encoding tag"));
1151 };
1152 let kind = Kind::from_tag(tag)?;
1153 if !matches!(kind, Kind::Constant | Kind::Packed | Kind::Rle | Kind::Strided | Kind::Dict) {
1154 let values = decode_chunk(reader)?;
1155 return positions
1156 .iter()
1157 .map(|&position| {
1158 values.get(position).copied().ok_or_else(|| {
1159 Error::internal(format!(
1160 "selected integer position {position} is outside {} values",
1161 values.len()
1162 ))
1163 })
1164 })
1165 .collect();
1166 }
1167
1168 let decoded = Kind::from_tag(reader.u8()?)?;
1169 debug_assert_eq!(decoded, kind);
1170 let count = reader.u32()? as usize;
1171 if positions.last().is_some_and(|&position| position >= count) {
1172 return Err(Error::internal(format!(
1173 "selected integer position {} is outside {count} values",
1174 positions.last().expect("a last position exists")
1175 )));
1176 }
1177 match kind {
1178 Kind::Constant => {
1179 let value = reader.i64()?;
1180 Ok(vec![value; positions.len()])
1181 }
1182 Kind::Packed => {
1183 let mut out = Vec::with_capacity(positions.len());
1184 let mut from = 0;
1185 let mut done = 0;
1186 while done < count {
1187 let base = reader.i64()?;
1188 let width = reader.u8()? as usize;
1189 let wanted = (count - done).min(VALUES);
1190 let upto = positions.partition_point(|&position| position < done + wanted);
1191 if wanted == VALUES && (upto - from) * SPARSE > VALUES {
1192 let bytes = reader.bytes(bitpack::unit_len(width))?;
1195 let mut unit = [0_i64; VALUES];
1196 bitpack::unpack_unit_into(bytes, width, &mut unit, |offset| {
1197 value_from(offset, base)
1198 })?;
1199 out.extend(positions[from..upto].iter().map(|&position| unit[position - done]));
1200 } else if wanted == VALUES {
1201 let bytes = reader.bytes(bitpack::unit_len(width))?;
1202 for &position in &positions[from..upto] {
1203 let offset = bitpack::unpack_u64_at(bytes, width, position - done)?;
1204 out.push(value_from(offset, base));
1205 }
1206 } else {
1207 let bytes = reader.bytes(bitpack::tail_len(wanted, width))?;
1208 for &position in &positions[from..upto] {
1209 let offset = bitpack::tail_at(bytes, width, position - done)?;
1210 out.push(value_from(offset, base));
1211 }
1212 }
1213 from = upto;
1214 done += wanted;
1215 }
1216 Ok(out)
1217 }
1218 Kind::Rle => {
1219 let run_value_bytes = reader.rest();
1220 let mut run_value_reader = Reader::new(run_value_bytes);
1221 let run_value_count = skip_chunk(&mut run_value_reader)?;
1222 let run_value_len = run_value_reader.used();
1223 reader.skip(run_value_len)?;
1224 let run_lengths = decode_chunk(reader)?;
1225 if run_value_count != run_lengths.len() {
1226 return Err(Error::internal("an RLE chunk has more runs than run lengths"));
1227 }
1228 let mut wanted_runs = Vec::new();
1229 let mut selected_per_run = Vec::new();
1230 let mut selected = 0;
1231 let mut at = 0usize;
1232 for (run, length) in run_lengths.into_iter().enumerate() {
1233 let length = usize::try_from(length)
1234 .map_err(|_| Error::internal("a negative RLE run length"))?;
1235 let end = at
1236 .checked_add(length)
1237 .filter(|end| *end <= count)
1238 .ok_or_else(|| Error::internal("an RLE run ends past its chunk"))?;
1239 let before = selected;
1240 while selected < positions.len() && positions[selected] < end {
1241 if positions[selected] < at {
1242 return Err(Error::internal("selected integer positions went backwards"));
1243 }
1244 selected += 1;
1245 }
1246 if selected != before {
1247 wanted_runs.push(run);
1248 selected_per_run.push(selected - before);
1249 }
1250 at = end;
1251 }
1252 check_count(at, count)?;
1253 if selected != positions.len() {
1254 return Err(Error::internal("an RLE chunk ended before a selected position"));
1255 }
1256 let run_values = decode_selected(&run_value_bytes[..run_value_len], &wanted_runs)?;
1257 let mut out = Vec::with_capacity(positions.len());
1258 for (value, repeat) in run_values.into_iter().zip(selected_per_run) {
1259 out.extend(std::iter::repeat_n(value, repeat));
1260 }
1261 Ok(out)
1262 }
1263 Kind::Strided => {
1266 let base = reader.i64()?;
1267 let stride = reader.u64()?;
1268 let steps = decode_selected_chunk(reader, positions)?;
1269 steps
1270 .into_iter()
1271 .map(|step| {
1272 let step = u64::try_from(step)
1273 .map_err(|_| Error::internal("a negative number of strides"))?;
1274 Ok(value_from(step.wrapping_mul(stride), base))
1275 })
1276 .collect()
1277 }
1278 Kind::Dict => {
1279 let dictionary = decode_chunk(reader)?;
1280 let codes = decode_selected_chunk(reader, positions)?;
1281 codes
1282 .into_iter()
1283 .map(|code| {
1284 usize::try_from(code)
1285 .ok()
1286 .and_then(|index| dictionary.get(index))
1287 .copied()
1288 .ok_or_else(|| {
1289 Error::internal(format!("code {code} is not in the dictionary"))
1290 })
1291 })
1292 .collect()
1293 }
1294 _ => unreachable!("unsupported kinds used the full decoder"),
1295 }
1296}
1297
1298fn skip_chunk(reader: &mut Reader<'_>) -> Result<usize> {
1300 let kind = Kind::from_tag(reader.u8()?)?;
1301 let count = reader.u32()? as usize;
1302 match kind {
1303 Kind::Constant => reader.skip(8)?,
1304 Kind::Packed => skip_packed(reader, count)?,
1305 Kind::Delta => {
1306 reader.skip(8)?;
1307 skip_chunk(reader)?;
1308 }
1309 Kind::Rle | Kind::Dict => {
1310 skip_chunk(reader)?;
1311 skip_chunk(reader)?;
1312 }
1313 Kind::Sparse => {
1314 reader.skip(12)?;
1315 skip_chunk(reader)?;
1316 skip_chunk(reader)?;
1317 }
1318 Kind::Strided => {
1319 reader.skip(16)?;
1320 skip_chunk(reader)?;
1321 }
1322 }
1323 Ok(count)
1324}
1325
1326fn skip_packed(reader: &mut Reader<'_>, count: usize) -> Result<()> {
1328 let mut done = 0;
1329 while done < count {
1330 reader.skip(8)?;
1331 let width = reader.u8()? as usize;
1332 if width > 64 {
1333 return Err(Error::internal(format!("a packed integer width of {width} is past 64")));
1334 }
1335 let wanted = (count - done).min(VALUES);
1336 let bytes = if wanted == VALUES {
1337 bitpack::packed_len::<u64>(width)
1338 .checked_mul(8)
1339 .ok_or_else(|| Error::internal("packed integer size overflow"))?
1340 } else {
1341 bitpack::tail_len(wanted, width)
1342 };
1343 reader.skip(bytes)?;
1344 done += wanted;
1345 }
1346 Ok(())
1347}
1348
1349fn shape_chunk(reader: &mut Reader<'_>, kinds: &mut Vec<Kind>) -> Result<()> {
1351 let kind = Kind::from_tag(reader.u8()?)?;
1352 let count = reader.u32()? as usize;
1353 kinds.push(kind);
1354 match kind {
1355 Kind::Constant => reader.skip(8)?,
1356 Kind::Packed => skip_packed(reader, count)?,
1357 Kind::Delta => {
1358 reader.skip(8)?;
1359 shape_chunk(reader, kinds)?;
1360 }
1361 Kind::Rle | Kind::Dict => {
1362 shape_chunk(reader, kinds)?;
1363 shape_chunk(reader, kinds)?;
1364 }
1365 Kind::Sparse => {
1366 reader.skip(12)?;
1367 shape_chunk(reader, kinds)?;
1368 shape_chunk(reader, kinds)?;
1369 }
1370 Kind::Strided => {
1371 reader.skip(16)?;
1372 shape_chunk(reader, kinds)?;
1373 }
1374 }
1375 Ok(())
1376}
1377
1378fn describe_chunk(reader: &mut Reader<'_>) -> Result<String> {
1379 let kind = Kind::from_tag(reader.u8()?)?;
1380 let count = reader.u32()? as usize;
1381 Ok(match kind {
1382 Kind::Constant => {
1383 reader.i64()?;
1384 "CONSTANT".to_string()
1385 }
1386 Kind::Packed => {
1387 let mut widths = Vec::new();
1388 let mut seen = 0;
1389 while seen < count {
1390 reader.i64()?;
1391 let width = reader.u8()? as usize;
1392 let wanted = (count - seen).min(VALUES);
1393 if wanted == VALUES {
1394 for _ in 0..bitpack::packed_len::<u64>(width) {
1395 reader.u64()?;
1396 }
1397 } else {
1398 reader.bytes(bitpack::tail_len(wanted, width))?;
1399 }
1400 widths.push(width);
1401 seen += wanted;
1402 }
1403 let low = widths.iter().copied().min().unwrap_or(0);
1404 let high = widths.iter().copied().max().unwrap_or(0);
1405 if low == high {
1408 format!("FOR+BITPACK[{low}]")
1409 } else {
1410 format!("FOR+BITPACK[{low}..{high}]")
1411 }
1412 }
1413 Kind::Delta => {
1414 reader.i64()?;
1415 format!("DELTA({})", describe_chunk(reader)?)
1416 }
1417 Kind::Rle => {
1418 let values = describe_chunk(reader)?;
1419 let lengths = describe_chunk(reader)?;
1420 format!("RLE({values}, {lengths})")
1421 }
1422 Kind::Dict => {
1423 let dictionary = describe_chunk(reader)?;
1424 let codes = describe_chunk(reader)?;
1425 format!("DICT({dictionary}, {codes})")
1426 }
1427 Kind::Sparse => {
1428 reader.i64()?;
1429 reader.u32()?;
1430 let positions = describe_chunk(reader)?;
1431 let exceptions = describe_chunk(reader)?;
1432 format!("SPARSE({positions}, {exceptions})")
1433 }
1434 Kind::Strided => {
1435 reader.i64()?;
1436 let stride = reader.u64()?;
1437 format!("STRIDE[{stride}]({})", describe_chunk(reader)?)
1438 }
1439 })
1440}
1441
1442fn stride_of(values: &[i64]) -> Option<u64> {
1454 stride_from(values, values.iter().min().copied()?)
1455}
1456
1457fn stride_from(values: &[i64], base: i64) -> Option<u64> {
1459 let mut divisor = 0u64;
1460 for value in values {
1461 divisor = gcd(divisor, offset_from(*value, base));
1462 if divisor == 1 {
1463 return None;
1464 }
1465 }
1466 (divisor > 1).then_some(divisor)
1469}
1470
1471fn gcd(mut left: u64, mut right: u64) -> u64 {
1473 if left == 0 {
1474 return right;
1475 }
1476 if right == 0 {
1477 return left;
1478 }
1479 let shift = (left | right).trailing_zeros();
1480 left >>= left.trailing_zeros();
1481 loop {
1482 right >>= right.trailing_zeros();
1483 if left > right {
1484 std::mem::swap(&mut left, &mut right);
1485 }
1486 right -= left;
1487 if right == 0 {
1488 return left << shift;
1489 }
1490 }
1491}
1492
1493fn offset_from(value: i64, base: i64) -> u64 {
1496 (i128::from(value) - i128::from(base)) as u64
1497}
1498
1499fn value_from(offset: u64, base: i64) -> i64 {
1500 (i128::from(base) + i128::from(offset)) as i64
1501}
1502
1503fn zigzag(value: i64) -> u64 {
1506 ((value << 1) ^ (value >> 63)) as u64
1507}
1508
1509fn unzigzag(value: u64) -> i64 {
1510 ((value >> 1) as i64) ^ -((value & 1) as i64)
1511}
1512
1513fn deltas_fit(values: &[i64]) -> bool {
1525 values.windows(2).all(|pair| pair[1].checked_sub(pair[0]).is_some())
1526}
1527
1528fn deltas(values: &[i64]) -> Option<Vec<i64>> {
1529 let mut deltas = Vec::with_capacity(values.len().saturating_sub(1));
1530 for pair in values.windows(2) {
1531 let difference = pair[1].checked_sub(pair[0])?;
1532 deltas.push(zigzag(difference) as i64);
1533 }
1534 Some(deltas)
1535}
1536
1537fn runs(values: &[i64]) -> (Vec<i64>, Vec<i64>) {
1544 let mut run_values: Vec<i64> = Vec::new();
1545 let mut run_lengths: Vec<i64> = Vec::new();
1546 let mut start = 0;
1547 while let Some(&value) = values.get(start) {
1548 let length = values[start..].iter().take_while(|other| **other == value).count();
1549 run_values.push(value);
1550 run_lengths.push(length as i64);
1551 start += length;
1552 }
1553 (run_values, run_lengths)
1554}
1555
1556fn spread_of(values: &[i64]) -> (usize, Option<(i64, usize)>) {
1571 let mut sorted = values.to_vec();
1572 sorted.sort_unstable();
1573 let mut distinct = 0;
1574 let mut best: Option<(i64, usize)> = None;
1575 let mut index = 0;
1576 while index < sorted.len() {
1577 let value = sorted[index];
1578 let mut end = index;
1579 while end < sorted.len() && sorted[end] == value {
1580 end += 1;
1581 }
1582 distinct += 1;
1583 let count = end - index;
1584 if best.is_none_or(|(_, seen)| count > seen) {
1585 best = Some((value, count));
1586 }
1587 index = end;
1588 }
1589 (distinct, best)
1590}
1591
1592fn majority(values: &[i64]) -> Option<(i64, usize)> {
1600 let mut candidate = *values.first()?;
1601 let mut lead = 0usize;
1602 for value in values {
1603 if lead == 0 {
1604 candidate = *value;
1605 lead = 1;
1606 } else if *value == candidate {
1607 lead += 1;
1608 } else {
1609 lead -= 1;
1610 }
1611 }
1612 let count = values.iter().filter(|value| **value == candidate).count();
1613 (count * 2 > values.len()).then_some((candidate, count))
1614}
1615
1616fn distinct_values(values: &[i64]) -> Vec<i64> {
1619 let mut distinct = values.to_vec();
1620 distinct.sort_unstable();
1621 distinct.dedup();
1622 distinct
1623}
1624
1625fn codes_over(values: &[i64], dictionary: &[i64]) -> Vec<i64> {
1635 values
1636 .iter()
1637 .map(|value| {
1638 dictionary
1639 .binary_search(value)
1640 .expect("the dictionary is the distinct values of this chunk") as i64
1641 })
1642 .collect()
1643}
1644
1645fn check_count(actual: usize, expected: usize) -> Result<()> {
1646 if actual == expected {
1647 Ok(())
1648 } else {
1649 Err(Error::internal(format!(
1650 "a chunk says it holds {expected} values and decoded to {actual}"
1651 )))
1652 }
1653}
1654
1655fn too_long(len: usize) -> Error {
1656 Error::internal(format!("a chunk of {len} values is longer than the format allows"))
1657}
1658
1659fn put_u8(out: &mut Vec<u8>, value: u8) {
1660 out.push(value);
1661}
1662
1663fn put_u32(out: &mut Vec<u8>, value: u32) {
1664 out.extend_from_slice(&value.to_le_bytes());
1665}
1666
1667fn put_u64(out: &mut Vec<u8>, value: u64) {
1668 out.extend_from_slice(&value.to_le_bytes());
1669}
1670
1671fn put_i64(out: &mut Vec<u8>, value: i64) {
1672 out.extend_from_slice(&value.to_le_bytes());
1673}
1674
1675#[cfg(test)]
1676mod tests {
1677 use super::*;
1678
1679 fn round_trip(values: &[i64]) -> Vec<u8> {
1680 let bytes = encode(values).unwrap();
1681 assert_eq!(decode(&bytes).unwrap(), values, "{}", describe(&bytes).unwrap());
1682 bytes
1683 }
1684
1685 fn kind_of(bytes: &[u8]) -> Kind {
1686 Kind::from_tag(bytes[0]).unwrap()
1687 }
1688
1689 struct Random(u64);
1691
1692 impl Random {
1693 fn new() -> Self {
1694 Self(0x9e37_79b9_7f4a_7c15)
1695 }
1696
1697 fn next(&mut self) -> u64 {
1698 self.0 ^= self.0 << 13;
1699 self.0 ^= self.0 >> 7;
1700 self.0 ^= self.0 << 17;
1701 self.0
1702 }
1703 }
1704
1705 #[test]
1706 fn the_dictionary_is_sorted_and_the_codes_point_back_at_the_values() {
1707 let values = vec![30i64, 10, 30, 20, 10, -5];
1708 let dictionary = distinct_values(&values);
1709 let codes = codes_over(&values, &dictionary);
1710 assert_eq!(dictionary, vec![-5, 10, 20, 30]);
1711 assert_eq!(codes, vec![3, 1, 3, 2, 1, 0]);
1712 for (code, value) in codes.iter().zip(&values) {
1713 assert_eq!(dictionary[*code as usize], *value);
1714 }
1715 }
1716
1717 #[test]
1718 fn one_sort_gives_the_distinct_count_and_the_most_frequent_value() {
1719 let values = vec![7i64, 7, 7, 1, 2, 2];
1720 assert_eq!(spread_of(&values), (3, Some((7, 3))));
1721 assert_eq!(spread_of(&[]), (0, None));
1722 assert_eq!(spread_of(&[9]), (1, Some((9, 1))));
1723
1724 assert_eq!(spread_of(&[4i64, 4, 8, 8]), (2, Some((4, 2))));
1727 }
1728
1729 #[test]
1730 fn the_majority_is_the_most_frequent_value_whenever_there_is_one() {
1731 let chunks: Vec<Vec<i64>> = vec![
1732 vec![],
1733 vec![3],
1734 vec![1, 2],
1735 vec![1, 1, 2],
1736 vec![2, 1, 1],
1737 vec![4, 4, 8, 8],
1738 vec![7, 1, 7, 2, 7, 3, 7],
1739 vec![1, 2, 3, 9, 9, 9, 9],
1740 (0..1000).map(|index| if index % 5 == 0 { index } else { -4 }).collect(),
1741 (0..1000).map(|index| index % 3).collect(),
1742 ];
1743 for chunk in chunks {
1744 let (_, dominant) = spread_of(&chunk);
1745 let expected = dominant.filter(|(_, count)| count * 2 > chunk.len());
1746 assert_eq!(majority(&chunk), expected, "{chunk:?}");
1747 }
1748 }
1749
1750 #[test]
1754 fn the_one_pass_offers_what_the_separate_tests_offered() {
1755 let mut random = Random::new();
1756 let mut chunks: Vec<Vec<i64>> = vec![
1757 vec![],
1758 vec![5],
1759 vec![5, 5, 5],
1760 vec![i64::MIN, i64::MAX],
1761 vec![i64::MAX, i64::MIN, i64::MAX],
1762 vec![i64::MIN, 0, i64::MAX],
1763 vec![-1, i64::MAX],
1764 (0..1000).map(|index| if index % 5 == 0 { index } else { -4 }).collect(),
1765 (0..1000).map(|index| if index % 4 == 0 { index } else { -4 }).collect(),
1766 (0..1000).map(|index| index / 7).collect(),
1767 (0..1000).map(|index| index * 1_000_000).collect(),
1768 ];
1769 for _ in 0..200 {
1770 let len = (random.next() % 300) as usize;
1771 let spread = 1 + random.next() % 8;
1772 let common = (random.next() % 5) as i64;
1773 chunks.push(
1774 (0..len)
1775 .map(|_| {
1776 let draw = random.next();
1777 if draw % 10 < spread { (draw >> 8) as i64 % 50 } else { common }
1778 })
1779 .collect(),
1780 );
1781 }
1782 for chunk in chunks {
1783 let mut expected = vec![Kind::Packed];
1784 if !chunk.is_empty() {
1785 if chunk.iter().all(|value| *value == chunk[0]) {
1786 expected = vec![Kind::Constant];
1787 } else {
1788 let runs = 1 + chunk.windows(2).filter(|pair| pair[0] != pair[1]).count();
1789 let low = *chunk.iter().min().unwrap();
1790 let high = *chunk.iter().max().unwrap();
1791 let bits = |range: u128| 128 - range.leading_zeros();
1792 let width = bits((i128::from(high) - i128::from(low)) as u128);
1793 let zigzags: Vec<u128> = chunk
1794 .windows(2)
1795 .map(|pair| u128::from(zigzag(pair[1].wrapping_sub(pair[0]))))
1796 .collect();
1797 let spread = zigzags.iter().max().unwrap() - zigzags.iter().min().unwrap();
1798 let turns = 1 + zigzags.windows(2).filter(|pair| pair[0] != pair[1]).count();
1799 let mut first: Vec<u128> = zigzags.iter().take(64).copied().collect();
1800 first.sort_unstable();
1801 first.dedup();
1802 let pays = bits(spread) < width
1803 || (runs * 4 > chunk.len() * 3
1804 && (turns * 4 <= (chunk.len() - 1) * 3 || first.len() <= 4));
1805 if deltas_fit(&chunk) && pays {
1806 expected.push(Kind::Delta);
1807 }
1808 if runs * 4 <= chunk.len() * 3 {
1809 expected.push(Kind::Rle);
1810 }
1811 let distinct = spread_of(&chunk).0;
1812 if distinct * 2 <= chunk.len() && bits(distinct as u128 - 1) < width {
1813 expected.push(Kind::Dict);
1814 }
1815 if majority(&chunk).is_some_and(|(_, count)| count * 10 >= chunk.len() * 8) {
1816 expected.push(Kind::Sparse);
1817 }
1818 if stride_of(&chunk).is_some() {
1819 expected.push(Kind::Strided);
1820 }
1821 }
1822 }
1823 assert_eq!(candidates(&chunk, 0, &EXHAUSTIVE), expected, "{chunk:?}");
1824 }
1825 }
1826
1827 #[test]
1828 fn runs_are_every_stretch_of_equal_neighbours_in_order() {
1829 assert_eq!(runs(&[]), (vec![], vec![]));
1830 assert_eq!(runs(&[4]), (vec![4], vec![1]));
1831 assert_eq!(runs(&[1, 1, 2, 1, 1, 1]), (vec![1, 2, 1], vec![2, 1, 3]));
1832 }
1833
1834 #[test]
1835 fn deltas_that_do_not_fit_are_refused_before_they_are_built() {
1836 assert!(deltas_fit(&[1i64, 2, 3]));
1837 assert!(deltas_fit(&[i64::MAX, i64::MAX]));
1838 assert!(!deltas_fit(&[i64::MIN, i64::MAX]));
1839 assert_eq!(deltas_fit(&[i64::MIN, i64::MAX]), deltas(&[i64::MIN, i64::MAX]).is_some());
1840 assert_eq!(deltas_fit(&[1i64, 2, 3]), deltas(&[1i64, 2, 3]).is_some());
1841 }
1842
1843 #[test]
1844 fn what_the_chooser_returns_is_the_smallest_of_what_it_was_offered() {
1845 let mut random = Random::new();
1849 let noise: Vec<i64> = (0..2000).map(|_| (random.next() % 5000) as i64).collect();
1850 let runs: Vec<i64> = (0..2000).map(|index: i64| index / 100).collect();
1851 let climbing: Vec<i64> = (0..2000).map(|index| 1_700_000_000 + index).collect();
1852 for values in [noise, runs, climbing, vec![7; 300], Vec::new()] {
1853 let chosen = encode(&values).unwrap();
1854 let mut smallest: Option<Vec<u8>> = None;
1855 for kind in offered(&values) {
1856 let Some(bytes) = encode_only(kind, &values).unwrap() else {
1857 continue;
1858 };
1859 if smallest.as_ref().is_none_or(|best| bytes.len() < best.len()) {
1860 smallest = Some(bytes);
1861 }
1862 }
1863 assert_eq!(smallest.as_deref(), Some(chosen.as_slice()), "{}", values.len());
1864 }
1865 }
1866
1867 #[test]
1868 fn a_column_of_whole_seconds_in_microseconds_pays_nothing_for_the_zeroes() {
1869 let mut random = Random::new();
1873 let day = 1_374_000_000_000_000i64;
1874 let values: Vec<i64> =
1875 (0..100_000).map(|_| day + (random.next() % 68_400) as i64 * 1_000_000).collect();
1876 let bytes = round_trip(&values);
1877 assert_eq!(kind_of(&bytes), Kind::Strided);
1878 assert!(describe(&bytes).unwrap().starts_with("STRIDE[1000000]"), "{:?}", describe(&bytes));
1879 let strided = 100_000 * 17 / 8;
1881 assert!(bytes.len() < strided + 2000, "{} bytes for {strided} of payload", bytes.len());
1882
1883 let plain = encode_only(Kind::Packed, &values).unwrap().expect("packing always applies");
1884 assert!(
1885 bytes.len() * 2 < plain.len(),
1886 "{} strided against {} packed",
1887 bytes.len(),
1888 plain.len()
1889 );
1890 }
1891
1892 #[test]
1893 fn a_stride_is_the_common_factor_of_the_distances_from_the_smallest_value() {
1894 assert_eq!(stride_of(&[10i64, 20, 40]), Some(10));
1895 assert_eq!(stride_of(&[7i64, 17, 37]), Some(10));
1898 assert_eq!(stride_of(&[10i64, 20, 23]), None);
1899 assert_eq!(stride_of(&[5i64; 100]), None);
1902 assert_eq!(stride_of(&[]), None);
1903 assert_eq!(stride_of(&[i64::MIN, i64::MAX]), Some(u64::MAX));
1905 }
1906
1907 #[test]
1908 fn a_stride_across_the_whole_of_the_type_round_trips() {
1909 for values in [vec![i64::MIN, i64::MAX], vec![i64::MIN, 0, i64::MAX]] {
1912 let bytes = round_trip(&values);
1913 assert_eq!(decode(&bytes).unwrap(), values);
1914 }
1915 }
1916
1917 #[test]
1918 fn a_column_with_no_common_factor_is_not_offered_a_stride() {
1919 let mut random = Random::new();
1920 let values: Vec<i64> = (0..2000).map(|_| (random.next() % 1_000_000) as i64).collect();
1921 assert!(!offered(&values).contains(&Kind::Strided));
1922 assert!(encode_only(Kind::Strided, &values).unwrap().is_none());
1923 }
1924
1925 #[test]
1926 fn an_empty_chunk_round_trips() {
1927 let bytes = round_trip(&[]);
1928 assert_eq!(bytes.len(), 5);
1929 }
1930
1931 #[test]
1932 fn a_constant_column_costs_thirteen_bytes_however_long_it_is() {
1933 let bytes = round_trip(&vec![42; 1_000_000]);
1934 assert_eq!(kind_of(&bytes), Kind::Constant);
1935 assert_eq!(bytes.len(), 13);
1936 }
1937
1938 #[test]
1939 fn a_narrow_range_is_packed_at_the_width_of_the_range_and_not_of_the_type() {
1940 let mut random = Random::new();
1942 let values: Vec<i64> = (0..100_000).map(|_| 1000 + (random.next() % 64) as i64).collect();
1943 let bytes = round_trip(&values);
1944 assert_eq!(kind_of(&bytes), Kind::Packed);
1945 let packed = 100_000 * 6 / 8;
1946 assert!(bytes.len() < packed + 2000, "{} bytes for {packed} of payload", bytes.len());
1947 assert!(bytes.len() > packed, "{} bytes cannot hold {packed}", bytes.len());
1948 }
1949
1950 #[test]
1951 fn a_counter_becomes_deltas_and_then_a_constant() {
1952 let values: Vec<i64> = (0..1_000_000).collect();
1955 let bytes = round_trip(&values);
1956 assert_eq!(kind_of(&bytes), Kind::Delta);
1957 assert_eq!(describe(&bytes).unwrap(), "DELTA(CONSTANT)");
1958 assert!(bytes.len() < 40, "{} bytes for a counter", bytes.len());
1959 }
1960
1961 #[test]
1962 fn a_column_that_counts_down_is_as_cheap_as_one_that_counts_up() {
1963 let up: Vec<i64> = (0..100_000).collect();
1965 let down: Vec<i64> = (0..100_000).rev().collect();
1966 assert_eq!(round_trip(&up).len(), round_trip(&down).len());
1967 }
1968
1969 #[test]
1970 fn long_runs_become_rle() {
1971 let mut values = Vec::new();
1972 for run in 0..1000 {
1973 values.extend(std::iter::repeat_n(run % 7, 200));
1974 }
1975 let bytes = round_trip(&values);
1976 assert_eq!(kind_of(&bytes), Kind::Rle);
1977 assert!(bytes.len() < 2000, "{} bytes for 1000 runs", bytes.len());
1978 }
1979
1980 #[test]
1981 fn a_low_cardinality_column_becomes_a_dictionary() {
1982 let mut random = Random::new();
1988 let dictionary: Vec<i64> =
1989 (0..40).map(|_| 1_000_000_000 + (random.next() % (1 << 30)) as i64).collect();
1990 let values: Vec<i64> =
1991 (0..100_000).map(|_| dictionary[(random.next() % 40) as usize]).collect();
1992 let bytes = round_trip(&values);
1993 assert_eq!(kind_of(&bytes), Kind::Dict);
1994 assert!(bytes.len() < 100_000, "{} bytes", bytes.len());
1995 }
1996
1997 #[test]
1998 fn a_nearly_constant_column_becomes_sparse() {
1999 let mut values = vec![0i64; 100_000];
2000 for index in 0..300 {
2001 values[index * 331] = 1 << 40;
2002 }
2003 let bytes = round_trip(&values);
2004 assert_eq!(kind_of(&bytes), Kind::Sparse);
2005 assert!(bytes.len() < 3000, "{} bytes for 300 exceptions", bytes.len());
2006 }
2007
2008 #[test]
2009 fn encoded_counts_match_decoded_rows_across_integer_shapes() {
2010 let mut sparse = vec![0_i64; 4096];
2011 for (index, value) in [(7, -3), (91, 12), (1001, -3), (3000, 12)] {
2012 sparse[index] = value;
2013 }
2014 let mut runs = Vec::new();
2015 for value in [0, 7, 0, -5] {
2016 runs.extend(std::iter::repeat_n(value, 500));
2017 }
2018 let mut random = Random::new();
2019 let packed = (0..2000).map(|_| (random.next() % 251) as i64).collect::<Vec<_>>();
2020 for values in [vec![0_i64; 1024], sparse, runs, packed] {
2021 let bytes = encode(&values).unwrap();
2022 let (rows, counts) = tally(&bytes).unwrap();
2023 let mut expected = BTreeMap::<i64, u64>::new();
2024 for value in decode(&bytes).unwrap() {
2025 *expected.entry(value).or_default() += 1;
2026 }
2027 assert_eq!(rows, values.len());
2028 assert_eq!(counts, expected.into_iter().collect::<Vec<_>>());
2029 }
2030 }
2031
2032 #[test]
2033 fn folded_sparse_exceptions_keep_the_last_value_at_a_repeated_position() {
2034 let mut bytes = vec![Kind::Sparse.tag()];
2035 put_u32(&mut bytes, 10);
2036 put_i64(&mut bytes, 0);
2037 put_u32(&mut bytes, 2);
2038 bytes.extend(encode(&[7, 7]).unwrap());
2039 bytes.extend(encode(&[3, 5]).unwrap());
2040
2041 let mut counts = BTreeMap::<i64, u64>::new();
2042 assert_eq!(
2043 fold(&bytes, |value, count| {
2044 *counts.entry(value).or_default() += count;
2045 Ok(())
2046 })
2047 .unwrap(),
2048 10
2049 );
2050 assert_eq!(counts, BTreeMap::from([(0, 9), (5, 1)]));
2051 assert_eq!(decode(&bytes).unwrap()[7], 5);
2052 }
2053
2054 #[test]
2055 fn the_cascade_goes_more_than_one_level_deep() {
2056 let mut values = Vec::new();
2059 for index in 0..2000i64 {
2060 values.extend(std::iter::repeat_n(1_000_000 + (index % 5) * 104_729, 100));
2061 }
2062 let bytes = round_trip(&values);
2063 let shape = describe(&bytes).unwrap();
2064 assert!(shape.contains('('), "{shape} is not a cascade");
2065 assert!(bytes.len() < 4000, "{} bytes: {shape}", bytes.len());
2066 }
2067
2068 #[test]
2069 fn random_data_is_packed_at_full_width_and_costs_what_it_costs() {
2070 let mut random = Random::new();
2073 let values: Vec<i64> = (0..10_000).map(|_| random.next() as i64).collect();
2074 let bytes = round_trip(&values);
2075 assert_eq!(kind_of(&bytes), Kind::Packed);
2076 assert!(bytes.len() < 10_000 * 8 + 1000, "{} bytes", bytes.len());
2077 }
2078
2079 #[test]
2080 fn the_extremes_of_the_type_survive() {
2081 let values = vec![i64::MIN, i64::MAX, 0, -1, i64::MIN, i64::MAX];
2084 round_trip(&values);
2085 round_trip(&[i64::MIN; 3]);
2086 round_trip(&[i64::MIN, i64::MIN + 1]);
2087 }
2088
2089 #[test]
2090 fn a_chunk_that_is_not_a_multiple_of_the_unit_round_trips() {
2091 for len in [1, 2, 1023, 1024, 1025, 2047, 2049] {
2092 let values: Vec<i64> = (0..len).map(|index| (index * 31 % 97) as i64).collect();
2093 round_trip(&values);
2094 }
2095 }
2096
2097 #[test]
2098 fn units_of_different_widths_in_one_chunk_do_not_read_each_others_leftovers() {
2099 let mut random = Random::new();
2111 let mut values = Vec::new();
2112 for width in [40u32, 3, 61, 1, 17, 40] {
2113 for _ in 0..1024 {
2114 values.push((random.next() & ((1u64 << width) - 1)) as i64);
2115 }
2116 }
2117 let bytes = encode(&values).unwrap();
2118 let described = describe(&bytes).unwrap();
2119 assert!(described.starts_with("FOR+BITPACK"), "expected one packed chunk, got {described}");
2120 assert_eq!(decode(&bytes).unwrap(), values, "{described}");
2121 }
2122
2123 #[test]
2124 fn a_chunk_that_cascades_more_than_one_level_deep_decodes_whole() {
2125 let mut values = Vec::new();
2130 for index in 0..8192i64 {
2131 values.push(1_600_000_000 + index / 4 + (index % 7) * 1_000);
2132 }
2133 let bytes = encode(&values).unwrap();
2134 let described = describe(&bytes).unwrap();
2135 assert!(described.contains('('), "expected a cascade, got {described}");
2136 assert_eq!(decode(&bytes).unwrap(), values, "{described}");
2137 }
2138
2139 #[test]
2140 fn selected_positions_agree_with_a_full_decode_for_every_kind_with_a_point_form() {
2141 let positions = [0, 1, 17, 1023, 1024, 4097, 8191];
2142 let packed: Vec<i64> = (0..8192).map(|index| index * 31 % 1_000_003).collect();
2143 let mut runs = Vec::new();
2144 for run in 0..160i64 {
2145 runs.extend(std::iter::repeat_n(run * 13, (run as usize % 71) + 2));
2146 }
2147 runs.resize(8192, -7);
2148 let strided: Vec<i64> = (0..8192).map(|index| 500 + index * 7 % 5003 * 100).collect();
2149 let coded: Vec<i64> =
2150 (0..8192).map(|index| [-9_000_000_000, 3, 77, 1 << 40][index % 4]).collect();
2151
2152 for (kind, values) in [
2153 (Kind::Packed, packed),
2154 (Kind::Rle, runs),
2155 (Kind::Strided, strided),
2156 (Kind::Dict, coded),
2157 ] {
2158 let bytes = encode_only(kind, &values).unwrap().expect("encoding applies");
2159 let selected = decode_selected(&bytes, &positions).unwrap();
2160 let expected = positions.iter().map(|&position| values[position]).collect::<Vec<_>>();
2161 assert_eq!(selected, expected, "{}", kind.name());
2162 let shape = describe(&bytes).unwrap();
2163 let simple = !shape.contains("RLE") && !shape.contains("DELTA");
2164 assert_eq!(pointed(&bytes), simple, "{shape}");
2165 assert_eq!(run_length(&bytes), kind == Kind::Rle, "{shape}");
2166 }
2167 }
2168
2169 #[test]
2170 fn selected_positions_must_be_ordered_and_inside_the_chunk() {
2171 let bytes = encode_only(Kind::Packed, &(0..2048).collect::<Vec<_>>())
2172 .unwrap()
2173 .expect("packed applies");
2174 assert!(decode_selected(&bytes, &[7, 7]).is_err());
2175 assert!(decode_selected(&bytes, &[8, 3]).is_err());
2176 assert!(decode_selected(&bytes, &[2048]).is_err());
2177 }
2178
2179 #[test]
2180 fn a_partial_unit_costs_its_own_values_and_not_a_whole_unit() {
2181 let values = vec![1i64 << 39, (1 << 39) + 7, 1 << 38];
2185 let bytes = encode_only(Kind::Packed, &values).unwrap().unwrap();
2186 assert_eq!(bytes.len(), 5 + 9 + 15);
2187 assert_eq!(decode(&bytes).unwrap(), values);
2188 }
2189
2190 #[test]
2191 fn the_frame_of_reference_is_per_unit_and_not_per_chunk() {
2192 let values: Vec<i64> =
2196 (0..4096i64).map(|index| (index / 1024) * 1_000_000 + (index % 1024)).collect();
2197 let bytes = encode_only(Kind::Packed, &values).unwrap().unwrap();
2198 assert_eq!(describe(&bytes).unwrap(), "FOR+BITPACK[10]");
2199 assert_eq!(decode(&bytes).unwrap(), values);
2200 }
2201
2202 #[test]
2203 fn every_candidate_that_applies_decodes_to_the_input() {
2204 let mut values = vec![5i64; 3000];
2208 for (index, value) in values.iter_mut().enumerate() {
2209 if index % 500 == 0 {
2210 *value = index as i64;
2211 }
2212 }
2213 let applicable = candidates(&values, 0, &EXHAUSTIVE);
2214 assert!(applicable.len() >= 4, "{applicable:?}");
2215 for kind in applicable {
2216 let bytes = encode_only(kind, &values).unwrap().unwrap();
2217 assert_eq!(decode(&bytes).unwrap(), values, "{}", kind.name());
2218 }
2219 }
2220
2221 #[test]
2226 fn every_kind_that_applies_decodes_to_what_it_was_given() {
2227 let shapes: Vec<Vec<i64>> = vec![
2228 Vec::new(),
2229 vec![5; 1024],
2230 vec![i64::MIN, i64::MAX, 0, -1],
2231 (0..1024).map(|at| at * 7).collect(),
2232 (0..1024).map(|at| at % 17).collect(),
2233 (0..1024).map(|at| if at % 100 == 0 { at } else { 3 }).collect(),
2234 (0..1024).map(|at| -at * 1_000_003).collect(),
2235 (0..1024_i64)
2236 .map(|at| {
2237 at.wrapping_mul(6_364_136_223_846_793_005)
2238 .wrapping_add(1_442_695_040_888_963_407)
2239 })
2240 .collect(),
2241 ];
2242 let kinds =
2243 [Kind::Constant, Kind::Packed, Kind::Delta, Kind::Rle, Kind::Dict, Kind::Sparse];
2244 for values in &shapes {
2245 for kind in kinds {
2246 let Some(bytes) = encode_only(kind, values).unwrap() else {
2247 continue;
2248 };
2249 assert_eq!(
2250 &decode(&bytes).unwrap(),
2251 values,
2252 "{} over {} values",
2253 kind.name(),
2254 values.len()
2255 );
2256 }
2257 }
2258 }
2259
2260 #[test]
2261 fn the_chooser_picks_the_smallest_candidate_rather_than_the_first_that_applies() {
2262 let mut values = vec![5i64; 3000];
2263 values[1500] = 9;
2264 let chosen = encode(&values).unwrap();
2265 for (_, size) in candidate_sizes(&values).unwrap() {
2266 assert!(chosen.len() <= size);
2267 }
2268 }
2269
2270 #[test]
2271 fn a_truncated_chunk_is_an_error_and_not_a_panic() {
2272 let bytes = encode(&[1, 2, 3, 4, 5]).unwrap();
2273 for len in 0..bytes.len() {
2274 let error = decode(&bytes[..len]).unwrap_err();
2275 assert!(error.message().contains("chunk"), "{error}");
2276 }
2277 }
2278
2279 #[test]
2280 fn trailing_bytes_are_an_error() {
2281 let mut bytes = encode(&[1, 2, 3]).unwrap();
2282 bytes.push(0);
2283 let error = decode(&bytes).unwrap_err();
2284 assert!(error.message().contains("left over"), "{error}");
2285 }
2286
2287 #[test]
2288 fn an_unknown_tag_is_an_error() {
2289 let error = decode(&[99, 0, 0, 0, 0]).unwrap_err();
2290 assert!(error.message().contains("unknown encoding tag"), "{error}");
2291 }
2292
2293 #[test]
2294 fn a_dictionary_code_outside_the_dictionary_is_an_error() {
2295 let mut bytes = vec![Kind::Dict.tag()];
2300 put_u32(&mut bytes, 1);
2301 bytes.extend_from_slice(&encode(&[10]).unwrap());
2302 bytes.extend_from_slice(&encode(&[5]).unwrap());
2303 let error = decode(&bytes).unwrap_err();
2304 assert!(error.message().contains("not in the dictionary"), "{error}");
2305 }
2306
2307 #[test]
2308 fn a_negative_run_length_is_an_error() {
2309 let mut bytes = vec![Kind::Rle.tag()];
2312 put_u32(&mut bytes, 4);
2313 bytes.extend_from_slice(&encode(&[7]).unwrap());
2314 bytes.extend_from_slice(&encode(&[-4]).unwrap());
2315 let error = decode(&bytes).unwrap_err();
2316 assert!(error.message().contains("negative"), "{error}");
2317 }
2318
2319 #[test]
2321 fn a_run_that_runs_past_its_chunk_is_an_error() {
2322 let mut bytes = vec![Kind::Rle.tag()];
2327 put_u32(&mut bytes, 4);
2328 bytes.extend_from_slice(&encode(&[7]).unwrap());
2329 bytes.extend_from_slice(&encode(&[9]).unwrap());
2330 let error = decode(&bytes).unwrap_err();
2331 assert!(error.message().contains("past its chunk"), "{error}");
2332 }
2333
2334 #[test]
2336 fn runs_shorter_and_longer_than_the_width_they_are_written_in_all_come_back() {
2337 let lengths = [1, 3, 7, 8, 9, 40, 2, 1];
2342 let mut values = Vec::new();
2343 for (at, length) in lengths.iter().enumerate() {
2344 let value = i64::try_from(at).expect("eight runs") * 1000 - 3;
2345 values.extend(std::iter::repeat_n(value, *length));
2346 }
2347 let bytes = encode(&values).expect("encodes");
2348 assert_eq!(decode(&bytes).expect("decodes"), values, "runs around the write width");
2349 let singles: Vec<i64> = (0..300).map(|index| index * 7 % 11).collect();
2352 let bytes = encode(&singles).expect("encodes");
2353 assert_eq!(decode(&bytes).expect("decodes"), singles, "no run longer than one");
2354 }
2355
2356 #[test]
2357 fn the_cascade_depth_is_bounded() {
2358 let values: Vec<i64> = (0..50_000).map(|index| (index / 100) % 250).collect();
2362 let bytes = round_trip(&values);
2363 let shape = describe(&bytes).unwrap();
2364 let depth = shape.matches('(').count();
2365 assert!(depth <= MAX_DEPTH as usize, "{shape} is {depth} deep");
2366 }
2367
2368 #[test]
2369 fn candidate_sizes_reports_what_the_chooser_looked_at() {
2370 let values: Vec<i64> = (0..5000).map(|index| index % 17 * 1000).collect();
2371 let sizes = candidate_sizes(&values).unwrap();
2372 assert!(sizes.iter().any(|(kind, _)| *kind == Kind::Dict));
2373 assert!(sizes.iter().any(|(kind, _)| *kind == Kind::Packed));
2374 assert!(sizes.iter().all(|(_, size)| *size > 0));
2375 }
2376
2377 #[test]
2378 fn a_chunk_can_be_read_from_the_front_of_a_longer_buffer() {
2379 let first = encode(&[1, 2, 3]).unwrap();
2382 let second: Vec<i64> = (0..3000).map(|index| index % 11).collect();
2383 let second_bytes = encode(&second).unwrap();
2384 let mut joined = first.clone();
2385 joined.extend_from_slice(&second_bytes);
2386 joined.extend_from_slice(b"and then something else");
2387
2388 let (values, used) = decode_prefix(&joined).unwrap();
2389 assert_eq!(values, vec![1, 2, 3]);
2390 assert_eq!(used, first.len());
2391 let (more, used_again) = decode_prefix(&joined[used..]).unwrap();
2392 assert_eq!(more, second);
2393 assert_eq!(used_again, second_bytes.len());
2394
2395 let (text, described) = describe_prefix(&joined).unwrap();
2396 assert_eq!(described, first.len());
2397 assert_eq!(text, describe(&first).unwrap());
2398 }
2399
2400 #[test]
2401 fn a_truncated_chunk_is_still_an_error_when_read_as_a_prefix() {
2402 let bytes = encode(&(0..2000).collect::<Vec<i64>>()).unwrap();
2403 for len in 0..bytes.len() {
2404 assert!(decode_prefix(&bytes[..len]).is_err(), "{len} bytes decoded");
2405 }
2406 }
2407
2408 #[test]
2411 fn decoding_into_a_narrow_type_agrees_with_the_wide_decoder() {
2412 let columns: Vec<Vec<i64>> = vec![
2413 vec![7; 3000],
2414 (0..3000).map(|i| (i * 37) % 200 - 100).collect(),
2415 (0..3000).map(|i| if i % 97 == 0 { i % 50 } else { 0 }).collect(),
2416 (0..3000).map(|i| i / 250).collect(),
2417 (0..3000).map(|i| i * 3 + 11).collect(),
2418 (0..3000).map(|i| [5, -9, 120][i as usize % 3]).collect(),
2419 ];
2420 let kinds = [
2421 Kind::Constant,
2422 Kind::Packed,
2423 Kind::Delta,
2424 Kind::Rle,
2425 Kind::Dict,
2426 Kind::Sparse,
2427 Kind::Strided,
2428 ];
2429 for values in &columns {
2430 for kind in kinds {
2431 let Some(bytes) = encode_only(kind, values).unwrap() else { continue };
2432 let wide = decode(&bytes).unwrap();
2433 let as_i16: Vec<i64> =
2434 decode_as::<i16>(&bytes).unwrap().into_iter().map(i64::from).collect();
2435 let as_i32: Vec<i64> =
2436 decode_as::<i32>(&bytes).unwrap().into_iter().map(i64::from).collect();
2437 assert_eq!(as_i16, wide, "{kind:?} as i16");
2438 assert_eq!(as_i32, wide, "{kind:?} as i32");
2439 assert_eq!(decode_as::<i64>(&bytes).unwrap(), wide, "{kind:?} as i64");
2440 }
2441 let chosen = encode(values).unwrap();
2442 let narrow: Vec<i64> =
2443 decode_as::<i16>(&chosen).unwrap().into_iter().map(i64::from).collect();
2444 assert_eq!(narrow, decode(&chosen).unwrap(), "the chosen cascade as i16");
2445 }
2446 }
2447
2448 #[test]
2450 fn decoding_into_a_narrow_type_takes_what_fits_and_refuses_what_does_not() {
2451 fn check<T: Lane + TryFrom<i64> + PartialEq + std::fmt::Debug>(edges: [i64; 2]) {
2452 for edge in edges {
2453 for value in [edge - 1, edge, edge + 1] {
2454 for kind in
2455 [Kind::Constant, Kind::Packed, Kind::Rle, Kind::Sparse, Kind::Strided]
2456 {
2457 let values = [value, value, edges[0].max(0).min(edges[1]), value];
2458 let Some(bytes) = encode_only(kind, &values).unwrap() else { continue };
2459 let fits = values.iter().all(|&value| T::try_from(value).is_ok());
2460 assert_eq!(decode_as::<T>(&bytes).is_ok(), fits, "{value} {kind:?}");
2461 }
2462 }
2463 }
2464 }
2465 check::<i8>([-128, 127]);
2466 check::<u8>([0, 255]);
2467 check::<i16>([-32_768, 32_767]);
2468 check::<u16>([0, 65_535]);
2469 check::<i32>([i64::from(i32::MIN), i64::from(i32::MAX)]);
2470 check::<u32>([0, i64::from(u32::MAX)]);
2471 }
2472
2473 #[test]
2476 fn a_packed_block_wider_than_its_type_still_decodes_when_its_values_fit() {
2477 let values: Vec<i64> = (0..1500).map(|i| if i % 2 == 0 { -5 } else { 32_767 }).collect();
2478 let bytes = encode_only(Kind::Packed, &values).unwrap().expect("packing always applies");
2479 let narrow: Vec<i64> =
2480 decode_as::<i16>(&bytes).unwrap().into_iter().map(i64::from).collect();
2481 assert_eq!(narrow, values);
2482 let over: Vec<i64> = values.iter().map(|&value| value + 1).collect();
2483 let bytes = encode_only(Kind::Packed, &over).unwrap().expect("packing always applies");
2484 assert!(decode_as::<i16>(&bytes).is_err(), "32768 is not an i16");
2485 }
2486}