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 = with_decoding(|scratch| decode_chunk(&mut reader, scratch))?;
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 = with_decoding(|scratch| decode_chunk_as(&mut reader, scratch))?;
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, values) = with_decoding(|scratch| -> Result<_> {
287 Ok((decode_chunk(&mut reader, scratch)?, decode_chunk(&mut reader, scratch)?))
288 })?;
289 if positions.len() != exception_count || values.len() != exception_count {
290 return Err(Error::internal("a sparse chunk disagrees about its exception count"));
291 }
292 let mut ordered = true;
293 let mut previous = None;
294 for &position in &positions {
295 let position = usize::try_from(position)
296 .ok()
297 .filter(|&position| position < count)
298 .ok_or_else(|| Error::internal("a sparse exception is outside the chunk"))?;
299 if previous.is_some_and(|last| position <= last) {
300 ordered = false;
301 }
302 previous = Some(position);
303 }
304 if ordered {
305 if count != exception_count {
306 emit(dominant, (count - exception_count) as u64)?;
307 }
308 for value in values {
309 emit(value, 1)?;
310 }
311 } else {
312 let mut exceptions = BTreeMap::<usize, i64>::new();
315 for (position, value) in positions.into_iter().zip(values) {
316 exceptions.insert(position as usize, value);
317 }
318 if count != exceptions.len() {
319 emit(dominant, (count - exceptions.len()) as u64)?;
320 }
321 for value in exceptions.into_values() {
322 emit(value, 1)?;
323 }
324 }
325 }
326 Kind::Rle => {
327 let (values, lengths) = with_decoding(|scratch| -> Result<_> {
328 Ok((decode_chunk(&mut reader, scratch)?, decode_chunk(&mut reader, scratch)?))
329 })?;
330 if values.len() != lengths.len() {
331 return Err(Error::internal("an RLE chunk has more runs than run lengths"));
332 }
333 let mut rows = 0_usize;
334 for (value, length) in values.into_iter().zip(lengths) {
335 let length = usize::try_from(length)
336 .map_err(|_| Error::internal("a negative RLE run length"))?;
337 rows = rows
338 .checked_add(length)
339 .filter(|&rows| rows <= count)
340 .ok_or_else(|| Error::internal("an RLE run ends past its chunk"))?;
341 if length != 0 {
342 emit(value, length as u64)?;
343 }
344 }
345 check_count(rows, count)?;
346 }
347 _ => {
348 reader = Reader::new(bytes);
350 let values = with_decoding(|scratch| decode_chunk(&mut reader, scratch))?;
351 check_count(values.len(), count)?;
352 for value in values {
353 emit(value, 1)?;
354 }
355 }
356 }
357 if reader.remaining() != 0 {
358 return Err(Error::internal(format!(
359 "{} bytes left over after counting a chunk",
360 reader.remaining()
361 )));
362 }
363 Ok(count)
364}
365
366const SPARSE: usize = 32;
369
370pub fn decode_selected(bytes: &[u8], positions: &[usize]) -> Result<Vec<i64>> {
381 if positions.windows(2).any(|pair| pair[0] >= pair[1]) {
382 return Err(Error::internal("selected integer positions are not sorted and unique"));
383 }
384 let mut reader = Reader::new(bytes);
385 let values = with_decoding(|scratch| decode_selected_chunk(&mut reader, positions, scratch))?;
386 if reader.remaining() != 0 {
387 return Err(Error::internal(format!(
388 "{} bytes left over after decoding selected values",
389 reader.remaining()
390 )));
391 }
392 Ok(values)
393}
394
395#[must_use]
402pub fn pointed(bytes: &[u8]) -> bool {
403 let simple = |bytes: &[u8]| {
404 bytes
405 .first()
406 .and_then(|&tag| Kind::from_tag(tag).ok())
407 .is_some_and(|kind| matches!(kind, Kind::Constant | Kind::Packed))
408 };
409 match bytes.first().and_then(|&tag| Kind::from_tag(tag).ok()) {
410 Some(Kind::Constant | Kind::Packed) => true,
411 Some(Kind::Strided) => bytes.get(1 + 4 + 8 + 8..).is_some_and(simple),
413 Some(Kind::Dict) => {
415 let mut reader = Reader::new(bytes.get(1 + 4..).unwrap_or_default());
416 skip_chunk(&mut reader).is_ok() && simple(reader.rest())
417 }
418 _ => false,
419 }
420}
421
422pub fn decode_prefix(bytes: &[u8]) -> Result<(Vec<i64>, usize)> {
432 let mut reader = Reader::new(bytes);
433 let values = with_decoding(|scratch| decode_chunk(&mut reader, scratch))?;
434 Ok((values, reader.used()))
435}
436
437pub fn describe_prefix(bytes: &[u8]) -> Result<(String, usize)> {
443 let mut reader = Reader::new(bytes);
444 let text = describe_chunk(&mut reader)?;
445 Ok((text, reader.used()))
446}
447
448pub fn candidate_sizes(values: &[i64]) -> Result<Vec<(Kind, usize)>> {
455 let mut sizes = Vec::new();
456 for kind in candidates(values, 0, &EXHAUSTIVE) {
457 if let Some(bytes) = encode_as(kind, values, 0, &EXHAUSTIVE)? {
458 sizes.push((kind, bytes.len()));
459 }
460 }
461 Ok(sizes)
462}
463
464#[must_use]
471pub fn offered(values: &[i64]) -> Vec<Kind> {
472 candidates(values, 0, &EXHAUSTIVE)
473}
474
475pub fn encode_only(kind: Kind, values: &[i64]) -> Result<Option<Vec<u8>>> {
486 encode_as(kind, values, 0, &EXHAUSTIVE)
487}
488
489pub(crate) fn size_as(kind: Kind, values: &[i64], depth: u8) -> Result<Option<usize>> {
494 Ok(encode_as(kind, values, depth, &EXHAUSTIVE)?.map(|bytes| bytes.len()))
495}
496
497pub fn shape(bytes: &[u8]) -> Result<Vec<Kind>> {
509 let mut reader = Reader::new(bytes);
510 let mut kinds = Vec::new();
511 shape_chunk(&mut reader, &mut kinds)?;
512 Ok(kinds)
513}
514
515pub fn describe(bytes: &[u8]) -> Result<String> {
521 let mut reader = Reader::new(bytes);
522 describe_chunk(&mut reader)
523}
524
525fn encode_at(values: &[i64], depth: u8, chooser: &dyn Chooser) -> Result<Vec<u8>> {
526 let started = Instant::now();
527 let offered = candidates(values, depth, chooser);
528 let narrowed = chooser.narrow_integers(values, &offered, depth);
529 let counted = depth == 0;
531 if counted {
532 tally::chose(Family::Integer, started);
533 }
534 let mut best: Option<(Kind, Vec<u8>)> = None;
535 for kind in narrowed {
536 let encoded = if counted {
537 tally::offer(Family::Integer, kind.tag(), || encode_as(kind, values, depth, chooser))?
538 } else {
539 encode_as(kind, values, depth, chooser)?
540 };
541 let Some(bytes) = encoded else {
542 continue;
543 };
544 if best.as_ref().is_none_or(|(_, current)| bytes.len() < current.len()) {
545 best = Some((kind, bytes));
546 }
547 }
548 let (kind, bytes) = best.ok_or_else(|| Error::internal("no encoding applied to the chunk"))?;
551 if counted {
552 tally::kept(Family::Integer, kind.tag());
553 }
554 Ok(bytes)
555}
556
557fn candidates(values: &[i64], depth: u8, chooser: &dyn Chooser) -> Vec<Kind> {
568 let mut kinds = vec![Kind::Packed];
569 if depth >= MAX_DEPTH {
570 return kinds;
571 }
572 let Some(profile) = Profile::of(values) else {
573 return kinds;
574 };
575 if profile.runs == 1 {
576 return vec![Kind::Constant];
578 }
579 let considered = |kind| chooser.considers_integer(kind, depth);
580 let fits = profile.max.checked_sub(profile.min).is_some();
583 if considered(Kind::Delta)
584 && (if fits { profile.deltas_pay(values) } else { deltas_fit(values) })
585 {
586 kinds.push(Kind::Delta);
587 }
588 if considered(Kind::Rle) && profile.runs * 4 <= values.len() * 3 {
589 kinds.push(Kind::Rle);
590 }
591 if considered(Kind::Dict) && profile.width() > 1 {
595 let distinct = spread_of(values).0;
596 if distinct * 2 <= values.len() && width_of(distinct as u64 - 1) < profile.width() {
597 kinds.push(Kind::Dict);
598 }
599 }
600 if considered(Kind::Sparse)
604 && (profile.runs - 1) * 5 <= values.len() * 2
605 && majority(values).is_some_and(|(_, count)| count * 10 >= values.len() * 8)
606 {
607 kinds.push(Kind::Sparse);
608 }
609 if considered(Kind::Strided) && stride_from(values, profile.min).is_some() {
610 kinds.push(Kind::Strided);
611 }
612 kinds
613}
614
615struct Profile {
629 min: i64,
630 max: i64,
631 runs: usize,
633 delta_low: u64,
636 delta_high: u64,
637 delta_runs: usize,
639}
640
641impl Profile {
642 fn of(values: &[i64]) -> Option<Self> {
643 let first = *values.first()?;
644 let (mut min, mut max, mut breaks) = (first, first, 0usize);
645 let mut last = values.get(1).map_or(0, |second| second.wrapping_sub(first));
646 let (mut delta_low, mut delta_high, mut turns) = (u64::MAX, 0u64, 0usize);
647 for (before, after) in values.iter().zip(&values[1..]) {
648 min = min.min(*after);
649 max = max.max(*after);
650 breaks += usize::from(before != after);
651 let delta = after.wrapping_sub(*before);
652 let zigzagged = zigzag(delta);
653 delta_low = delta_low.min(zigzagged);
654 delta_high = delta_high.max(zigzagged);
655 turns += usize::from(delta != last);
656 last = delta;
657 }
658 Some(Self { min, max, runs: breaks + 1, delta_low, delta_high, delta_runs: turns + 1 })
659 }
660
661 fn width(&self) -> u32 {
663 width_of(self.max.wrapping_sub(self.min) as u64)
664 }
665
666 fn deltas_pay(&self, values: &[i64]) -> bool {
674 let len = values.len();
675 let narrower = width_of(self.delta_high.wrapping_sub(self.delta_low)) < self.width();
676 let unruly = self.runs * 4 > len * 3;
679 let repeat = self.delta_runs * 4 <= len.saturating_sub(1) * 3;
680 narrower || (unruly && (repeat || few_deltas(values)))
681 }
682}
683
684fn few_deltas(values: &[i64]) -> bool {
689 let mut seen = [0i64; FEW_DELTAS];
690 let mut count = 0;
691 for pair in values.windows(2).take(FEW_DELTAS_SEEN) {
692 let delta = pair[1].wrapping_sub(pair[0]);
693 if seen[..count].contains(&delta) {
694 continue;
695 }
696 if count == FEW_DELTAS {
697 return false;
698 }
699 seen[count] = delta;
700 count += 1;
701 }
702 true
703}
704
705const FEW_DELTAS: usize = 4;
707
708const FEW_DELTAS_SEEN: usize = 64;
710
711fn width_of(range: u64) -> u32 {
713 u64::BITS - range.leading_zeros()
714}
715
716fn encode_as(
719 kind: Kind,
720 values: &[i64],
721 depth: u8,
722 chooser: &dyn Chooser,
723) -> Result<Option<Vec<u8>>> {
724 let mut out = Vec::new();
725 put_u8(&mut out, kind.tag());
726 put_u32(&mut out, u32::try_from(values.len()).map_err(|_| too_long(values.len()))?);
727 match kind {
728 Kind::Constant => {
729 let Some(first) = values.first() else {
730 return Ok(None);
731 };
732 if values.iter().any(|value| value != first) {
733 return Ok(None);
734 }
735 put_i64(&mut out, *first);
736 }
737 Kind::Packed => encode_packed(values, &mut out)?,
738 Kind::Delta => {
739 let (Some(first), Some(deltas)) = (values.first(), deltas(values)) else {
743 return Ok(None);
744 };
745 put_i64(&mut out, *first);
746 out.extend_from_slice(&encode_at(&deltas, depth + 1, chooser)?);
747 }
748 Kind::Rle => {
749 let (run_values, run_lengths) = runs(values);
750 if run_values.is_empty() {
751 return Ok(None);
752 }
753 out.extend_from_slice(&encode_at(&run_values, depth + 1, chooser)?);
754 out.extend_from_slice(&encode_at(&run_lengths, depth + 1, chooser)?);
755 }
756 Kind::Dict => {
757 let dictionary = distinct_values(values);
758 if dictionary.is_empty() {
759 return Ok(None);
760 }
761 let codes = codes_over(values, &dictionary);
762 out.extend_from_slice(&encode_at(&dictionary, depth + 1, chooser)?);
763 out.extend_from_slice(&encode_at(&codes, depth + 1, chooser)?);
764 }
765 Kind::Sparse => {
766 let Some((value, _)) = majority(values).or_else(|| spread_of(values).1) else {
770 return Ok(None);
771 };
772 let mut positions = Vec::new();
773 let mut exceptions = Vec::new();
774 for (index, other) in values.iter().enumerate() {
775 if *other != value {
776 positions.push(index as i64);
777 exceptions.push(*other);
778 }
779 }
780 put_i64(&mut out, value);
781 put_u32(
782 &mut out,
783 u32::try_from(positions.len()).map_err(|_| too_long(positions.len()))?,
784 );
785 out.extend_from_slice(&encode_at(&positions, depth + 1, chooser)?);
786 out.extend_from_slice(&encode_at(&exceptions, depth + 1, chooser)?);
787 }
788 Kind::Strided => {
789 let (Some(base), Some(stride)) = (values.iter().min().copied(), stride_of(values))
790 else {
791 return Ok(None);
792 };
793 let mut steps = Vec::with_capacity(values.len());
794 for value in values {
795 let step = offset_from(*value, base) / stride;
796 let Ok(step) = i64::try_from(step) else {
801 return Ok(None);
802 };
803 steps.push(step);
804 }
805 put_i64(&mut out, base);
806 put_u64(&mut out, stride);
807 out.extend_from_slice(&encode_at(&steps, depth + 1, chooser)?);
808 }
809 }
810 Ok(Some(out))
811}
812
813fn encode_packed(values: &[i64], out: &mut Vec<u8>) -> Result<()> {
825 let mut offsets: Vec<u64> = Vec::with_capacity(VALUES);
829 let mut packed: Vec<u64> = vec![0; bitpack::packed_len::<u64>(64)];
832 let mut transposed = bitpack::Scratch::<u64>::new();
833 for unit in values.chunks(VALUES) {
834 let base = unit.iter().copied().min().unwrap_or(0);
835 offsets.clear();
836 offsets.extend(unit.iter().map(|value| offset_from(*value, base)));
837 let width = bitpack::required_width(&offsets);
838 put_i64(out, base);
839 put_u8(out, u8::try_from(width).map_err(|_| Error::internal("impossible width"))?);
840 if unit.len() == VALUES {
841 let words = bitpack::packed_len::<u64>(width);
842 bitpack::pack_with(&offsets, width, &mut packed[..words], &mut transposed)?;
843 for word in &packed[..words] {
844 put_u64(out, *word);
845 }
846 } else {
847 bitpack::pack_tail(&offsets, width, out)?;
848 }
849 }
850 Ok(())
851}
852
853struct Decoding {
880 packed: Vec<u64>,
883}
884
885thread_local! {
886 static DECODING: std::cell::RefCell<Decoding> =
888 const { std::cell::RefCell::new(Decoding::new()) };
889}
890
891fn with_decoding<T>(run: impl FnOnce(&mut Decoding) -> T) -> T {
898 DECODING.with(|cell| match cell.try_borrow_mut() {
899 Ok(mut scratch) => run(&mut scratch),
900 Err(_) => run(&mut Decoding::new()),
901 })
902}
903
904impl Decoding {
905 const fn new() -> Self {
907 Self { packed: Vec::new() }
908 }
909
910 fn ready(&mut self) {
912 if self.packed.len() != bitpack::packed_len::<u64>(64) {
913 self.packed.resize(bitpack::packed_len::<u64>(64), 0);
914 }
915 }
916}
917
918fn decode_chunk(reader: &mut Reader<'_>, scratch: &mut Decoding) -> Result<Vec<i64>> {
919 let kind = Kind::from_tag(reader.u8()?)?;
920 let count = reader.u32()? as usize;
921 match kind {
922 Kind::Constant => Ok(vec![reader.i64()?; count]),
923 Kind::Packed => {
924 let mut values = vec![0i64; count];
928 scratch.ready();
929 let mut done = 0;
930 while done < count {
931 let base = reader.i64()?;
932 let width = reader.u8()? as usize;
933 let wanted = (count - done).min(VALUES);
934 let into = &mut values[done..done + wanted];
935 if wanted == VALUES {
936 let words = bitpack::packed_len::<u64>(width);
937 for word in &mut scratch.packed[..words] {
938 *word = reader.u64()?;
939 }
940 bitpack::unpack_mapped(&scratch.packed[..words], width, into, |offset| {
941 value_from(offset, base)
942 })?;
943 } else {
944 let bytes = reader.bytes(bitpack::tail_len(wanted, width))?;
945 bitpack::unpack_tail_into(bytes, width, into, |offset| {
946 value_from(offset, base)
947 })?;
948 }
949 done += wanted;
950 }
951 Ok(values)
952 }
953 Kind::Delta => {
954 let first = reader.i64()?;
955 let mut values = decode_chunk(reader, scratch)?;
956 check_count(values.len() + 1, count)?;
957 let mut current = first;
961 for value in &mut values {
962 let delta = unzigzag(*value as u64);
963 *value = current;
964 current = current.wrapping_add(delta);
965 }
966 values.push(current);
967 Ok(values)
968 }
969 Kind::Rle => {
970 let run_values = decode_chunk(reader, scratch)?;
971 let run_lengths = decode_chunk(reader, scratch)?;
972 expanded(&run_values, &run_lengths, count)
973 }
974 Kind::Dict => {
975 let dictionary = decode_chunk(reader, scratch)?;
976 let codes = decode_chunk(reader, scratch)?;
977 let mut values = Vec::with_capacity(count);
978 for code in codes {
979 let index =
980 usize::try_from(code).ok().and_then(|index| dictionary.get(index)).ok_or_else(
981 || Error::internal(format!("code {code} is not in the dictionary")),
982 )?;
983 values.push(*index);
984 }
985 check_count(values.len(), count)?;
986 Ok(values)
987 }
988 Kind::Sparse => {
989 let value = reader.i64()?;
990 let exception_count = reader.u32()? as usize;
991 let positions = decode_chunk(reader, scratch)?;
992 let exceptions = decode_chunk(reader, scratch)?;
993 if positions.len() != exception_count || exceptions.len() != exception_count {
994 return Err(Error::internal("a sparse chunk disagrees about its exception count"));
995 }
996 let mut values = vec![value; count];
997 for (position, exception) in positions.into_iter().zip(exceptions) {
998 let position = usize::try_from(position)
999 .ok()
1000 .filter(|position| *position < count)
1001 .ok_or_else(|| {
1002 Error::internal(format!("exception at {position} is outside the chunk"))
1003 })?;
1004 values[position] = exception;
1005 }
1006 Ok(values)
1007 }
1008 Kind::Strided => {
1009 let base = reader.i64()?;
1010 let stride = reader.u64()?;
1011 let steps = decode_chunk(reader, scratch)?;
1012 check_count(steps.len(), count)?;
1013 strided(steps, stride, base)
1014 }
1015 }
1016}
1017
1018fn strided(mut steps: Vec<i64>, stride: u64, base: i64) -> Result<Vec<i64>> {
1026 if steps.iter().fold(0, |held, &step| held | step) < 0 {
1028 return Err(Error::internal("a negative number of strides"));
1029 }
1030 for step in &mut steps {
1031 *step = base.wrapping_add((*step as u64).wrapping_mul(stride) as i64);
1032 }
1033 Ok(steps)
1034}
1035
1036fn expanded<T: Lane>(run_values: &[i64], run_lengths: &[i64], count: usize) -> Result<Vec<T>> {
1052 if run_values.len() != run_lengths.len() {
1053 return Err(Error::internal("an RLE chunk has more runs than run lengths"));
1054 }
1055 let (signs, longest, total) =
1056 run_lengths.iter().fold((0, 0, 0u128), |(signs, longest, total), &length| {
1057 (signs | length, longest.max(length), total + u128::from(length as u64))
1058 });
1059 if signs < 0 {
1060 return Err(Error::internal("a negative RLE run length"));
1061 }
1062 if total > count as u128 {
1063 return Err(Error::internal("an RLE run ends past its chunk"));
1064 }
1065 check_count(total as usize, count)?;
1066 let wide = T::fit(i64::MIN).is_some() && T::fit(i64::MAX).is_some();
1068 if !wide {
1069 let (low, high) = run_values
1070 .iter()
1071 .fold((i64::MAX, i64::MIN), |(low, high), &value| (low.min(value), high.max(value)));
1072 if !run_values.is_empty() {
1073 lane::<T>(low)?;
1074 lane::<T>(high)?;
1075 }
1076 }
1077 let runs = run_values.iter().zip(run_lengths);
1078 if run_values.len().saturating_mul(LONG_RUN) <= count {
1079 let mut values = Vec::with_capacity(count);
1080 for (&value, &length) in runs {
1081 values.resize(values.len() + length as usize, T::wrap(value));
1082 }
1083 return Ok(values);
1084 }
1085 let mut values = vec![T::default(); count + RUN];
1086 let mut at = 0;
1087 if longest as usize <= RUN {
1088 for (&value, &length) in runs {
1089 values[at..at + RUN].fill(T::wrap(value));
1090 at += length as usize;
1091 }
1092 } else {
1093 for (&value, &length) in runs {
1094 let length = length as usize;
1095 values[at..at + length.max(RUN)].fill(T::wrap(value));
1096 at += length;
1097 }
1098 }
1099 values.truncate(count);
1100 Ok(values)
1101}
1102
1103fn decode_chunk_as<T: Lane>(reader: &mut Reader<'_>, scratch: &mut Decoding) -> Result<Vec<T>> {
1105 let Some(&tag) = reader.rest().first() else {
1106 return Err(Error::internal("a chunk ended before its encoding tag"));
1107 };
1108 match Kind::from_tag(tag)? {
1109 Kind::Constant | Kind::Packed | Kind::Sparse | Kind::Rle => {}
1110 Kind::Strided => {
1113 let values = decode_chunk(reader, scratch)?;
1114 let (low, high) = values.iter().fold((i64::MAX, i64::MIN), |(low, high), &value| {
1115 (low.min(value), high.max(value))
1116 });
1117 if values.is_empty() || T::fit(low).is_some() && T::fit(high).is_some() {
1118 return Ok(values.into_iter().map(T::wrap).collect());
1119 }
1120 return values.into_iter().map(lane).collect();
1121 }
1122 _ => return decode_chunk(reader, scratch)?.into_iter().map(lane).collect(),
1123 }
1124 let kind = Kind::from_tag(reader.u8()?)?;
1125 let count = reader.u32()? as usize;
1126 match kind {
1127 Kind::Constant => Ok(vec![lane(reader.i64()?)?; count]),
1128 Kind::Packed => {
1129 let mut values = vec![T::default(); count];
1130 scratch.ready();
1131 let mut wide = [0i64; VALUES];
1132 let mut done = 0;
1133 while done < count {
1134 let base = reader.i64()?;
1135 let width = reader.u8()? as usize;
1136 let wanted = (count - done).min(VALUES);
1137 let into = &mut values[done..done + wanted];
1138 let bytes = if wanted == VALUES {
1139 let words = bitpack::packed_len::<u64>(width);
1140 for word in &mut scratch.packed[..words] {
1141 *word = reader.u64()?;
1142 }
1143 None
1144 } else {
1145 Some(reader.bytes(bitpack::tail_len(wanted, width))?)
1146 };
1147 let mask = if width >= 64 { u64::MAX } else { (1u64 << width) - 1 };
1152 let top = i64::try_from(i128::from(base) + i128::from(mask)).ok();
1153 if T::fit(base).is_some() && top.and_then(T::fit).is_some() {
1154 let map = |offset| T::wrap(value_from(offset, base));
1155 match bytes {
1156 None => {
1157 let words = bitpack::packed_len::<u64>(width);
1158 bitpack::unpack_mapped(&scratch.packed[..words], width, into, map)?;
1159 }
1160 Some(bytes) => bitpack::unpack_tail_into(bytes, width, into, map)?,
1161 }
1162 } else {
1163 let wide = &mut wide[..wanted];
1164 let map = |offset| value_from(offset, base);
1165 match bytes {
1166 None => {
1167 let words = bitpack::packed_len::<u64>(width);
1168 bitpack::unpack_mapped(&scratch.packed[..words], width, wide, map)?;
1169 }
1170 Some(bytes) => bitpack::unpack_tail_into(bytes, width, wide, map)?,
1171 }
1172 for (value, &held) in into.iter_mut().zip(wide.iter()) {
1173 *value = lane(held)?;
1174 }
1175 }
1176 done += wanted;
1177 }
1178 Ok(values)
1179 }
1180 Kind::Rle => {
1181 let run_values = decode_chunk(reader, scratch)?;
1182 let run_lengths = decode_chunk(reader, scratch)?;
1183 expanded(&run_values, &run_lengths, count)
1184 }
1185 Kind::Sparse => {
1186 let value = lane::<T>(reader.i64()?)?;
1187 let exception_count = reader.u32()? as usize;
1188 let positions = decode_chunk(reader, scratch)?;
1189 let exceptions = decode_chunk(reader, scratch)?;
1190 if positions.len() != exception_count || exceptions.len() != exception_count {
1191 return Err(Error::internal("a sparse chunk disagrees about its exception count"));
1192 }
1193 let mut values = vec![value; count];
1194 for (position, exception) in positions.into_iter().zip(exceptions) {
1195 let position = usize::try_from(position)
1196 .ok()
1197 .filter(|position| *position < count)
1198 .ok_or_else(|| {
1199 Error::internal(format!("exception at {position} is outside the chunk"))
1200 })?;
1201 values[position] = lane(exception)?;
1202 }
1203 Ok(values)
1204 }
1205 Kind::Delta | Kind::Dict | Kind::Strided => {
1206 Err(Error::internal("a chunk kind that decodes wide reached the narrow decoder"))
1207 }
1208 }
1209}
1210
1211fn decode_selected_chunk(
1212 reader: &mut Reader<'_>,
1213 positions: &[usize],
1214 scratch: &mut Decoding,
1215) -> Result<Vec<i64>> {
1216 let Some(&tag) = reader.rest().first() else {
1217 return Err(Error::internal("a chunk ended before its encoding tag"));
1218 };
1219 let kind = Kind::from_tag(tag)?;
1220 if !matches!(kind, Kind::Constant | Kind::Packed | Kind::Rle | Kind::Strided | Kind::Dict) {
1221 let values = decode_chunk(reader, scratch)?;
1222 return positions
1223 .iter()
1224 .map(|&position| {
1225 values.get(position).copied().ok_or_else(|| {
1226 Error::internal(format!(
1227 "selected integer position {position} is outside {} values",
1228 values.len()
1229 ))
1230 })
1231 })
1232 .collect();
1233 }
1234
1235 let decoded = Kind::from_tag(reader.u8()?)?;
1236 debug_assert_eq!(decoded, kind);
1237 let count = reader.u32()? as usize;
1238 if positions.last().is_some_and(|&position| position >= count) {
1239 return Err(Error::internal(format!(
1240 "selected integer position {} is outside {count} values",
1241 positions.last().expect("a last position exists")
1242 )));
1243 }
1244 match kind {
1245 Kind::Constant => {
1246 let value = reader.i64()?;
1247 Ok(vec![value; positions.len()])
1248 }
1249 Kind::Packed => {
1250 let mut out = Vec::with_capacity(positions.len());
1251 let mut from = 0;
1252 let mut done = 0;
1253 while done < count {
1254 let base = reader.i64()?;
1255 let width = reader.u8()? as usize;
1256 let wanted = (count - done).min(VALUES);
1257 let upto = positions.partition_point(|&position| position < done + wanted);
1258 if wanted == VALUES && (upto - from) * SPARSE > VALUES {
1259 let words = bitpack::packed_len::<u64>(width);
1262 scratch.ready();
1263 for word in &mut scratch.packed[..words] {
1264 *word = reader.u64()?;
1265 }
1266 let mut unit = [0_i64; VALUES];
1267 bitpack::unpack_mapped(&scratch.packed[..words], width, &mut unit, |offset| {
1268 value_from(offset, base)
1269 })?;
1270 out.extend(positions[from..upto].iter().map(|&position| unit[position - done]));
1271 } else if wanted == VALUES {
1272 let bytes = reader.bytes(bitpack::packed_len::<u64>(width) * 8)?;
1273 for &position in &positions[from..upto] {
1274 let offset = bitpack::unpack_u64_at(bytes, width, position - done)?;
1275 out.push(value_from(offset, base));
1276 }
1277 } else {
1278 let bytes = reader.bytes(bitpack::tail_len(wanted, width))?;
1279 for &position in &positions[from..upto] {
1280 let offset = bitpack::tail_at(bytes, width, position - done)?;
1281 out.push(value_from(offset, base));
1282 }
1283 }
1284 from = upto;
1285 done += wanted;
1286 }
1287 Ok(out)
1288 }
1289 Kind::Rle => {
1290 let run_value_bytes = reader.rest();
1291 let mut run_value_reader = Reader::new(run_value_bytes);
1292 let run_value_count = skip_chunk(&mut run_value_reader)?;
1293 let run_value_len = run_value_reader.used();
1294 reader.skip(run_value_len)?;
1295 let run_lengths = decode_chunk(reader, scratch)?;
1296 if run_value_count != run_lengths.len() {
1297 return Err(Error::internal("an RLE chunk has more runs than run lengths"));
1298 }
1299 let mut wanted_runs = Vec::new();
1300 let mut selected_per_run = Vec::new();
1301 let mut selected = 0;
1302 let mut at = 0usize;
1303 for (run, length) in run_lengths.into_iter().enumerate() {
1304 let length = usize::try_from(length)
1305 .map_err(|_| Error::internal("a negative RLE run length"))?;
1306 let end = at
1307 .checked_add(length)
1308 .filter(|end| *end <= count)
1309 .ok_or_else(|| Error::internal("an RLE run ends past its chunk"))?;
1310 let before = selected;
1311 while selected < positions.len() && positions[selected] < end {
1312 if positions[selected] < at {
1313 return Err(Error::internal("selected integer positions went backwards"));
1314 }
1315 selected += 1;
1316 }
1317 if selected != before {
1318 wanted_runs.push(run);
1319 selected_per_run.push(selected - before);
1320 }
1321 at = end;
1322 }
1323 check_count(at, count)?;
1324 if selected != positions.len() {
1325 return Err(Error::internal("an RLE chunk ended before a selected position"));
1326 }
1327 let run_values = decode_selected(&run_value_bytes[..run_value_len], &wanted_runs)?;
1328 let mut out = Vec::with_capacity(positions.len());
1329 for (value, repeat) in run_values.into_iter().zip(selected_per_run) {
1330 out.extend(std::iter::repeat_n(value, repeat));
1331 }
1332 Ok(out)
1333 }
1334 Kind::Strided => {
1337 let base = reader.i64()?;
1338 let stride = reader.u64()?;
1339 let steps = decode_selected_chunk(reader, positions, scratch)?;
1340 steps
1341 .into_iter()
1342 .map(|step| {
1343 let step = u64::try_from(step)
1344 .map_err(|_| Error::internal("a negative number of strides"))?;
1345 Ok(value_from(step.wrapping_mul(stride), base))
1346 })
1347 .collect()
1348 }
1349 Kind::Dict => {
1350 let dictionary = decode_chunk(reader, scratch)?;
1351 let codes = decode_selected_chunk(reader, positions, scratch)?;
1352 codes
1353 .into_iter()
1354 .map(|code| {
1355 usize::try_from(code)
1356 .ok()
1357 .and_then(|index| dictionary.get(index))
1358 .copied()
1359 .ok_or_else(|| {
1360 Error::internal(format!("code {code} is not in the dictionary"))
1361 })
1362 })
1363 .collect()
1364 }
1365 _ => unreachable!("unsupported kinds used the full decoder"),
1366 }
1367}
1368
1369fn skip_chunk(reader: &mut Reader<'_>) -> Result<usize> {
1371 let kind = Kind::from_tag(reader.u8()?)?;
1372 let count = reader.u32()? as usize;
1373 match kind {
1374 Kind::Constant => reader.skip(8)?,
1375 Kind::Packed => skip_packed(reader, count)?,
1376 Kind::Delta => {
1377 reader.skip(8)?;
1378 skip_chunk(reader)?;
1379 }
1380 Kind::Rle | Kind::Dict => {
1381 skip_chunk(reader)?;
1382 skip_chunk(reader)?;
1383 }
1384 Kind::Sparse => {
1385 reader.skip(12)?;
1386 skip_chunk(reader)?;
1387 skip_chunk(reader)?;
1388 }
1389 Kind::Strided => {
1390 reader.skip(16)?;
1391 skip_chunk(reader)?;
1392 }
1393 }
1394 Ok(count)
1395}
1396
1397fn skip_packed(reader: &mut Reader<'_>, count: usize) -> Result<()> {
1399 let mut done = 0;
1400 while done < count {
1401 reader.skip(8)?;
1402 let width = reader.u8()? as usize;
1403 if width > 64 {
1404 return Err(Error::internal(format!("a packed integer width of {width} is past 64")));
1405 }
1406 let wanted = (count - done).min(VALUES);
1407 let bytes = if wanted == VALUES {
1408 bitpack::packed_len::<u64>(width)
1409 .checked_mul(8)
1410 .ok_or_else(|| Error::internal("packed integer size overflow"))?
1411 } else {
1412 bitpack::tail_len(wanted, width)
1413 };
1414 reader.skip(bytes)?;
1415 done += wanted;
1416 }
1417 Ok(())
1418}
1419
1420fn shape_chunk(reader: &mut Reader<'_>, kinds: &mut Vec<Kind>) -> Result<()> {
1422 let kind = Kind::from_tag(reader.u8()?)?;
1423 let count = reader.u32()? as usize;
1424 kinds.push(kind);
1425 match kind {
1426 Kind::Constant => reader.skip(8)?,
1427 Kind::Packed => skip_packed(reader, count)?,
1428 Kind::Delta => {
1429 reader.skip(8)?;
1430 shape_chunk(reader, kinds)?;
1431 }
1432 Kind::Rle | Kind::Dict => {
1433 shape_chunk(reader, kinds)?;
1434 shape_chunk(reader, kinds)?;
1435 }
1436 Kind::Sparse => {
1437 reader.skip(12)?;
1438 shape_chunk(reader, kinds)?;
1439 shape_chunk(reader, kinds)?;
1440 }
1441 Kind::Strided => {
1442 reader.skip(16)?;
1443 shape_chunk(reader, kinds)?;
1444 }
1445 }
1446 Ok(())
1447}
1448
1449fn describe_chunk(reader: &mut Reader<'_>) -> Result<String> {
1450 let kind = Kind::from_tag(reader.u8()?)?;
1451 let count = reader.u32()? as usize;
1452 Ok(match kind {
1453 Kind::Constant => {
1454 reader.i64()?;
1455 "CONSTANT".to_string()
1456 }
1457 Kind::Packed => {
1458 let mut widths = Vec::new();
1459 let mut seen = 0;
1460 while seen < count {
1461 reader.i64()?;
1462 let width = reader.u8()? as usize;
1463 let wanted = (count - seen).min(VALUES);
1464 if wanted == VALUES {
1465 for _ in 0..bitpack::packed_len::<u64>(width) {
1466 reader.u64()?;
1467 }
1468 } else {
1469 reader.bytes(bitpack::tail_len(wanted, width))?;
1470 }
1471 widths.push(width);
1472 seen += wanted;
1473 }
1474 let low = widths.iter().copied().min().unwrap_or(0);
1475 let high = widths.iter().copied().max().unwrap_or(0);
1476 if low == high {
1479 format!("FOR+BITPACK[{low}]")
1480 } else {
1481 format!("FOR+BITPACK[{low}..{high}]")
1482 }
1483 }
1484 Kind::Delta => {
1485 reader.i64()?;
1486 format!("DELTA({})", describe_chunk(reader)?)
1487 }
1488 Kind::Rle => {
1489 let values = describe_chunk(reader)?;
1490 let lengths = describe_chunk(reader)?;
1491 format!("RLE({values}, {lengths})")
1492 }
1493 Kind::Dict => {
1494 let dictionary = describe_chunk(reader)?;
1495 let codes = describe_chunk(reader)?;
1496 format!("DICT({dictionary}, {codes})")
1497 }
1498 Kind::Sparse => {
1499 reader.i64()?;
1500 reader.u32()?;
1501 let positions = describe_chunk(reader)?;
1502 let exceptions = describe_chunk(reader)?;
1503 format!("SPARSE({positions}, {exceptions})")
1504 }
1505 Kind::Strided => {
1506 reader.i64()?;
1507 let stride = reader.u64()?;
1508 format!("STRIDE[{stride}]({})", describe_chunk(reader)?)
1509 }
1510 })
1511}
1512
1513fn stride_of(values: &[i64]) -> Option<u64> {
1525 stride_from(values, values.iter().min().copied()?)
1526}
1527
1528fn stride_from(values: &[i64], base: i64) -> Option<u64> {
1530 let mut divisor = 0u64;
1531 for value in values {
1532 divisor = gcd(divisor, offset_from(*value, base));
1533 if divisor == 1 {
1534 return None;
1535 }
1536 }
1537 (divisor > 1).then_some(divisor)
1540}
1541
1542fn gcd(mut left: u64, mut right: u64) -> u64 {
1544 if left == 0 {
1545 return right;
1546 }
1547 if right == 0 {
1548 return left;
1549 }
1550 let shift = (left | right).trailing_zeros();
1551 left >>= left.trailing_zeros();
1552 loop {
1553 right >>= right.trailing_zeros();
1554 if left > right {
1555 std::mem::swap(&mut left, &mut right);
1556 }
1557 right -= left;
1558 if right == 0 {
1559 return left << shift;
1560 }
1561 }
1562}
1563
1564fn offset_from(value: i64, base: i64) -> u64 {
1567 (i128::from(value) - i128::from(base)) as u64
1568}
1569
1570fn value_from(offset: u64, base: i64) -> i64 {
1571 (i128::from(base) + i128::from(offset)) as i64
1572}
1573
1574fn zigzag(value: i64) -> u64 {
1577 ((value << 1) ^ (value >> 63)) as u64
1578}
1579
1580fn unzigzag(value: u64) -> i64 {
1581 ((value >> 1) as i64) ^ -((value & 1) as i64)
1582}
1583
1584fn deltas_fit(values: &[i64]) -> bool {
1596 values.windows(2).all(|pair| pair[1].checked_sub(pair[0]).is_some())
1597}
1598
1599fn deltas(values: &[i64]) -> Option<Vec<i64>> {
1600 let mut deltas = Vec::with_capacity(values.len().saturating_sub(1));
1601 for pair in values.windows(2) {
1602 let difference = pair[1].checked_sub(pair[0])?;
1603 deltas.push(zigzag(difference) as i64);
1604 }
1605 Some(deltas)
1606}
1607
1608fn runs(values: &[i64]) -> (Vec<i64>, Vec<i64>) {
1615 let mut run_values: Vec<i64> = Vec::new();
1616 let mut run_lengths: Vec<i64> = Vec::new();
1617 let mut start = 0;
1618 while let Some(&value) = values.get(start) {
1619 let length = values[start..].iter().take_while(|other| **other == value).count();
1620 run_values.push(value);
1621 run_lengths.push(length as i64);
1622 start += length;
1623 }
1624 (run_values, run_lengths)
1625}
1626
1627fn spread_of(values: &[i64]) -> (usize, Option<(i64, usize)>) {
1642 let mut sorted = values.to_vec();
1643 sorted.sort_unstable();
1644 let mut distinct = 0;
1645 let mut best: Option<(i64, usize)> = None;
1646 let mut index = 0;
1647 while index < sorted.len() {
1648 let value = sorted[index];
1649 let mut end = index;
1650 while end < sorted.len() && sorted[end] == value {
1651 end += 1;
1652 }
1653 distinct += 1;
1654 let count = end - index;
1655 if best.is_none_or(|(_, seen)| count > seen) {
1656 best = Some((value, count));
1657 }
1658 index = end;
1659 }
1660 (distinct, best)
1661}
1662
1663fn majority(values: &[i64]) -> Option<(i64, usize)> {
1671 let mut candidate = *values.first()?;
1672 let mut lead = 0usize;
1673 for value in values {
1674 if lead == 0 {
1675 candidate = *value;
1676 lead = 1;
1677 } else if *value == candidate {
1678 lead += 1;
1679 } else {
1680 lead -= 1;
1681 }
1682 }
1683 let count = values.iter().filter(|value| **value == candidate).count();
1684 (count * 2 > values.len()).then_some((candidate, count))
1685}
1686
1687fn distinct_values(values: &[i64]) -> Vec<i64> {
1690 let mut distinct = values.to_vec();
1691 distinct.sort_unstable();
1692 distinct.dedup();
1693 distinct
1694}
1695
1696fn codes_over(values: &[i64], dictionary: &[i64]) -> Vec<i64> {
1706 values
1707 .iter()
1708 .map(|value| {
1709 dictionary
1710 .binary_search(value)
1711 .expect("the dictionary is the distinct values of this chunk") as i64
1712 })
1713 .collect()
1714}
1715
1716fn check_count(actual: usize, expected: usize) -> Result<()> {
1717 if actual == expected {
1718 Ok(())
1719 } else {
1720 Err(Error::internal(format!(
1721 "a chunk says it holds {expected} values and decoded to {actual}"
1722 )))
1723 }
1724}
1725
1726fn too_long(len: usize) -> Error {
1727 Error::internal(format!("a chunk of {len} values is longer than the format allows"))
1728}
1729
1730fn put_u8(out: &mut Vec<u8>, value: u8) {
1731 out.push(value);
1732}
1733
1734fn put_u32(out: &mut Vec<u8>, value: u32) {
1735 out.extend_from_slice(&value.to_le_bytes());
1736}
1737
1738fn put_u64(out: &mut Vec<u8>, value: u64) {
1739 out.extend_from_slice(&value.to_le_bytes());
1740}
1741
1742fn put_i64(out: &mut Vec<u8>, value: i64) {
1743 out.extend_from_slice(&value.to_le_bytes());
1744}
1745
1746#[cfg(test)]
1747mod tests {
1748 use super::*;
1749
1750 fn round_trip(values: &[i64]) -> Vec<u8> {
1751 let bytes = encode(values).unwrap();
1752 assert_eq!(decode(&bytes).unwrap(), values, "{}", describe(&bytes).unwrap());
1753 bytes
1754 }
1755
1756 fn kind_of(bytes: &[u8]) -> Kind {
1757 Kind::from_tag(bytes[0]).unwrap()
1758 }
1759
1760 struct Random(u64);
1762
1763 impl Random {
1764 fn new() -> Self {
1765 Self(0x9e37_79b9_7f4a_7c15)
1766 }
1767
1768 fn next(&mut self) -> u64 {
1769 self.0 ^= self.0 << 13;
1770 self.0 ^= self.0 >> 7;
1771 self.0 ^= self.0 << 17;
1772 self.0
1773 }
1774 }
1775
1776 #[test]
1777 fn the_dictionary_is_sorted_and_the_codes_point_back_at_the_values() {
1778 let values = vec![30i64, 10, 30, 20, 10, -5];
1779 let dictionary = distinct_values(&values);
1780 let codes = codes_over(&values, &dictionary);
1781 assert_eq!(dictionary, vec![-5, 10, 20, 30]);
1782 assert_eq!(codes, vec![3, 1, 3, 2, 1, 0]);
1783 for (code, value) in codes.iter().zip(&values) {
1784 assert_eq!(dictionary[*code as usize], *value);
1785 }
1786 }
1787
1788 #[test]
1789 fn one_sort_gives_the_distinct_count_and_the_most_frequent_value() {
1790 let values = vec![7i64, 7, 7, 1, 2, 2];
1791 assert_eq!(spread_of(&values), (3, Some((7, 3))));
1792 assert_eq!(spread_of(&[]), (0, None));
1793 assert_eq!(spread_of(&[9]), (1, Some((9, 1))));
1794
1795 assert_eq!(spread_of(&[4i64, 4, 8, 8]), (2, Some((4, 2))));
1798 }
1799
1800 #[test]
1801 fn the_majority_is_the_most_frequent_value_whenever_there_is_one() {
1802 let chunks: Vec<Vec<i64>> = vec![
1803 vec![],
1804 vec![3],
1805 vec![1, 2],
1806 vec![1, 1, 2],
1807 vec![2, 1, 1],
1808 vec![4, 4, 8, 8],
1809 vec![7, 1, 7, 2, 7, 3, 7],
1810 vec![1, 2, 3, 9, 9, 9, 9],
1811 (0..1000).map(|index| if index % 5 == 0 { index } else { -4 }).collect(),
1812 (0..1000).map(|index| index % 3).collect(),
1813 ];
1814 for chunk in chunks {
1815 let (_, dominant) = spread_of(&chunk);
1816 let expected = dominant.filter(|(_, count)| count * 2 > chunk.len());
1817 assert_eq!(majority(&chunk), expected, "{chunk:?}");
1818 }
1819 }
1820
1821 #[test]
1825 fn the_one_pass_offers_what_the_separate_tests_offered() {
1826 let mut random = Random::new();
1827 let mut chunks: Vec<Vec<i64>> = vec![
1828 vec![],
1829 vec![5],
1830 vec![5, 5, 5],
1831 vec![i64::MIN, i64::MAX],
1832 vec![i64::MAX, i64::MIN, i64::MAX],
1833 vec![i64::MIN, 0, i64::MAX],
1834 vec![-1, i64::MAX],
1835 (0..1000).map(|index| if index % 5 == 0 { index } else { -4 }).collect(),
1836 (0..1000).map(|index| if index % 4 == 0 { index } else { -4 }).collect(),
1837 (0..1000).map(|index| index / 7).collect(),
1838 (0..1000).map(|index| index * 1_000_000).collect(),
1839 ];
1840 for _ in 0..200 {
1841 let len = (random.next() % 300) as usize;
1842 let spread = 1 + random.next() % 8;
1843 let common = (random.next() % 5) as i64;
1844 chunks.push(
1845 (0..len)
1846 .map(|_| {
1847 let draw = random.next();
1848 if draw % 10 < spread { (draw >> 8) as i64 % 50 } else { common }
1849 })
1850 .collect(),
1851 );
1852 }
1853 for chunk in chunks {
1854 let mut expected = vec![Kind::Packed];
1855 if !chunk.is_empty() {
1856 if chunk.iter().all(|value| *value == chunk[0]) {
1857 expected = vec![Kind::Constant];
1858 } else {
1859 let runs = 1 + chunk.windows(2).filter(|pair| pair[0] != pair[1]).count();
1860 let low = *chunk.iter().min().unwrap();
1861 let high = *chunk.iter().max().unwrap();
1862 let bits = |range: u128| 128 - range.leading_zeros();
1863 let width = bits((i128::from(high) - i128::from(low)) as u128);
1864 let zigzags: Vec<u128> = chunk
1865 .windows(2)
1866 .map(|pair| u128::from(zigzag(pair[1].wrapping_sub(pair[0]))))
1867 .collect();
1868 let spread = zigzags.iter().max().unwrap() - zigzags.iter().min().unwrap();
1869 let turns = 1 + zigzags.windows(2).filter(|pair| pair[0] != pair[1]).count();
1870 let mut first: Vec<u128> = zigzags.iter().take(64).copied().collect();
1871 first.sort_unstable();
1872 first.dedup();
1873 let pays = bits(spread) < width
1874 || (runs * 4 > chunk.len() * 3
1875 && (turns * 4 <= (chunk.len() - 1) * 3 || first.len() <= 4));
1876 if deltas_fit(&chunk) && pays {
1877 expected.push(Kind::Delta);
1878 }
1879 if runs * 4 <= chunk.len() * 3 {
1880 expected.push(Kind::Rle);
1881 }
1882 let distinct = spread_of(&chunk).0;
1883 if distinct * 2 <= chunk.len() && bits(distinct as u128 - 1) < width {
1884 expected.push(Kind::Dict);
1885 }
1886 if majority(&chunk).is_some_and(|(_, count)| count * 10 >= chunk.len() * 8) {
1887 expected.push(Kind::Sparse);
1888 }
1889 if stride_of(&chunk).is_some() {
1890 expected.push(Kind::Strided);
1891 }
1892 }
1893 }
1894 assert_eq!(candidates(&chunk, 0, &EXHAUSTIVE), expected, "{chunk:?}");
1895 }
1896 }
1897
1898 #[test]
1899 fn runs_are_every_stretch_of_equal_neighbours_in_order() {
1900 assert_eq!(runs(&[]), (vec![], vec![]));
1901 assert_eq!(runs(&[4]), (vec![4], vec![1]));
1902 assert_eq!(runs(&[1, 1, 2, 1, 1, 1]), (vec![1, 2, 1], vec![2, 1, 3]));
1903 }
1904
1905 #[test]
1906 fn deltas_that_do_not_fit_are_refused_before_they_are_built() {
1907 assert!(deltas_fit(&[1i64, 2, 3]));
1908 assert!(deltas_fit(&[i64::MAX, i64::MAX]));
1909 assert!(!deltas_fit(&[i64::MIN, i64::MAX]));
1910 assert_eq!(deltas_fit(&[i64::MIN, i64::MAX]), deltas(&[i64::MIN, i64::MAX]).is_some());
1911 assert_eq!(deltas_fit(&[1i64, 2, 3]), deltas(&[1i64, 2, 3]).is_some());
1912 }
1913
1914 #[test]
1915 fn what_the_chooser_returns_is_the_smallest_of_what_it_was_offered() {
1916 let mut random = Random::new();
1920 let noise: Vec<i64> = (0..2000).map(|_| (random.next() % 5000) as i64).collect();
1921 let runs: Vec<i64> = (0..2000).map(|index: i64| index / 100).collect();
1922 let climbing: Vec<i64> = (0..2000).map(|index| 1_700_000_000 + index).collect();
1923 for values in [noise, runs, climbing, vec![7; 300], Vec::new()] {
1924 let chosen = encode(&values).unwrap();
1925 let mut smallest: Option<Vec<u8>> = None;
1926 for kind in offered(&values) {
1927 let Some(bytes) = encode_only(kind, &values).unwrap() else {
1928 continue;
1929 };
1930 if smallest.as_ref().is_none_or(|best| bytes.len() < best.len()) {
1931 smallest = Some(bytes);
1932 }
1933 }
1934 assert_eq!(smallest.as_deref(), Some(chosen.as_slice()), "{}", values.len());
1935 }
1936 }
1937
1938 #[test]
1939 fn a_column_of_whole_seconds_in_microseconds_pays_nothing_for_the_zeroes() {
1940 let mut random = Random::new();
1944 let day = 1_374_000_000_000_000i64;
1945 let values: Vec<i64> =
1946 (0..100_000).map(|_| day + (random.next() % 68_400) as i64 * 1_000_000).collect();
1947 let bytes = round_trip(&values);
1948 assert_eq!(kind_of(&bytes), Kind::Strided);
1949 assert!(describe(&bytes).unwrap().starts_with("STRIDE[1000000]"), "{:?}", describe(&bytes));
1950 let strided = 100_000 * 17 / 8;
1952 assert!(bytes.len() < strided + 2000, "{} bytes for {strided} of payload", bytes.len());
1953
1954 let plain = encode_only(Kind::Packed, &values).unwrap().expect("packing always applies");
1955 assert!(
1956 bytes.len() * 2 < plain.len(),
1957 "{} strided against {} packed",
1958 bytes.len(),
1959 plain.len()
1960 );
1961 }
1962
1963 #[test]
1964 fn a_stride_is_the_common_factor_of_the_distances_from_the_smallest_value() {
1965 assert_eq!(stride_of(&[10i64, 20, 40]), Some(10));
1966 assert_eq!(stride_of(&[7i64, 17, 37]), Some(10));
1969 assert_eq!(stride_of(&[10i64, 20, 23]), None);
1970 assert_eq!(stride_of(&[5i64; 100]), None);
1973 assert_eq!(stride_of(&[]), None);
1974 assert_eq!(stride_of(&[i64::MIN, i64::MAX]), Some(u64::MAX));
1976 }
1977
1978 #[test]
1979 fn a_stride_across_the_whole_of_the_type_round_trips() {
1980 for values in [vec![i64::MIN, i64::MAX], vec![i64::MIN, 0, i64::MAX]] {
1983 let bytes = round_trip(&values);
1984 assert_eq!(decode(&bytes).unwrap(), values);
1985 }
1986 }
1987
1988 #[test]
1989 fn a_column_with_no_common_factor_is_not_offered_a_stride() {
1990 let mut random = Random::new();
1991 let values: Vec<i64> = (0..2000).map(|_| (random.next() % 1_000_000) as i64).collect();
1992 assert!(!offered(&values).contains(&Kind::Strided));
1993 assert!(encode_only(Kind::Strided, &values).unwrap().is_none());
1994 }
1995
1996 #[test]
1997 fn an_empty_chunk_round_trips() {
1998 let bytes = round_trip(&[]);
1999 assert_eq!(bytes.len(), 5);
2000 }
2001
2002 #[test]
2003 fn a_constant_column_costs_thirteen_bytes_however_long_it_is() {
2004 let bytes = round_trip(&vec![42; 1_000_000]);
2005 assert_eq!(kind_of(&bytes), Kind::Constant);
2006 assert_eq!(bytes.len(), 13);
2007 }
2008
2009 #[test]
2010 fn a_narrow_range_is_packed_at_the_width_of_the_range_and_not_of_the_type() {
2011 let mut random = Random::new();
2013 let values: Vec<i64> = (0..100_000).map(|_| 1000 + (random.next() % 64) as i64).collect();
2014 let bytes = round_trip(&values);
2015 assert_eq!(kind_of(&bytes), Kind::Packed);
2016 let packed = 100_000 * 6 / 8;
2017 assert!(bytes.len() < packed + 2000, "{} bytes for {packed} of payload", bytes.len());
2018 assert!(bytes.len() > packed, "{} bytes cannot hold {packed}", bytes.len());
2019 }
2020
2021 #[test]
2022 fn a_counter_becomes_deltas_and_then_a_constant() {
2023 let values: Vec<i64> = (0..1_000_000).collect();
2026 let bytes = round_trip(&values);
2027 assert_eq!(kind_of(&bytes), Kind::Delta);
2028 assert_eq!(describe(&bytes).unwrap(), "DELTA(CONSTANT)");
2029 assert!(bytes.len() < 40, "{} bytes for a counter", bytes.len());
2030 }
2031
2032 #[test]
2033 fn a_column_that_counts_down_is_as_cheap_as_one_that_counts_up() {
2034 let up: Vec<i64> = (0..100_000).collect();
2036 let down: Vec<i64> = (0..100_000).rev().collect();
2037 assert_eq!(round_trip(&up).len(), round_trip(&down).len());
2038 }
2039
2040 #[test]
2041 fn long_runs_become_rle() {
2042 let mut values = Vec::new();
2043 for run in 0..1000 {
2044 values.extend(std::iter::repeat_n(run % 7, 200));
2045 }
2046 let bytes = round_trip(&values);
2047 assert_eq!(kind_of(&bytes), Kind::Rle);
2048 assert!(bytes.len() < 2000, "{} bytes for 1000 runs", bytes.len());
2049 }
2050
2051 #[test]
2052 fn a_low_cardinality_column_becomes_a_dictionary() {
2053 let mut random = Random::new();
2059 let dictionary: Vec<i64> =
2060 (0..40).map(|_| 1_000_000_000 + (random.next() % (1 << 30)) as i64).collect();
2061 let values: Vec<i64> =
2062 (0..100_000).map(|_| dictionary[(random.next() % 40) as usize]).collect();
2063 let bytes = round_trip(&values);
2064 assert_eq!(kind_of(&bytes), Kind::Dict);
2065 assert!(bytes.len() < 100_000, "{} bytes", bytes.len());
2066 }
2067
2068 #[test]
2069 fn a_nearly_constant_column_becomes_sparse() {
2070 let mut values = vec![0i64; 100_000];
2071 for index in 0..300 {
2072 values[index * 331] = 1 << 40;
2073 }
2074 let bytes = round_trip(&values);
2075 assert_eq!(kind_of(&bytes), Kind::Sparse);
2076 assert!(bytes.len() < 3000, "{} bytes for 300 exceptions", bytes.len());
2077 }
2078
2079 #[test]
2080 fn encoded_counts_match_decoded_rows_across_integer_shapes() {
2081 let mut sparse = vec![0_i64; 4096];
2082 for (index, value) in [(7, -3), (91, 12), (1001, -3), (3000, 12)] {
2083 sparse[index] = value;
2084 }
2085 let mut runs = Vec::new();
2086 for value in [0, 7, 0, -5] {
2087 runs.extend(std::iter::repeat_n(value, 500));
2088 }
2089 let mut random = Random::new();
2090 let packed = (0..2000).map(|_| (random.next() % 251) as i64).collect::<Vec<_>>();
2091 for values in [vec![0_i64; 1024], sparse, runs, packed] {
2092 let bytes = encode(&values).unwrap();
2093 let (rows, counts) = tally(&bytes).unwrap();
2094 let mut expected = BTreeMap::<i64, u64>::new();
2095 for value in decode(&bytes).unwrap() {
2096 *expected.entry(value).or_default() += 1;
2097 }
2098 assert_eq!(rows, values.len());
2099 assert_eq!(counts, expected.into_iter().collect::<Vec<_>>());
2100 }
2101 }
2102
2103 #[test]
2104 fn folded_sparse_exceptions_keep_the_last_value_at_a_repeated_position() {
2105 let mut bytes = vec![Kind::Sparse.tag()];
2106 put_u32(&mut bytes, 10);
2107 put_i64(&mut bytes, 0);
2108 put_u32(&mut bytes, 2);
2109 bytes.extend(encode(&[7, 7]).unwrap());
2110 bytes.extend(encode(&[3, 5]).unwrap());
2111
2112 let mut counts = BTreeMap::<i64, u64>::new();
2113 assert_eq!(
2114 fold(&bytes, |value, count| {
2115 *counts.entry(value).or_default() += count;
2116 Ok(())
2117 })
2118 .unwrap(),
2119 10
2120 );
2121 assert_eq!(counts, BTreeMap::from([(0, 9), (5, 1)]));
2122 assert_eq!(decode(&bytes).unwrap()[7], 5);
2123 }
2124
2125 #[test]
2126 fn the_cascade_goes_more_than_one_level_deep() {
2127 let mut values = Vec::new();
2130 for index in 0..2000i64 {
2131 values.extend(std::iter::repeat_n(1_000_000 + (index % 5) * 104_729, 100));
2132 }
2133 let bytes = round_trip(&values);
2134 let shape = describe(&bytes).unwrap();
2135 assert!(shape.contains('('), "{shape} is not a cascade");
2136 assert!(bytes.len() < 4000, "{} bytes: {shape}", bytes.len());
2137 }
2138
2139 #[test]
2140 fn random_data_is_packed_at_full_width_and_costs_what_it_costs() {
2141 let mut random = Random::new();
2144 let values: Vec<i64> = (0..10_000).map(|_| random.next() as i64).collect();
2145 let bytes = round_trip(&values);
2146 assert_eq!(kind_of(&bytes), Kind::Packed);
2147 assert!(bytes.len() < 10_000 * 8 + 1000, "{} bytes", bytes.len());
2148 }
2149
2150 #[test]
2151 fn the_extremes_of_the_type_survive() {
2152 let values = vec![i64::MIN, i64::MAX, 0, -1, i64::MIN, i64::MAX];
2155 round_trip(&values);
2156 round_trip(&[i64::MIN; 3]);
2157 round_trip(&[i64::MIN, i64::MIN + 1]);
2158 }
2159
2160 #[test]
2161 fn a_chunk_that_is_not_a_multiple_of_the_unit_round_trips() {
2162 for len in [1, 2, 1023, 1024, 1025, 2047, 2049] {
2163 let values: Vec<i64> = (0..len).map(|index| (index * 31 % 97) as i64).collect();
2164 round_trip(&values);
2165 }
2166 }
2167
2168 #[test]
2169 fn units_of_different_widths_in_one_chunk_do_not_read_each_others_leftovers() {
2170 let mut random = Random::new();
2182 let mut values = Vec::new();
2183 for width in [40u32, 3, 61, 1, 17, 40] {
2184 for _ in 0..1024 {
2185 values.push((random.next() & ((1u64 << width) - 1)) as i64);
2186 }
2187 }
2188 let bytes = encode(&values).unwrap();
2189 let described = describe(&bytes).unwrap();
2190 assert!(described.starts_with("FOR+BITPACK"), "expected one packed chunk, got {described}");
2191 assert_eq!(decode(&bytes).unwrap(), values, "{described}");
2192 }
2193
2194 #[test]
2195 fn a_cascade_decodes_the_same_through_a_shared_scratch_as_through_its_own() {
2196 let mut values = Vec::new();
2201 for index in 0..8192i64 {
2202 values.push(1_600_000_000 + index / 4 + (index % 7) * 1_000);
2203 }
2204 let bytes = encode(&values).unwrap();
2205 let described = describe(&bytes).unwrap();
2206 assert!(described.contains('('), "expected a cascade, got {described}");
2207 assert_eq!(decode(&bytes).unwrap(), values, "{described}");
2208 }
2209
2210 #[test]
2211 fn selected_positions_agree_with_a_full_decode_for_every_kind_with_a_point_form() {
2212 let positions = [0, 1, 17, 1023, 1024, 4097, 8191];
2213 let packed: Vec<i64> = (0..8192).map(|index| index * 31 % 1_000_003).collect();
2214 let mut runs = Vec::new();
2215 for run in 0..160i64 {
2216 runs.extend(std::iter::repeat_n(run * 13, (run as usize % 71) + 2));
2217 }
2218 runs.resize(8192, -7);
2219 let strided: Vec<i64> = (0..8192).map(|index| 500 + index * 7 % 5003 * 100).collect();
2220 let coded: Vec<i64> =
2221 (0..8192).map(|index| [-9_000_000_000, 3, 77, 1 << 40][index % 4]).collect();
2222
2223 for (kind, values) in [
2224 (Kind::Packed, packed),
2225 (Kind::Rle, runs),
2226 (Kind::Strided, strided),
2227 (Kind::Dict, coded),
2228 ] {
2229 let bytes = encode_only(kind, &values).unwrap().expect("encoding applies");
2230 let selected = decode_selected(&bytes, &positions).unwrap();
2231 let expected = positions.iter().map(|&position| values[position]).collect::<Vec<_>>();
2232 assert_eq!(selected, expected, "{}", kind.name());
2233 let shape = describe(&bytes).unwrap();
2234 let simple = !shape.contains("RLE") && !shape.contains("DELTA");
2235 assert_eq!(pointed(&bytes), simple, "{shape}");
2236 }
2237 }
2238
2239 #[test]
2240 fn selected_positions_must_be_ordered_and_inside_the_chunk() {
2241 let bytes = encode_only(Kind::Packed, &(0..2048).collect::<Vec<_>>())
2242 .unwrap()
2243 .expect("packed applies");
2244 assert!(decode_selected(&bytes, &[7, 7]).is_err());
2245 assert!(decode_selected(&bytes, &[8, 3]).is_err());
2246 assert!(decode_selected(&bytes, &[2048]).is_err());
2247 }
2248
2249 #[test]
2250 fn a_partial_unit_costs_its_own_values_and_not_a_whole_unit() {
2251 let values = vec![1i64 << 39, (1 << 39) + 7, 1 << 38];
2255 let bytes = encode_only(Kind::Packed, &values).unwrap().unwrap();
2256 assert_eq!(bytes.len(), 5 + 9 + 15);
2257 assert_eq!(decode(&bytes).unwrap(), values);
2258 }
2259
2260 #[test]
2261 fn the_frame_of_reference_is_per_unit_and_not_per_chunk() {
2262 let values: Vec<i64> =
2266 (0..4096i64).map(|index| (index / 1024) * 1_000_000 + (index % 1024)).collect();
2267 let bytes = encode_only(Kind::Packed, &values).unwrap().unwrap();
2268 assert_eq!(describe(&bytes).unwrap(), "FOR+BITPACK[10]");
2269 assert_eq!(decode(&bytes).unwrap(), values);
2270 }
2271
2272 #[test]
2273 fn every_candidate_that_applies_decodes_to_the_input() {
2274 let mut values = vec![5i64; 3000];
2278 for (index, value) in values.iter_mut().enumerate() {
2279 if index % 500 == 0 {
2280 *value = index as i64;
2281 }
2282 }
2283 let applicable = candidates(&values, 0, &EXHAUSTIVE);
2284 assert!(applicable.len() >= 4, "{applicable:?}");
2285 for kind in applicable {
2286 let bytes = encode_only(kind, &values).unwrap().unwrap();
2287 assert_eq!(decode(&bytes).unwrap(), values, "{}", kind.name());
2288 }
2289 }
2290
2291 #[test]
2296 fn every_kind_that_applies_decodes_to_what_it_was_given() {
2297 let shapes: Vec<Vec<i64>> = vec![
2298 Vec::new(),
2299 vec![5; 1024],
2300 vec![i64::MIN, i64::MAX, 0, -1],
2301 (0..1024).map(|at| at * 7).collect(),
2302 (0..1024).map(|at| at % 17).collect(),
2303 (0..1024).map(|at| if at % 100 == 0 { at } else { 3 }).collect(),
2304 (0..1024).map(|at| -at * 1_000_003).collect(),
2305 (0..1024_i64)
2306 .map(|at| {
2307 at.wrapping_mul(6_364_136_223_846_793_005)
2308 .wrapping_add(1_442_695_040_888_963_407)
2309 })
2310 .collect(),
2311 ];
2312 let kinds =
2313 [Kind::Constant, Kind::Packed, Kind::Delta, Kind::Rle, Kind::Dict, Kind::Sparse];
2314 for values in &shapes {
2315 for kind in kinds {
2316 let Some(bytes) = encode_only(kind, values).unwrap() else {
2317 continue;
2318 };
2319 assert_eq!(
2320 &decode(&bytes).unwrap(),
2321 values,
2322 "{} over {} values",
2323 kind.name(),
2324 values.len()
2325 );
2326 }
2327 }
2328 }
2329
2330 #[test]
2331 fn the_chooser_picks_the_smallest_candidate_rather_than_the_first_that_applies() {
2332 let mut values = vec![5i64; 3000];
2333 values[1500] = 9;
2334 let chosen = encode(&values).unwrap();
2335 for (_, size) in candidate_sizes(&values).unwrap() {
2336 assert!(chosen.len() <= size);
2337 }
2338 }
2339
2340 #[test]
2341 fn a_truncated_chunk_is_an_error_and_not_a_panic() {
2342 let bytes = encode(&[1, 2, 3, 4, 5]).unwrap();
2343 for len in 0..bytes.len() {
2344 let error = decode(&bytes[..len]).unwrap_err();
2345 assert!(error.message().contains("chunk"), "{error}");
2346 }
2347 }
2348
2349 #[test]
2350 fn trailing_bytes_are_an_error() {
2351 let mut bytes = encode(&[1, 2, 3]).unwrap();
2352 bytes.push(0);
2353 let error = decode(&bytes).unwrap_err();
2354 assert!(error.message().contains("left over"), "{error}");
2355 }
2356
2357 #[test]
2358 fn an_unknown_tag_is_an_error() {
2359 let error = decode(&[99, 0, 0, 0, 0]).unwrap_err();
2360 assert!(error.message().contains("unknown encoding tag"), "{error}");
2361 }
2362
2363 #[test]
2364 fn a_dictionary_code_outside_the_dictionary_is_an_error() {
2365 let mut bytes = vec![Kind::Dict.tag()];
2370 put_u32(&mut bytes, 1);
2371 bytes.extend_from_slice(&encode(&[10]).unwrap());
2372 bytes.extend_from_slice(&encode(&[5]).unwrap());
2373 let error = decode(&bytes).unwrap_err();
2374 assert!(error.message().contains("not in the dictionary"), "{error}");
2375 }
2376
2377 #[test]
2378 fn a_negative_run_length_is_an_error() {
2379 let mut bytes = vec![Kind::Rle.tag()];
2382 put_u32(&mut bytes, 4);
2383 bytes.extend_from_slice(&encode(&[7]).unwrap());
2384 bytes.extend_from_slice(&encode(&[-4]).unwrap());
2385 let error = decode(&bytes).unwrap_err();
2386 assert!(error.message().contains("negative"), "{error}");
2387 }
2388
2389 #[test]
2391 fn a_run_that_runs_past_its_chunk_is_an_error() {
2392 let mut bytes = vec![Kind::Rle.tag()];
2397 put_u32(&mut bytes, 4);
2398 bytes.extend_from_slice(&encode(&[7]).unwrap());
2399 bytes.extend_from_slice(&encode(&[9]).unwrap());
2400 let error = decode(&bytes).unwrap_err();
2401 assert!(error.message().contains("past its chunk"), "{error}");
2402 }
2403
2404 #[test]
2406 fn runs_shorter_and_longer_than_the_width_they_are_written_in_all_come_back() {
2407 let lengths = [1, 3, 7, 8, 9, 40, 2, 1];
2412 let mut values = Vec::new();
2413 for (at, length) in lengths.iter().enumerate() {
2414 let value = i64::try_from(at).expect("eight runs") * 1000 - 3;
2415 values.extend(std::iter::repeat_n(value, *length));
2416 }
2417 let bytes = encode(&values).expect("encodes");
2418 assert_eq!(decode(&bytes).expect("decodes"), values, "runs around the write width");
2419 let singles: Vec<i64> = (0..300).map(|index| index * 7 % 11).collect();
2422 let bytes = encode(&singles).expect("encodes");
2423 assert_eq!(decode(&bytes).expect("decodes"), singles, "no run longer than one");
2424 }
2425
2426 #[test]
2427 fn the_cascade_depth_is_bounded() {
2428 let values: Vec<i64> = (0..50_000).map(|index| (index / 100) % 250).collect();
2432 let bytes = round_trip(&values);
2433 let shape = describe(&bytes).unwrap();
2434 let depth = shape.matches('(').count();
2435 assert!(depth <= MAX_DEPTH as usize, "{shape} is {depth} deep");
2436 }
2437
2438 #[test]
2439 fn candidate_sizes_reports_what_the_chooser_looked_at() {
2440 let values: Vec<i64> = (0..5000).map(|index| index % 17 * 1000).collect();
2441 let sizes = candidate_sizes(&values).unwrap();
2442 assert!(sizes.iter().any(|(kind, _)| *kind == Kind::Dict));
2443 assert!(sizes.iter().any(|(kind, _)| *kind == Kind::Packed));
2444 assert!(sizes.iter().all(|(_, size)| *size > 0));
2445 }
2446
2447 #[test]
2448 fn a_chunk_can_be_read_from_the_front_of_a_longer_buffer() {
2449 let first = encode(&[1, 2, 3]).unwrap();
2452 let second: Vec<i64> = (0..3000).map(|index| index % 11).collect();
2453 let second_bytes = encode(&second).unwrap();
2454 let mut joined = first.clone();
2455 joined.extend_from_slice(&second_bytes);
2456 joined.extend_from_slice(b"and then something else");
2457
2458 let (values, used) = decode_prefix(&joined).unwrap();
2459 assert_eq!(values, vec![1, 2, 3]);
2460 assert_eq!(used, first.len());
2461 let (more, used_again) = decode_prefix(&joined[used..]).unwrap();
2462 assert_eq!(more, second);
2463 assert_eq!(used_again, second_bytes.len());
2464
2465 let (text, described) = describe_prefix(&joined).unwrap();
2466 assert_eq!(described, first.len());
2467 assert_eq!(text, describe(&first).unwrap());
2468 }
2469
2470 #[test]
2471 fn a_truncated_chunk_is_still_an_error_when_read_as_a_prefix() {
2472 let bytes = encode(&(0..2000).collect::<Vec<i64>>()).unwrap();
2473 for len in 0..bytes.len() {
2474 assert!(decode_prefix(&bytes[..len]).is_err(), "{len} bytes decoded");
2475 }
2476 }
2477
2478 #[test]
2481 fn decoding_into_a_narrow_type_agrees_with_the_wide_decoder() {
2482 let columns: Vec<Vec<i64>> = vec![
2483 vec![7; 3000],
2484 (0..3000).map(|i| (i * 37) % 200 - 100).collect(),
2485 (0..3000).map(|i| if i % 97 == 0 { i % 50 } else { 0 }).collect(),
2486 (0..3000).map(|i| i / 250).collect(),
2487 (0..3000).map(|i| i * 3 + 11).collect(),
2488 (0..3000).map(|i| [5, -9, 120][i as usize % 3]).collect(),
2489 ];
2490 let kinds = [
2491 Kind::Constant,
2492 Kind::Packed,
2493 Kind::Delta,
2494 Kind::Rle,
2495 Kind::Dict,
2496 Kind::Sparse,
2497 Kind::Strided,
2498 ];
2499 for values in &columns {
2500 for kind in kinds {
2501 let Some(bytes) = encode_only(kind, values).unwrap() else { continue };
2502 let wide = decode(&bytes).unwrap();
2503 let as_i16: Vec<i64> =
2504 decode_as::<i16>(&bytes).unwrap().into_iter().map(i64::from).collect();
2505 let as_i32: Vec<i64> =
2506 decode_as::<i32>(&bytes).unwrap().into_iter().map(i64::from).collect();
2507 assert_eq!(as_i16, wide, "{kind:?} as i16");
2508 assert_eq!(as_i32, wide, "{kind:?} as i32");
2509 assert_eq!(decode_as::<i64>(&bytes).unwrap(), wide, "{kind:?} as i64");
2510 }
2511 let chosen = encode(values).unwrap();
2512 let narrow: Vec<i64> =
2513 decode_as::<i16>(&chosen).unwrap().into_iter().map(i64::from).collect();
2514 assert_eq!(narrow, decode(&chosen).unwrap(), "the chosen cascade as i16");
2515 }
2516 }
2517
2518 #[test]
2520 fn decoding_into_a_narrow_type_takes_what_fits_and_refuses_what_does_not() {
2521 fn check<T: Lane + TryFrom<i64> + PartialEq + std::fmt::Debug>(edges: [i64; 2]) {
2522 for edge in edges {
2523 for value in [edge - 1, edge, edge + 1] {
2524 for kind in
2525 [Kind::Constant, Kind::Packed, Kind::Rle, Kind::Sparse, Kind::Strided]
2526 {
2527 let values = [value, value, edges[0].max(0).min(edges[1]), value];
2528 let Some(bytes) = encode_only(kind, &values).unwrap() else { continue };
2529 let fits = values.iter().all(|&value| T::try_from(value).is_ok());
2530 assert_eq!(decode_as::<T>(&bytes).is_ok(), fits, "{value} {kind:?}");
2531 }
2532 }
2533 }
2534 }
2535 check::<i8>([-128, 127]);
2536 check::<u8>([0, 255]);
2537 check::<i16>([-32_768, 32_767]);
2538 check::<u16>([0, 65_535]);
2539 check::<i32>([i64::from(i32::MIN), i64::from(i32::MAX)]);
2540 check::<u32>([0, i64::from(u32::MAX)]);
2541 }
2542
2543 #[test]
2546 fn a_packed_block_wider_than_its_type_still_decodes_when_its_values_fit() {
2547 let values: Vec<i64> = (0..1500).map(|i| if i % 2 == 0 { -5 } else { 32_767 }).collect();
2548 let bytes = encode_only(Kind::Packed, &values).unwrap().expect("packing always applies");
2549 let narrow: Vec<i64> =
2550 decode_as::<i16>(&bytes).unwrap().into_iter().map(i64::from).collect();
2551 assert_eq!(narrow, values);
2552 let over: Vec<i64> = values.iter().map(|&value| value + 1).collect();
2553 let bytes = encode_only(Kind::Packed, &over).unwrap().expect("packing always applies");
2554 assert!(decode_as::<i16>(&bytes).is_err(), "32768 is not an i16");
2555 }
2556}