1use std::collections::BTreeMap;
45
46use rudb_common::{Error, Result};
47
48use crate::chooser::{Chooser, EXHAUSTIVE};
49use crate::reader::Reader;
50
51use crate::bitpack::{self, VALUES};
52
53const MAX_DEPTH: u8 = 3;
60
61const RUN: usize = 8;
71
72const LONG_RUN: usize = 64;
76
77#[derive(Debug, Clone, Copy, PartialEq, Eq)]
80pub enum Kind {
81 Constant = 0,
83 Packed = 1,
86 Delta = 2,
89 Rle = 3,
91 Dict = 4,
94 Sparse = 5,
96 Strided = 6,
99}
100
101impl Kind {
102 pub const ALL: [Self; 7] = [
104 Self::Constant,
105 Self::Packed,
106 Self::Delta,
107 Self::Rle,
108 Self::Dict,
109 Self::Sparse,
110 Self::Strided,
111 ];
112
113 fn tag(self) -> u8 {
114 self as u8
115 }
116
117 fn from_tag(tag: u8) -> Result<Self> {
118 match tag {
119 0 => Ok(Self::Constant),
120 1 => Ok(Self::Packed),
121 2 => Ok(Self::Delta),
122 3 => Ok(Self::Rle),
123 4 => Ok(Self::Dict),
124 5 => Ok(Self::Sparse),
125 6 => Ok(Self::Strided),
126 other => Err(Error::internal(format!("unknown encoding tag {other}"))),
127 }
128 }
129
130 #[must_use]
132 pub fn name(self) -> &'static str {
133 match self {
134 Self::Constant => "CONSTANT",
135 Self::Packed => "FOR+BITPACK",
136 Self::Delta => "DELTA",
137 Self::Rle => "RLE",
138 Self::Dict => "DICT",
139 Self::Sparse => "SPARSE",
140 Self::Strided => "STRIDE",
141 }
142 }
143}
144
145pub fn encode(values: &[i64]) -> Result<Vec<u8>> {
152 encode_with(values, &EXHAUSTIVE)
153}
154
155pub fn encode_with(values: &[i64], chooser: &dyn Chooser) -> Result<Vec<u8>> {
165 encode_at(values, 0, chooser)
166}
167
168pub fn decode(bytes: &[u8]) -> Result<Vec<i64>> {
175 let mut reader = Reader::new(bytes);
176 let values = with_decoding(|scratch| decode_chunk(&mut reader, scratch))?;
177 if reader.remaining() != 0 {
178 return Err(Error::internal(format!(
179 "{} bytes left over after decoding a chunk",
180 reader.remaining()
181 )));
182 }
183 Ok(values)
184}
185
186pub fn tally(bytes: &[u8]) -> Result<(usize, Vec<(i64, u64)>)> {
195 let mut counts = BTreeMap::<i64, u64>::new();
196 let rows = fold(bytes, |value, count| {
197 *counts.entry(value).or_default() += count;
198 Ok(())
199 })?;
200 Ok((rows, counts.into_iter().collect()))
201}
202
203pub fn fold(bytes: &[u8], mut emit: impl FnMut(i64, u64) -> Result<()>) -> Result<usize> {
211 let mut reader = Reader::new(bytes);
212 let kind = Kind::from_tag(reader.u8()?)?;
213 let count = reader.u32()? as usize;
214 match kind {
215 Kind::Constant => {
216 let value = reader.i64()?;
217 if count != 0 {
218 emit(value, count as u64)?;
219 }
220 }
221 Kind::Sparse => {
222 let dominant = reader.i64()?;
223 let exception_count = reader.u32()? as usize;
224 let (positions, values) = with_decoding(|scratch| -> Result<_> {
225 Ok((decode_chunk(&mut reader, scratch)?, decode_chunk(&mut reader, scratch)?))
226 })?;
227 if positions.len() != exception_count || values.len() != exception_count {
228 return Err(Error::internal("a sparse chunk disagrees about its exception count"));
229 }
230 let mut ordered = true;
231 let mut previous = None;
232 for &position in &positions {
233 let position = usize::try_from(position)
234 .ok()
235 .filter(|&position| position < count)
236 .ok_or_else(|| Error::internal("a sparse exception is outside the chunk"))?;
237 if previous.is_some_and(|last| position <= last) {
238 ordered = false;
239 }
240 previous = Some(position);
241 }
242 if ordered {
243 if count != exception_count {
244 emit(dominant, (count - exception_count) as u64)?;
245 }
246 for value in values {
247 emit(value, 1)?;
248 }
249 } else {
250 let mut exceptions = BTreeMap::<usize, i64>::new();
253 for (position, value) in positions.into_iter().zip(values) {
254 exceptions.insert(position as usize, value);
255 }
256 if count != exceptions.len() {
257 emit(dominant, (count - exceptions.len()) as u64)?;
258 }
259 for value in exceptions.into_values() {
260 emit(value, 1)?;
261 }
262 }
263 }
264 Kind::Rle => {
265 let (values, lengths) = with_decoding(|scratch| -> Result<_> {
266 Ok((decode_chunk(&mut reader, scratch)?, decode_chunk(&mut reader, scratch)?))
267 })?;
268 if values.len() != lengths.len() {
269 return Err(Error::internal("an RLE chunk has more runs than run lengths"));
270 }
271 let mut rows = 0_usize;
272 for (value, length) in values.into_iter().zip(lengths) {
273 let length = usize::try_from(length)
274 .map_err(|_| Error::internal("a negative RLE run length"))?;
275 rows = rows
276 .checked_add(length)
277 .filter(|&rows| rows <= count)
278 .ok_or_else(|| Error::internal("an RLE run ends past its chunk"))?;
279 if length != 0 {
280 emit(value, length as u64)?;
281 }
282 }
283 check_count(rows, count)?;
284 }
285 _ => {
286 reader = Reader::new(bytes);
288 let values = with_decoding(|scratch| decode_chunk(&mut reader, scratch))?;
289 check_count(values.len(), count)?;
290 for value in values {
291 emit(value, 1)?;
292 }
293 }
294 }
295 if reader.remaining() != 0 {
296 return Err(Error::internal(format!(
297 "{} bytes left over after counting a chunk",
298 reader.remaining()
299 )));
300 }
301 Ok(count)
302}
303
304pub fn decode_selected(bytes: &[u8], positions: &[usize]) -> Result<Vec<i64>> {
315 if positions.windows(2).any(|pair| pair[0] >= pair[1]) {
316 return Err(Error::internal("selected integer positions are not sorted and unique"));
317 }
318 let mut reader = Reader::new(bytes);
319 let values = with_decoding(|scratch| decode_selected_chunk(&mut reader, positions, scratch))?;
320 if reader.remaining() != 0 {
321 return Err(Error::internal(format!(
322 "{} bytes left over after decoding selected values",
323 reader.remaining()
324 )));
325 }
326 Ok(values)
327}
328
329pub fn decode_prefix(bytes: &[u8]) -> Result<(Vec<i64>, usize)> {
339 let mut reader = Reader::new(bytes);
340 let values = with_decoding(|scratch| decode_chunk(&mut reader, scratch))?;
341 Ok((values, reader.used()))
342}
343
344pub fn describe_prefix(bytes: &[u8]) -> Result<(String, usize)> {
350 let mut reader = Reader::new(bytes);
351 let text = describe_chunk(&mut reader)?;
352 Ok((text, reader.used()))
353}
354
355pub fn candidate_sizes(values: &[i64]) -> Result<Vec<(Kind, usize)>> {
362 let mut sizes = Vec::new();
363 for kind in candidates(values, 0, &EXHAUSTIVE) {
364 if let Some(bytes) = encode_as(kind, values, 0, &EXHAUSTIVE)? {
365 sizes.push((kind, bytes.len()));
366 }
367 }
368 Ok(sizes)
369}
370
371#[must_use]
378pub fn offered(values: &[i64]) -> Vec<Kind> {
379 candidates(values, 0, &EXHAUSTIVE)
380}
381
382pub fn encode_only(kind: Kind, values: &[i64]) -> Result<Option<Vec<u8>>> {
393 encode_as(kind, values, 0, &EXHAUSTIVE)
394}
395
396pub(crate) fn size_as(kind: Kind, values: &[i64], depth: u8) -> Result<Option<usize>> {
401 Ok(encode_as(kind, values, depth, &EXHAUSTIVE)?.map(|bytes| bytes.len()))
402}
403
404pub fn shape(bytes: &[u8]) -> Result<Vec<Kind>> {
416 let mut reader = Reader::new(bytes);
417 let mut kinds = Vec::new();
418 shape_chunk(&mut reader, &mut kinds)?;
419 Ok(kinds)
420}
421
422pub fn describe(bytes: &[u8]) -> Result<String> {
428 let mut reader = Reader::new(bytes);
429 describe_chunk(&mut reader)
430}
431
432fn encode_at(values: &[i64], depth: u8, chooser: &dyn Chooser) -> Result<Vec<u8>> {
433 let offered = candidates(values, depth, chooser);
434 let mut best: Option<Vec<u8>> = None;
435 for kind in chooser.narrow_integers(values, &offered, depth) {
436 let Some(bytes) = encode_as(kind, values, depth, chooser)? else {
437 continue;
438 };
439 if best.as_ref().is_none_or(|current| bytes.len() < current.len()) {
440 best = Some(bytes);
441 }
442 }
443 best.ok_or_else(|| Error::internal("no encoding applied to the chunk"))
446}
447
448fn candidates(values: &[i64], depth: u8, chooser: &dyn Chooser) -> Vec<Kind> {
459 let mut kinds = vec![Kind::Packed];
460 if depth >= MAX_DEPTH {
461 return kinds;
462 }
463 let Some(profile) = Profile::of(values) else {
464 return kinds;
465 };
466 if profile.runs == 1 {
467 return vec![Kind::Constant];
469 }
470 let considered = |kind| chooser.considers_integer(kind, depth);
471 if considered(Kind::Delta)
474 && (profile.max.checked_sub(profile.min).is_some() || deltas_fit(values))
475 {
476 kinds.push(Kind::Delta);
477 }
478 if considered(Kind::Rle) && profile.runs * 4 <= values.len() * 3 {
479 kinds.push(Kind::Rle);
480 }
481 if considered(Kind::Dict) && spread_of(values).0 * 2 <= values.len() {
482 kinds.push(Kind::Dict);
483 }
484 if considered(Kind::Sparse)
488 && (profile.runs - 1) * 5 <= values.len() * 2
489 && majority(values).is_some_and(|(_, count)| count * 10 >= values.len() * 8)
490 {
491 kinds.push(Kind::Sparse);
492 }
493 if considered(Kind::Strided) && stride_from(values, profile.min).is_some() {
494 kinds.push(Kind::Strided);
495 }
496 kinds
497}
498
499struct Profile {
508 min: i64,
509 max: i64,
510 runs: usize,
512}
513
514impl Profile {
515 fn of(values: &[i64]) -> Option<Self> {
516 let first = *values.first()?;
517 let (mut min, mut max, mut breaks) = (first, first, 0usize);
518 for (before, after) in values.iter().zip(&values[1..]) {
519 min = min.min(*after);
520 max = max.max(*after);
521 breaks += usize::from(before != after);
522 }
523 Some(Self { min, max, runs: breaks + 1 })
524 }
525}
526
527fn encode_as(
530 kind: Kind,
531 values: &[i64],
532 depth: u8,
533 chooser: &dyn Chooser,
534) -> Result<Option<Vec<u8>>> {
535 let mut out = Vec::new();
536 put_u8(&mut out, kind.tag());
537 put_u32(&mut out, u32::try_from(values.len()).map_err(|_| too_long(values.len()))?);
538 match kind {
539 Kind::Constant => {
540 let Some(first) = values.first() else {
541 return Ok(None);
542 };
543 if values.iter().any(|value| value != first) {
544 return Ok(None);
545 }
546 put_i64(&mut out, *first);
547 }
548 Kind::Packed => encode_packed(values, &mut out)?,
549 Kind::Delta => {
550 let (Some(first), Some(deltas)) = (values.first(), deltas(values)) else {
554 return Ok(None);
555 };
556 put_i64(&mut out, *first);
557 out.extend_from_slice(&encode_at(&deltas, depth + 1, chooser)?);
558 }
559 Kind::Rle => {
560 let (run_values, run_lengths) = runs(values);
561 if run_values.is_empty() {
562 return Ok(None);
563 }
564 out.extend_from_slice(&encode_at(&run_values, depth + 1, chooser)?);
565 out.extend_from_slice(&encode_at(&run_lengths, depth + 1, chooser)?);
566 }
567 Kind::Dict => {
568 let dictionary = distinct_values(values);
569 if dictionary.is_empty() {
570 return Ok(None);
571 }
572 let codes = codes_over(values, &dictionary);
573 out.extend_from_slice(&encode_at(&dictionary, depth + 1, chooser)?);
574 out.extend_from_slice(&encode_at(&codes, depth + 1, chooser)?);
575 }
576 Kind::Sparse => {
577 let Some((value, _)) = majority(values).or_else(|| spread_of(values).1) else {
581 return Ok(None);
582 };
583 let mut positions = Vec::new();
584 let mut exceptions = Vec::new();
585 for (index, other) in values.iter().enumerate() {
586 if *other != value {
587 positions.push(index as i64);
588 exceptions.push(*other);
589 }
590 }
591 put_i64(&mut out, value);
592 put_u32(
593 &mut out,
594 u32::try_from(positions.len()).map_err(|_| too_long(positions.len()))?,
595 );
596 out.extend_from_slice(&encode_at(&positions, depth + 1, chooser)?);
597 out.extend_from_slice(&encode_at(&exceptions, depth + 1, chooser)?);
598 }
599 Kind::Strided => {
600 let (Some(base), Some(stride)) = (values.iter().min().copied(), stride_of(values))
601 else {
602 return Ok(None);
603 };
604 let mut steps = Vec::with_capacity(values.len());
605 for value in values {
606 let step = offset_from(*value, base) / stride;
607 let Ok(step) = i64::try_from(step) else {
612 return Ok(None);
613 };
614 steps.push(step);
615 }
616 put_i64(&mut out, base);
617 put_u64(&mut out, stride);
618 out.extend_from_slice(&encode_at(&steps, depth + 1, chooser)?);
619 }
620 }
621 Ok(Some(out))
622}
623
624fn encode_packed(values: &[i64], out: &mut Vec<u8>) -> Result<()> {
636 let mut offsets: Vec<u64> = Vec::with_capacity(VALUES);
640 let mut packed: Vec<u64> = vec![0; bitpack::packed_len::<u64>(64)];
643 let mut transposed = bitpack::Scratch::<u64>::new();
644 for unit in values.chunks(VALUES) {
645 let base = unit.iter().copied().min().unwrap_or(0);
646 offsets.clear();
647 offsets.extend(unit.iter().map(|value| offset_from(*value, base)));
648 let width = bitpack::required_width(&offsets);
649 put_i64(out, base);
650 put_u8(out, u8::try_from(width).map_err(|_| Error::internal("impossible width"))?);
651 if unit.len() == VALUES {
652 let words = bitpack::packed_len::<u64>(width);
653 bitpack::pack_with(&offsets, width, &mut packed[..words], &mut transposed)?;
654 for word in &packed[..words] {
655 put_u64(out, *word);
656 }
657 } else {
658 bitpack::pack_tail(&offsets, width, out)?;
659 }
660 }
661 Ok(())
662}
663
664struct Decoding {
691 packed: Vec<u64>,
694}
695
696thread_local! {
697 static DECODING: std::cell::RefCell<Decoding> =
699 const { std::cell::RefCell::new(Decoding::new()) };
700}
701
702fn with_decoding<T>(run: impl FnOnce(&mut Decoding) -> T) -> T {
709 DECODING.with(|cell| match cell.try_borrow_mut() {
710 Ok(mut scratch) => run(&mut scratch),
711 Err(_) => run(&mut Decoding::new()),
712 })
713}
714
715impl Decoding {
716 const fn new() -> Self {
718 Self { packed: Vec::new() }
719 }
720
721 fn ready(&mut self) {
723 if self.packed.len() != bitpack::packed_len::<u64>(64) {
724 self.packed.resize(bitpack::packed_len::<u64>(64), 0);
725 }
726 }
727}
728
729fn decode_chunk(reader: &mut Reader<'_>, scratch: &mut Decoding) -> Result<Vec<i64>> {
730 let kind = Kind::from_tag(reader.u8()?)?;
731 let count = reader.u32()? as usize;
732 match kind {
733 Kind::Constant => Ok(vec![reader.i64()?; count]),
734 Kind::Packed => {
735 let mut values = vec![0i64; count];
739 scratch.ready();
740 let mut done = 0;
741 while done < count {
742 let base = reader.i64()?;
743 let width = reader.u8()? as usize;
744 let wanted = (count - done).min(VALUES);
745 let into = &mut values[done..done + wanted];
746 if wanted == VALUES {
747 let words = bitpack::packed_len::<u64>(width);
748 for word in &mut scratch.packed[..words] {
749 *word = reader.u64()?;
750 }
751 bitpack::unpack_mapped(&scratch.packed[..words], width, into, |offset| {
752 value_from(offset, base)
753 })?;
754 } else {
755 let bytes = reader.bytes(bitpack::tail_len(wanted, width))?;
756 bitpack::unpack_tail_into(bytes, width, into, |offset| {
757 value_from(offset, base)
758 })?;
759 }
760 done += wanted;
761 }
762 Ok(values)
763 }
764 Kind::Delta => {
765 let first = reader.i64()?;
766 let deltas = decode_chunk(reader, scratch)?;
767 let mut values = Vec::with_capacity(count);
768 values.push(first);
769 let mut current = first;
770 for delta in deltas {
771 current = current.wrapping_add(unzigzag(delta as u64));
772 values.push(current);
773 }
774 check_count(values.len(), count)?;
775 Ok(values)
776 }
777 Kind::Rle => {
778 let run_values = decode_chunk(reader, scratch)?;
779 let run_lengths = decode_chunk(reader, scratch)?;
780 if run_values.len() != run_lengths.len() {
781 return Err(Error::internal("an RLE chunk has more runs than run lengths"));
782 }
783 let long = run_values.len().saturating_mul(LONG_RUN) <= count;
790 let mut values = if long { Vec::with_capacity(count) } else { vec![0; count + RUN] };
791 let mut at = 0usize;
792 for (value, length) in run_values.into_iter().zip(run_lengths) {
793 let length = usize::try_from(length)
794 .map_err(|_| Error::internal("a negative RLE run length"))?;
795 let end = at
796 .checked_add(length)
797 .filter(|end| *end <= count)
798 .ok_or_else(|| Error::internal("an RLE run ends past its chunk"))?;
799 if long {
800 values.resize(end, value);
801 } else {
802 let short =
803 if length <= RUN { values[at..].first_chunk_mut::<RUN>() } else { None };
804 match short {
805 Some(window) => window.fill(value),
806 None => values[at..end].fill(value),
807 }
808 }
809 at = end;
810 }
811 check_count(at, count)?;
812 values.truncate(count);
813 Ok(values)
814 }
815 Kind::Dict => {
816 let dictionary = decode_chunk(reader, scratch)?;
817 let codes = decode_chunk(reader, scratch)?;
818 let mut values = Vec::with_capacity(count);
819 for code in codes {
820 let index =
821 usize::try_from(code).ok().and_then(|index| dictionary.get(index)).ok_or_else(
822 || Error::internal(format!("code {code} is not in the dictionary")),
823 )?;
824 values.push(*index);
825 }
826 check_count(values.len(), count)?;
827 Ok(values)
828 }
829 Kind::Sparse => {
830 let value = reader.i64()?;
831 let exception_count = reader.u32()? as usize;
832 let positions = decode_chunk(reader, scratch)?;
833 let exceptions = decode_chunk(reader, scratch)?;
834 if positions.len() != exception_count || exceptions.len() != exception_count {
835 return Err(Error::internal("a sparse chunk disagrees about its exception count"));
836 }
837 let mut values = vec![value; count];
838 for (position, exception) in positions.into_iter().zip(exceptions) {
839 let position = usize::try_from(position)
840 .ok()
841 .filter(|position| *position < count)
842 .ok_or_else(|| {
843 Error::internal(format!("exception at {position} is outside the chunk"))
844 })?;
845 values[position] = exception;
846 }
847 Ok(values)
848 }
849 Kind::Strided => {
850 let base = reader.i64()?;
851 let stride = reader.u64()?;
852 let steps = decode_chunk(reader, scratch)?;
853 check_count(steps.len(), count)?;
854 let mut values = Vec::with_capacity(count);
855 for step in steps {
856 let step = u64::try_from(step)
857 .map_err(|_| Error::internal("a negative number of strides"))?;
858 values.push(value_from(step.wrapping_mul(stride), base));
859 }
860 Ok(values)
861 }
862 }
863}
864
865fn decode_selected_chunk(
866 reader: &mut Reader<'_>,
867 positions: &[usize],
868 scratch: &mut Decoding,
869) -> Result<Vec<i64>> {
870 let Some(&tag) = reader.rest().first() else {
871 return Err(Error::internal("a chunk ended before its encoding tag"));
872 };
873 let kind = Kind::from_tag(tag)?;
874 if !matches!(kind, Kind::Constant | Kind::Packed | Kind::Rle) {
875 let values = decode_chunk(reader, scratch)?;
876 return positions
877 .iter()
878 .map(|&position| {
879 values.get(position).copied().ok_or_else(|| {
880 Error::internal(format!(
881 "selected integer position {position} is outside {} values",
882 values.len()
883 ))
884 })
885 })
886 .collect();
887 }
888
889 let decoded = Kind::from_tag(reader.u8()?)?;
890 debug_assert_eq!(decoded, kind);
891 let count = reader.u32()? as usize;
892 if positions.last().is_some_and(|&position| position >= count) {
893 return Err(Error::internal(format!(
894 "selected integer position {} is outside {count} values",
895 positions.last().expect("a last position exists")
896 )));
897 }
898 match kind {
899 Kind::Constant => {
900 let value = reader.i64()?;
901 Ok(vec![value; positions.len()])
902 }
903 Kind::Packed => {
904 let mut out = Vec::with_capacity(positions.len());
905 let mut from = 0;
906 let mut done = 0;
907 while done < count {
908 let base = reader.i64()?;
909 let width = reader.u8()? as usize;
910 let wanted = (count - done).min(VALUES);
911 let upto = positions.partition_point(|&position| position < done + wanted);
912 if wanted == VALUES {
913 let bytes = reader.bytes(bitpack::packed_len::<u64>(width) * 8)?;
914 for &position in &positions[from..upto] {
915 let offset = bitpack::unpack_u64_at(bytes, width, position - done)?;
916 out.push(value_from(offset, base));
917 }
918 } else {
919 let bytes = reader.bytes(bitpack::tail_len(wanted, width))?;
920 for &position in &positions[from..upto] {
921 let offset = bitpack::tail_at(bytes, width, position - done)?;
922 out.push(value_from(offset, base));
923 }
924 }
925 from = upto;
926 done += wanted;
927 }
928 Ok(out)
929 }
930 Kind::Rle => {
931 let run_value_bytes = reader.rest();
932 let mut run_value_reader = Reader::new(run_value_bytes);
933 let run_value_count = skip_chunk(&mut run_value_reader)?;
934 let run_value_len = run_value_reader.used();
935 reader.skip(run_value_len)?;
936 let run_lengths = decode_chunk(reader, scratch)?;
937 if run_value_count != run_lengths.len() {
938 return Err(Error::internal("an RLE chunk has more runs than run lengths"));
939 }
940 let mut wanted_runs = Vec::new();
941 let mut selected_per_run = Vec::new();
942 let mut selected = 0;
943 let mut at = 0usize;
944 for (run, length) in run_lengths.into_iter().enumerate() {
945 let length = usize::try_from(length)
946 .map_err(|_| Error::internal("a negative RLE run length"))?;
947 let end = at
948 .checked_add(length)
949 .filter(|end| *end <= count)
950 .ok_or_else(|| Error::internal("an RLE run ends past its chunk"))?;
951 let before = selected;
952 while selected < positions.len() && positions[selected] < end {
953 if positions[selected] < at {
954 return Err(Error::internal("selected integer positions went backwards"));
955 }
956 selected += 1;
957 }
958 if selected != before {
959 wanted_runs.push(run);
960 selected_per_run.push(selected - before);
961 }
962 at = end;
963 }
964 check_count(at, count)?;
965 if selected != positions.len() {
966 return Err(Error::internal("an RLE chunk ended before a selected position"));
967 }
968 let run_values = decode_selected(&run_value_bytes[..run_value_len], &wanted_runs)?;
969 let mut out = Vec::with_capacity(positions.len());
970 for (value, repeat) in run_values.into_iter().zip(selected_per_run) {
971 out.extend(std::iter::repeat_n(value, repeat));
972 }
973 Ok(out)
974 }
975 _ => unreachable!("unsupported kinds used the full decoder"),
976 }
977}
978
979fn skip_chunk(reader: &mut Reader<'_>) -> Result<usize> {
981 let kind = Kind::from_tag(reader.u8()?)?;
982 let count = reader.u32()? as usize;
983 match kind {
984 Kind::Constant => reader.skip(8)?,
985 Kind::Packed => skip_packed(reader, count)?,
986 Kind::Delta => {
987 reader.skip(8)?;
988 skip_chunk(reader)?;
989 }
990 Kind::Rle | Kind::Dict => {
991 skip_chunk(reader)?;
992 skip_chunk(reader)?;
993 }
994 Kind::Sparse => {
995 reader.skip(12)?;
996 skip_chunk(reader)?;
997 skip_chunk(reader)?;
998 }
999 Kind::Strided => {
1000 reader.skip(16)?;
1001 skip_chunk(reader)?;
1002 }
1003 }
1004 Ok(count)
1005}
1006
1007fn skip_packed(reader: &mut Reader<'_>, count: usize) -> Result<()> {
1009 let mut done = 0;
1010 while done < count {
1011 reader.skip(8)?;
1012 let width = reader.u8()? as usize;
1013 if width > 64 {
1014 return Err(Error::internal(format!("a packed integer width of {width} is past 64")));
1015 }
1016 let wanted = (count - done).min(VALUES);
1017 let bytes = if wanted == VALUES {
1018 bitpack::packed_len::<u64>(width)
1019 .checked_mul(8)
1020 .ok_or_else(|| Error::internal("packed integer size overflow"))?
1021 } else {
1022 bitpack::tail_len(wanted, width)
1023 };
1024 reader.skip(bytes)?;
1025 done += wanted;
1026 }
1027 Ok(())
1028}
1029
1030fn shape_chunk(reader: &mut Reader<'_>, kinds: &mut Vec<Kind>) -> Result<()> {
1032 let kind = Kind::from_tag(reader.u8()?)?;
1033 let count = reader.u32()? as usize;
1034 kinds.push(kind);
1035 match kind {
1036 Kind::Constant => reader.skip(8)?,
1037 Kind::Packed => skip_packed(reader, count)?,
1038 Kind::Delta => {
1039 reader.skip(8)?;
1040 shape_chunk(reader, kinds)?;
1041 }
1042 Kind::Rle | Kind::Dict => {
1043 shape_chunk(reader, kinds)?;
1044 shape_chunk(reader, kinds)?;
1045 }
1046 Kind::Sparse => {
1047 reader.skip(12)?;
1048 shape_chunk(reader, kinds)?;
1049 shape_chunk(reader, kinds)?;
1050 }
1051 Kind::Strided => {
1052 reader.skip(16)?;
1053 shape_chunk(reader, kinds)?;
1054 }
1055 }
1056 Ok(())
1057}
1058
1059fn describe_chunk(reader: &mut Reader<'_>) -> Result<String> {
1060 let kind = Kind::from_tag(reader.u8()?)?;
1061 let count = reader.u32()? as usize;
1062 Ok(match kind {
1063 Kind::Constant => {
1064 reader.i64()?;
1065 "CONSTANT".to_string()
1066 }
1067 Kind::Packed => {
1068 let mut widths = Vec::new();
1069 let mut seen = 0;
1070 while seen < count {
1071 reader.i64()?;
1072 let width = reader.u8()? as usize;
1073 let wanted = (count - seen).min(VALUES);
1074 if wanted == VALUES {
1075 for _ in 0..bitpack::packed_len::<u64>(width) {
1076 reader.u64()?;
1077 }
1078 } else {
1079 reader.bytes(bitpack::tail_len(wanted, width))?;
1080 }
1081 widths.push(width);
1082 seen += wanted;
1083 }
1084 let low = widths.iter().copied().min().unwrap_or(0);
1085 let high = widths.iter().copied().max().unwrap_or(0);
1086 if low == high {
1089 format!("FOR+BITPACK[{low}]")
1090 } else {
1091 format!("FOR+BITPACK[{low}..{high}]")
1092 }
1093 }
1094 Kind::Delta => {
1095 reader.i64()?;
1096 format!("DELTA({})", describe_chunk(reader)?)
1097 }
1098 Kind::Rle => {
1099 let values = describe_chunk(reader)?;
1100 let lengths = describe_chunk(reader)?;
1101 format!("RLE({values}, {lengths})")
1102 }
1103 Kind::Dict => {
1104 let dictionary = describe_chunk(reader)?;
1105 let codes = describe_chunk(reader)?;
1106 format!("DICT({dictionary}, {codes})")
1107 }
1108 Kind::Sparse => {
1109 reader.i64()?;
1110 reader.u32()?;
1111 let positions = describe_chunk(reader)?;
1112 let exceptions = describe_chunk(reader)?;
1113 format!("SPARSE({positions}, {exceptions})")
1114 }
1115 Kind::Strided => {
1116 reader.i64()?;
1117 let stride = reader.u64()?;
1118 format!("STRIDE[{stride}]({})", describe_chunk(reader)?)
1119 }
1120 })
1121}
1122
1123fn stride_of(values: &[i64]) -> Option<u64> {
1135 stride_from(values, values.iter().min().copied()?)
1136}
1137
1138fn stride_from(values: &[i64], base: i64) -> Option<u64> {
1140 let mut divisor = 0u64;
1141 for value in values {
1142 divisor = gcd(divisor, offset_from(*value, base));
1143 if divisor == 1 {
1144 return None;
1145 }
1146 }
1147 (divisor > 1).then_some(divisor)
1150}
1151
1152fn gcd(mut left: u64, mut right: u64) -> u64 {
1154 if left == 0 {
1155 return right;
1156 }
1157 if right == 0 {
1158 return left;
1159 }
1160 let shift = (left | right).trailing_zeros();
1161 left >>= left.trailing_zeros();
1162 loop {
1163 right >>= right.trailing_zeros();
1164 if left > right {
1165 std::mem::swap(&mut left, &mut right);
1166 }
1167 right -= left;
1168 if right == 0 {
1169 return left << shift;
1170 }
1171 }
1172}
1173
1174fn offset_from(value: i64, base: i64) -> u64 {
1177 (i128::from(value) - i128::from(base)) as u64
1178}
1179
1180fn value_from(offset: u64, base: i64) -> i64 {
1181 (i128::from(base) + i128::from(offset)) as i64
1182}
1183
1184fn zigzag(value: i64) -> u64 {
1187 ((value << 1) ^ (value >> 63)) as u64
1188}
1189
1190fn unzigzag(value: u64) -> i64 {
1191 ((value >> 1) as i64) ^ -((value & 1) as i64)
1192}
1193
1194fn deltas_fit(values: &[i64]) -> bool {
1206 values.windows(2).all(|pair| pair[1].checked_sub(pair[0]).is_some())
1207}
1208
1209fn deltas(values: &[i64]) -> Option<Vec<i64>> {
1210 let mut deltas = Vec::with_capacity(values.len().saturating_sub(1));
1211 for pair in values.windows(2) {
1212 let difference = pair[1].checked_sub(pair[0])?;
1213 deltas.push(zigzag(difference) as i64);
1214 }
1215 Some(deltas)
1216}
1217
1218fn runs(values: &[i64]) -> (Vec<i64>, Vec<i64>) {
1225 let mut run_values: Vec<i64> = Vec::new();
1226 let mut run_lengths: Vec<i64> = Vec::new();
1227 let mut start = 0;
1228 while let Some(&value) = values.get(start) {
1229 let length = values[start..].iter().take_while(|other| **other == value).count();
1230 run_values.push(value);
1231 run_lengths.push(length as i64);
1232 start += length;
1233 }
1234 (run_values, run_lengths)
1235}
1236
1237fn spread_of(values: &[i64]) -> (usize, Option<(i64, usize)>) {
1252 let mut sorted = values.to_vec();
1253 sorted.sort_unstable();
1254 let mut distinct = 0;
1255 let mut best: Option<(i64, usize)> = None;
1256 let mut index = 0;
1257 while index < sorted.len() {
1258 let value = sorted[index];
1259 let mut end = index;
1260 while end < sorted.len() && sorted[end] == value {
1261 end += 1;
1262 }
1263 distinct += 1;
1264 let count = end - index;
1265 if best.is_none_or(|(_, seen)| count > seen) {
1266 best = Some((value, count));
1267 }
1268 index = end;
1269 }
1270 (distinct, best)
1271}
1272
1273fn majority(values: &[i64]) -> Option<(i64, usize)> {
1281 let mut candidate = *values.first()?;
1282 let mut lead = 0usize;
1283 for value in values {
1284 if lead == 0 {
1285 candidate = *value;
1286 lead = 1;
1287 } else if *value == candidate {
1288 lead += 1;
1289 } else {
1290 lead -= 1;
1291 }
1292 }
1293 let count = values.iter().filter(|value| **value == candidate).count();
1294 (count * 2 > values.len()).then_some((candidate, count))
1295}
1296
1297fn distinct_values(values: &[i64]) -> Vec<i64> {
1300 let mut distinct = values.to_vec();
1301 distinct.sort_unstable();
1302 distinct.dedup();
1303 distinct
1304}
1305
1306fn codes_over(values: &[i64], dictionary: &[i64]) -> Vec<i64> {
1316 values
1317 .iter()
1318 .map(|value| {
1319 dictionary
1320 .binary_search(value)
1321 .expect("the dictionary is the distinct values of this chunk") as i64
1322 })
1323 .collect()
1324}
1325
1326fn check_count(actual: usize, expected: usize) -> Result<()> {
1327 if actual == expected {
1328 Ok(())
1329 } else {
1330 Err(Error::internal(format!(
1331 "a chunk says it holds {expected} values and decoded to {actual}"
1332 )))
1333 }
1334}
1335
1336fn too_long(len: usize) -> Error {
1337 Error::internal(format!("a chunk of {len} values is longer than the format allows"))
1338}
1339
1340fn put_u8(out: &mut Vec<u8>, value: u8) {
1341 out.push(value);
1342}
1343
1344fn put_u32(out: &mut Vec<u8>, value: u32) {
1345 out.extend_from_slice(&value.to_le_bytes());
1346}
1347
1348fn put_u64(out: &mut Vec<u8>, value: u64) {
1349 out.extend_from_slice(&value.to_le_bytes());
1350}
1351
1352fn put_i64(out: &mut Vec<u8>, value: i64) {
1353 out.extend_from_slice(&value.to_le_bytes());
1354}
1355
1356#[cfg(test)]
1357mod tests {
1358 use super::*;
1359
1360 fn round_trip(values: &[i64]) -> Vec<u8> {
1361 let bytes = encode(values).unwrap();
1362 assert_eq!(decode(&bytes).unwrap(), values, "{}", describe(&bytes).unwrap());
1363 bytes
1364 }
1365
1366 fn kind_of(bytes: &[u8]) -> Kind {
1367 Kind::from_tag(bytes[0]).unwrap()
1368 }
1369
1370 struct Random(u64);
1372
1373 impl Random {
1374 fn new() -> Self {
1375 Self(0x9e37_79b9_7f4a_7c15)
1376 }
1377
1378 fn next(&mut self) -> u64 {
1379 self.0 ^= self.0 << 13;
1380 self.0 ^= self.0 >> 7;
1381 self.0 ^= self.0 << 17;
1382 self.0
1383 }
1384 }
1385
1386 #[test]
1387 fn the_dictionary_is_sorted_and_the_codes_point_back_at_the_values() {
1388 let values = vec![30i64, 10, 30, 20, 10, -5];
1389 let dictionary = distinct_values(&values);
1390 let codes = codes_over(&values, &dictionary);
1391 assert_eq!(dictionary, vec![-5, 10, 20, 30]);
1392 assert_eq!(codes, vec![3, 1, 3, 2, 1, 0]);
1393 for (code, value) in codes.iter().zip(&values) {
1394 assert_eq!(dictionary[*code as usize], *value);
1395 }
1396 }
1397
1398 #[test]
1399 fn one_sort_gives_the_distinct_count_and_the_most_frequent_value() {
1400 let values = vec![7i64, 7, 7, 1, 2, 2];
1401 assert_eq!(spread_of(&values), (3, Some((7, 3))));
1402 assert_eq!(spread_of(&[]), (0, None));
1403 assert_eq!(spread_of(&[9]), (1, Some((9, 1))));
1404
1405 assert_eq!(spread_of(&[4i64, 4, 8, 8]), (2, Some((4, 2))));
1408 }
1409
1410 #[test]
1411 fn the_majority_is_the_most_frequent_value_whenever_there_is_one() {
1412 let chunks: Vec<Vec<i64>> = vec![
1413 vec![],
1414 vec![3],
1415 vec![1, 2],
1416 vec![1, 1, 2],
1417 vec![2, 1, 1],
1418 vec![4, 4, 8, 8],
1419 vec![7, 1, 7, 2, 7, 3, 7],
1420 vec![1, 2, 3, 9, 9, 9, 9],
1421 (0..1000).map(|index| if index % 5 == 0 { index } else { -4 }).collect(),
1422 (0..1000).map(|index| index % 3).collect(),
1423 ];
1424 for chunk in chunks {
1425 let (_, dominant) = spread_of(&chunk);
1426 let expected = dominant.filter(|(_, count)| count * 2 > chunk.len());
1427 assert_eq!(majority(&chunk), expected, "{chunk:?}");
1428 }
1429 }
1430
1431 #[test]
1435 fn the_one_pass_offers_what_the_separate_tests_offered() {
1436 let mut random = Random::new();
1437 let mut chunks: Vec<Vec<i64>> = vec![
1438 vec![],
1439 vec![5],
1440 vec![5, 5, 5],
1441 vec![i64::MIN, i64::MAX],
1442 vec![i64::MAX, i64::MIN, i64::MAX],
1443 vec![i64::MIN, 0, i64::MAX],
1444 vec![-1, i64::MAX],
1445 (0..1000).map(|index| if index % 5 == 0 { index } else { -4 }).collect(),
1446 (0..1000).map(|index| if index % 4 == 0 { index } else { -4 }).collect(),
1447 (0..1000).map(|index| index / 7).collect(),
1448 (0..1000).map(|index| index * 1_000_000).collect(),
1449 ];
1450 for _ in 0..200 {
1451 let len = (random.next() % 300) as usize;
1452 let spread = 1 + random.next() % 8;
1453 let common = (random.next() % 5) as i64;
1454 chunks.push(
1455 (0..len)
1456 .map(|_| {
1457 let draw = random.next();
1458 if draw % 10 < spread { (draw >> 8) as i64 % 50 } else { common }
1459 })
1460 .collect(),
1461 );
1462 }
1463 for chunk in chunks {
1464 let mut expected = vec![Kind::Packed];
1465 if !chunk.is_empty() {
1466 if chunk.iter().all(|value| *value == chunk[0]) {
1467 expected = vec![Kind::Constant];
1468 } else {
1469 if chunk.len() >= 2 && deltas_fit(&chunk) {
1470 expected.push(Kind::Delta);
1471 }
1472 let runs = 1 + chunk.windows(2).filter(|pair| pair[0] != pair[1]).count();
1473 if runs * 4 <= chunk.len() * 3 {
1474 expected.push(Kind::Rle);
1475 }
1476 if spread_of(&chunk).0 * 2 <= chunk.len() {
1477 expected.push(Kind::Dict);
1478 }
1479 if majority(&chunk).is_some_and(|(_, count)| count * 10 >= chunk.len() * 8) {
1480 expected.push(Kind::Sparse);
1481 }
1482 if stride_of(&chunk).is_some() {
1483 expected.push(Kind::Strided);
1484 }
1485 }
1486 }
1487 assert_eq!(candidates(&chunk, 0, &EXHAUSTIVE), expected, "{chunk:?}");
1488 }
1489 }
1490
1491 #[test]
1492 fn runs_are_every_stretch_of_equal_neighbours_in_order() {
1493 assert_eq!(runs(&[]), (vec![], vec![]));
1494 assert_eq!(runs(&[4]), (vec![4], vec![1]));
1495 assert_eq!(runs(&[1, 1, 2, 1, 1, 1]), (vec![1, 2, 1], vec![2, 1, 3]));
1496 }
1497
1498 #[test]
1499 fn deltas_that_do_not_fit_are_refused_before_they_are_built() {
1500 assert!(deltas_fit(&[1i64, 2, 3]));
1501 assert!(deltas_fit(&[i64::MAX, i64::MAX]));
1502 assert!(!deltas_fit(&[i64::MIN, i64::MAX]));
1503 assert_eq!(deltas_fit(&[i64::MIN, i64::MAX]), deltas(&[i64::MIN, i64::MAX]).is_some());
1504 assert_eq!(deltas_fit(&[1i64, 2, 3]), deltas(&[1i64, 2, 3]).is_some());
1505 }
1506
1507 #[test]
1508 fn what_the_chooser_returns_is_the_smallest_of_what_it_was_offered() {
1509 let mut random = Random::new();
1513 let noise: Vec<i64> = (0..2000).map(|_| (random.next() % 5000) as i64).collect();
1514 let runs: Vec<i64> = (0..2000).map(|index: i64| index / 100).collect();
1515 let climbing: Vec<i64> = (0..2000).map(|index| 1_700_000_000 + index).collect();
1516 for values in [noise, runs, climbing, vec![7; 300], Vec::new()] {
1517 let chosen = encode(&values).unwrap();
1518 let mut smallest: Option<Vec<u8>> = None;
1519 for kind in offered(&values) {
1520 let Some(bytes) = encode_only(kind, &values).unwrap() else {
1521 continue;
1522 };
1523 if smallest.as_ref().is_none_or(|best| bytes.len() < best.len()) {
1524 smallest = Some(bytes);
1525 }
1526 }
1527 assert_eq!(smallest.as_deref(), Some(chosen.as_slice()), "{}", values.len());
1528 }
1529 }
1530
1531 #[test]
1532 fn a_column_of_whole_seconds_in_microseconds_pays_nothing_for_the_zeroes() {
1533 let mut random = Random::new();
1537 let day = 1_374_000_000_000_000i64;
1538 let values: Vec<i64> =
1539 (0..100_000).map(|_| day + (random.next() % 68_400) as i64 * 1_000_000).collect();
1540 let bytes = round_trip(&values);
1541 assert_eq!(kind_of(&bytes), Kind::Strided);
1542 assert!(describe(&bytes).unwrap().starts_with("STRIDE[1000000]"), "{:?}", describe(&bytes));
1543 let strided = 100_000 * 17 / 8;
1545 assert!(bytes.len() < strided + 2000, "{} bytes for {strided} of payload", bytes.len());
1546
1547 let plain = encode_only(Kind::Packed, &values).unwrap().expect("packing always applies");
1548 assert!(
1549 bytes.len() * 2 < plain.len(),
1550 "{} strided against {} packed",
1551 bytes.len(),
1552 plain.len()
1553 );
1554 }
1555
1556 #[test]
1557 fn a_stride_is_the_common_factor_of_the_distances_from_the_smallest_value() {
1558 assert_eq!(stride_of(&[10i64, 20, 40]), Some(10));
1559 assert_eq!(stride_of(&[7i64, 17, 37]), Some(10));
1562 assert_eq!(stride_of(&[10i64, 20, 23]), None);
1563 assert_eq!(stride_of(&[5i64; 100]), None);
1566 assert_eq!(stride_of(&[]), None);
1567 assert_eq!(stride_of(&[i64::MIN, i64::MAX]), Some(u64::MAX));
1569 }
1570
1571 #[test]
1572 fn a_stride_across_the_whole_of_the_type_round_trips() {
1573 for values in [vec![i64::MIN, i64::MAX], vec![i64::MIN, 0, i64::MAX]] {
1576 let bytes = round_trip(&values);
1577 assert_eq!(decode(&bytes).unwrap(), values);
1578 }
1579 }
1580
1581 #[test]
1582 fn a_column_with_no_common_factor_is_not_offered_a_stride() {
1583 let mut random = Random::new();
1584 let values: Vec<i64> = (0..2000).map(|_| (random.next() % 1_000_000) as i64).collect();
1585 assert!(!offered(&values).contains(&Kind::Strided));
1586 assert!(encode_only(Kind::Strided, &values).unwrap().is_none());
1587 }
1588
1589 #[test]
1590 fn an_empty_chunk_round_trips() {
1591 let bytes = round_trip(&[]);
1592 assert_eq!(bytes.len(), 5);
1593 }
1594
1595 #[test]
1596 fn a_constant_column_costs_thirteen_bytes_however_long_it_is() {
1597 let bytes = round_trip(&vec![42; 1_000_000]);
1598 assert_eq!(kind_of(&bytes), Kind::Constant);
1599 assert_eq!(bytes.len(), 13);
1600 }
1601
1602 #[test]
1603 fn a_narrow_range_is_packed_at_the_width_of_the_range_and_not_of_the_type() {
1604 let mut random = Random::new();
1606 let values: Vec<i64> = (0..100_000).map(|_| 1000 + (random.next() % 64) as i64).collect();
1607 let bytes = round_trip(&values);
1608 assert_eq!(kind_of(&bytes), Kind::Packed);
1609 let packed = 100_000 * 6 / 8;
1610 assert!(bytes.len() < packed + 2000, "{} bytes for {packed} of payload", bytes.len());
1611 assert!(bytes.len() > packed, "{} bytes cannot hold {packed}", bytes.len());
1612 }
1613
1614 #[test]
1615 fn a_counter_becomes_deltas_and_then_a_constant() {
1616 let values: Vec<i64> = (0..1_000_000).collect();
1619 let bytes = round_trip(&values);
1620 assert_eq!(kind_of(&bytes), Kind::Delta);
1621 assert_eq!(describe(&bytes).unwrap(), "DELTA(CONSTANT)");
1622 assert!(bytes.len() < 40, "{} bytes for a counter", bytes.len());
1623 }
1624
1625 #[test]
1626 fn a_column_that_counts_down_is_as_cheap_as_one_that_counts_up() {
1627 let up: Vec<i64> = (0..100_000).collect();
1629 let down: Vec<i64> = (0..100_000).rev().collect();
1630 assert_eq!(round_trip(&up).len(), round_trip(&down).len());
1631 }
1632
1633 #[test]
1634 fn long_runs_become_rle() {
1635 let mut values = Vec::new();
1636 for run in 0..1000 {
1637 values.extend(std::iter::repeat_n(run % 7, 200));
1638 }
1639 let bytes = round_trip(&values);
1640 assert_eq!(kind_of(&bytes), Kind::Rle);
1641 assert!(bytes.len() < 2000, "{} bytes for 1000 runs", bytes.len());
1642 }
1643
1644 #[test]
1645 fn a_low_cardinality_column_becomes_a_dictionary() {
1646 let mut random = Random::new();
1652 let dictionary: Vec<i64> =
1653 (0..40).map(|_| 1_000_000_000 + (random.next() % (1 << 30)) as i64).collect();
1654 let values: Vec<i64> =
1655 (0..100_000).map(|_| dictionary[(random.next() % 40) as usize]).collect();
1656 let bytes = round_trip(&values);
1657 assert_eq!(kind_of(&bytes), Kind::Dict);
1658 assert!(bytes.len() < 100_000, "{} bytes", bytes.len());
1659 }
1660
1661 #[test]
1662 fn a_nearly_constant_column_becomes_sparse() {
1663 let mut values = vec![0i64; 100_000];
1664 for index in 0..300 {
1665 values[index * 331] = 1 << 40;
1666 }
1667 let bytes = round_trip(&values);
1668 assert_eq!(kind_of(&bytes), Kind::Sparse);
1669 assert!(bytes.len() < 3000, "{} bytes for 300 exceptions", bytes.len());
1670 }
1671
1672 #[test]
1673 fn encoded_counts_match_decoded_rows_across_integer_shapes() {
1674 let mut sparse = vec![0_i64; 4096];
1675 for (index, value) in [(7, -3), (91, 12), (1001, -3), (3000, 12)] {
1676 sparse[index] = value;
1677 }
1678 let mut runs = Vec::new();
1679 for value in [0, 7, 0, -5] {
1680 runs.extend(std::iter::repeat_n(value, 500));
1681 }
1682 let mut random = Random::new();
1683 let packed = (0..2000).map(|_| (random.next() % 251) as i64).collect::<Vec<_>>();
1684 for values in [vec![0_i64; 1024], sparse, runs, packed] {
1685 let bytes = encode(&values).unwrap();
1686 let (rows, counts) = tally(&bytes).unwrap();
1687 let mut expected = BTreeMap::<i64, u64>::new();
1688 for value in decode(&bytes).unwrap() {
1689 *expected.entry(value).or_default() += 1;
1690 }
1691 assert_eq!(rows, values.len());
1692 assert_eq!(counts, expected.into_iter().collect::<Vec<_>>());
1693 }
1694 }
1695
1696 #[test]
1697 fn folded_sparse_exceptions_keep_the_last_value_at_a_repeated_position() {
1698 let mut bytes = vec![Kind::Sparse.tag()];
1699 put_u32(&mut bytes, 10);
1700 put_i64(&mut bytes, 0);
1701 put_u32(&mut bytes, 2);
1702 bytes.extend(encode(&[7, 7]).unwrap());
1703 bytes.extend(encode(&[3, 5]).unwrap());
1704
1705 let mut counts = BTreeMap::<i64, u64>::new();
1706 assert_eq!(
1707 fold(&bytes, |value, count| {
1708 *counts.entry(value).or_default() += count;
1709 Ok(())
1710 })
1711 .unwrap(),
1712 10
1713 );
1714 assert_eq!(counts, BTreeMap::from([(0, 9), (5, 1)]));
1715 assert_eq!(decode(&bytes).unwrap()[7], 5);
1716 }
1717
1718 #[test]
1719 fn the_cascade_goes_more_than_one_level_deep() {
1720 let mut values = Vec::new();
1723 for index in 0..2000i64 {
1724 values.extend(std::iter::repeat_n(1_000_000 + (index % 5) * 104_729, 100));
1725 }
1726 let bytes = round_trip(&values);
1727 let shape = describe(&bytes).unwrap();
1728 assert!(shape.contains('('), "{shape} is not a cascade");
1729 assert!(bytes.len() < 4000, "{} bytes: {shape}", bytes.len());
1730 }
1731
1732 #[test]
1733 fn random_data_is_packed_at_full_width_and_costs_what_it_costs() {
1734 let mut random = Random::new();
1737 let values: Vec<i64> = (0..10_000).map(|_| random.next() as i64).collect();
1738 let bytes = round_trip(&values);
1739 assert_eq!(kind_of(&bytes), Kind::Packed);
1740 assert!(bytes.len() < 10_000 * 8 + 1000, "{} bytes", bytes.len());
1741 }
1742
1743 #[test]
1744 fn the_extremes_of_the_type_survive() {
1745 let values = vec![i64::MIN, i64::MAX, 0, -1, i64::MIN, i64::MAX];
1748 round_trip(&values);
1749 round_trip(&[i64::MIN; 3]);
1750 round_trip(&[i64::MIN, i64::MIN + 1]);
1751 }
1752
1753 #[test]
1754 fn a_chunk_that_is_not_a_multiple_of_the_unit_round_trips() {
1755 for len in [1, 2, 1023, 1024, 1025, 2047, 2049] {
1756 let values: Vec<i64> = (0..len).map(|index| (index * 31 % 97) as i64).collect();
1757 round_trip(&values);
1758 }
1759 }
1760
1761 #[test]
1762 fn units_of_different_widths_in_one_chunk_do_not_read_each_others_leftovers() {
1763 let mut random = Random::new();
1775 let mut values = Vec::new();
1776 for width in [40u32, 3, 61, 1, 17, 40] {
1777 for _ in 0..1024 {
1778 values.push((random.next() & ((1u64 << width) - 1)) as i64);
1779 }
1780 }
1781 let bytes = encode(&values).unwrap();
1782 let described = describe(&bytes).unwrap();
1783 assert!(described.starts_with("FOR+BITPACK"), "expected one packed chunk, got {described}");
1784 assert_eq!(decode(&bytes).unwrap(), values, "{described}");
1785 }
1786
1787 #[test]
1788 fn a_cascade_decodes_the_same_through_a_shared_scratch_as_through_its_own() {
1789 let mut values = Vec::new();
1794 for index in 0..8192i64 {
1795 values.push(1_600_000_000 + index / 4 + (index % 7) * 1_000);
1796 }
1797 let bytes = encode(&values).unwrap();
1798 let described = describe(&bytes).unwrap();
1799 assert!(described.contains('('), "expected a cascade, got {described}");
1800 assert_eq!(decode(&bytes).unwrap(), values, "{described}");
1801 }
1802
1803 #[test]
1804 fn selected_positions_agree_with_a_full_decode_for_packed_and_run_length_chunks() {
1805 let positions = [0, 1, 17, 1023, 1024, 4097, 8191];
1806 let packed: Vec<i64> = (0..8192).map(|index| index * 31 % 1_000_003).collect();
1807 let mut runs = Vec::new();
1808 for run in 0..160i64 {
1809 runs.extend(std::iter::repeat_n(run * 13, (run as usize % 71) + 2));
1810 }
1811 runs.resize(8192, -7);
1812
1813 for (kind, values) in [(Kind::Packed, packed), (Kind::Rle, runs)] {
1814 let bytes = encode_only(kind, &values).unwrap().expect("encoding applies");
1815 let selected = decode_selected(&bytes, &positions).unwrap();
1816 let expected = positions.iter().map(|&position| values[position]).collect::<Vec<_>>();
1817 assert_eq!(selected, expected, "{}", kind.name());
1818 }
1819 }
1820
1821 #[test]
1822 fn selected_positions_must_be_ordered_and_inside_the_chunk() {
1823 let bytes = encode_only(Kind::Packed, &(0..2048).collect::<Vec<_>>())
1824 .unwrap()
1825 .expect("packed applies");
1826 assert!(decode_selected(&bytes, &[7, 7]).is_err());
1827 assert!(decode_selected(&bytes, &[8, 3]).is_err());
1828 assert!(decode_selected(&bytes, &[2048]).is_err());
1829 }
1830
1831 #[test]
1832 fn a_partial_unit_costs_its_own_values_and_not_a_whole_unit() {
1833 let values = vec![1i64 << 39, (1 << 39) + 7, 1 << 38];
1837 let bytes = encode_only(Kind::Packed, &values).unwrap().unwrap();
1838 assert_eq!(bytes.len(), 5 + 9 + 15);
1839 assert_eq!(decode(&bytes).unwrap(), values);
1840 }
1841
1842 #[test]
1843 fn the_frame_of_reference_is_per_unit_and_not_per_chunk() {
1844 let values: Vec<i64> =
1848 (0..4096i64).map(|index| (index / 1024) * 1_000_000 + (index % 1024)).collect();
1849 let bytes = encode_only(Kind::Packed, &values).unwrap().unwrap();
1850 assert_eq!(describe(&bytes).unwrap(), "FOR+BITPACK[10]");
1851 assert_eq!(decode(&bytes).unwrap(), values);
1852 }
1853
1854 #[test]
1855 fn every_candidate_that_applies_decodes_to_the_input() {
1856 let mut values = vec![5i64; 3000];
1860 for (index, value) in values.iter_mut().enumerate() {
1861 if index % 500 == 0 {
1862 *value = index as i64;
1863 }
1864 }
1865 let applicable = candidates(&values, 0, &EXHAUSTIVE);
1866 assert!(applicable.len() >= 4, "{applicable:?}");
1867 for kind in applicable {
1868 let bytes = encode_only(kind, &values).unwrap().unwrap();
1869 assert_eq!(decode(&bytes).unwrap(), values, "{}", kind.name());
1870 }
1871 }
1872
1873 #[test]
1878 fn every_kind_that_applies_decodes_to_what_it_was_given() {
1879 let shapes: Vec<Vec<i64>> = vec![
1880 Vec::new(),
1881 vec![5; 1024],
1882 vec![i64::MIN, i64::MAX, 0, -1],
1883 (0..1024).map(|at| at * 7).collect(),
1884 (0..1024).map(|at| at % 17).collect(),
1885 (0..1024).map(|at| if at % 100 == 0 { at } else { 3 }).collect(),
1886 (0..1024).map(|at| -at * 1_000_003).collect(),
1887 (0..1024_i64)
1888 .map(|at| {
1889 at.wrapping_mul(6_364_136_223_846_793_005)
1890 .wrapping_add(1_442_695_040_888_963_407)
1891 })
1892 .collect(),
1893 ];
1894 let kinds =
1895 [Kind::Constant, Kind::Packed, Kind::Delta, Kind::Rle, Kind::Dict, Kind::Sparse];
1896 for values in &shapes {
1897 for kind in kinds {
1898 let Some(bytes) = encode_only(kind, values).unwrap() else {
1899 continue;
1900 };
1901 assert_eq!(
1902 &decode(&bytes).unwrap(),
1903 values,
1904 "{} over {} values",
1905 kind.name(),
1906 values.len()
1907 );
1908 }
1909 }
1910 }
1911
1912 #[test]
1913 fn the_chooser_picks_the_smallest_candidate_rather_than_the_first_that_applies() {
1914 let mut values = vec![5i64; 3000];
1915 values[1500] = 9;
1916 let chosen = encode(&values).unwrap();
1917 for (_, size) in candidate_sizes(&values).unwrap() {
1918 assert!(chosen.len() <= size);
1919 }
1920 }
1921
1922 #[test]
1923 fn a_truncated_chunk_is_an_error_and_not_a_panic() {
1924 let bytes = encode(&[1, 2, 3, 4, 5]).unwrap();
1925 for len in 0..bytes.len() {
1926 let error = decode(&bytes[..len]).unwrap_err();
1927 assert!(error.message().contains("chunk"), "{error}");
1928 }
1929 }
1930
1931 #[test]
1932 fn trailing_bytes_are_an_error() {
1933 let mut bytes = encode(&[1, 2, 3]).unwrap();
1934 bytes.push(0);
1935 let error = decode(&bytes).unwrap_err();
1936 assert!(error.message().contains("left over"), "{error}");
1937 }
1938
1939 #[test]
1940 fn an_unknown_tag_is_an_error() {
1941 let error = decode(&[99, 0, 0, 0, 0]).unwrap_err();
1942 assert!(error.message().contains("unknown encoding tag"), "{error}");
1943 }
1944
1945 #[test]
1946 fn a_dictionary_code_outside_the_dictionary_is_an_error() {
1947 let mut bytes = vec![Kind::Dict.tag()];
1952 put_u32(&mut bytes, 1);
1953 bytes.extend_from_slice(&encode(&[10]).unwrap());
1954 bytes.extend_from_slice(&encode(&[5]).unwrap());
1955 let error = decode(&bytes).unwrap_err();
1956 assert!(error.message().contains("not in the dictionary"), "{error}");
1957 }
1958
1959 #[test]
1960 fn a_negative_run_length_is_an_error() {
1961 let mut bytes = vec![Kind::Rle.tag()];
1964 put_u32(&mut bytes, 4);
1965 bytes.extend_from_slice(&encode(&[7]).unwrap());
1966 bytes.extend_from_slice(&encode(&[-4]).unwrap());
1967 let error = decode(&bytes).unwrap_err();
1968 assert!(error.message().contains("negative"), "{error}");
1969 }
1970
1971 #[test]
1973 fn a_run_that_runs_past_its_chunk_is_an_error() {
1974 let mut bytes = vec![Kind::Rle.tag()];
1979 put_u32(&mut bytes, 4);
1980 bytes.extend_from_slice(&encode(&[7]).unwrap());
1981 bytes.extend_from_slice(&encode(&[9]).unwrap());
1982 let error = decode(&bytes).unwrap_err();
1983 assert!(error.message().contains("past its chunk"), "{error}");
1984 }
1985
1986 #[test]
1988 fn runs_shorter_and_longer_than_the_width_they_are_written_in_all_come_back() {
1989 let lengths = [1, 3, 7, 8, 9, 40, 2, 1];
1994 let mut values = Vec::new();
1995 for (at, length) in lengths.iter().enumerate() {
1996 let value = i64::try_from(at).expect("eight runs") * 1000 - 3;
1997 values.extend(std::iter::repeat_n(value, *length));
1998 }
1999 let bytes = encode(&values).expect("encodes");
2000 assert_eq!(decode(&bytes).expect("decodes"), values, "runs around the write width");
2001 let singles: Vec<i64> = (0..300).map(|index| index * 7 % 11).collect();
2004 let bytes = encode(&singles).expect("encodes");
2005 assert_eq!(decode(&bytes).expect("decodes"), singles, "no run longer than one");
2006 }
2007
2008 #[test]
2009 fn the_cascade_depth_is_bounded() {
2010 let values: Vec<i64> = (0..50_000).map(|index| (index / 100) % 250).collect();
2014 let bytes = round_trip(&values);
2015 let shape = describe(&bytes).unwrap();
2016 let depth = shape.matches('(').count();
2017 assert!(depth <= MAX_DEPTH as usize, "{shape} is {depth} deep");
2018 }
2019
2020 #[test]
2021 fn candidate_sizes_reports_what_the_chooser_looked_at() {
2022 let values: Vec<i64> = (0..5000).map(|index| index % 17).collect();
2023 let sizes = candidate_sizes(&values).unwrap();
2024 assert!(sizes.iter().any(|(kind, _)| *kind == Kind::Dict));
2025 assert!(sizes.iter().any(|(kind, _)| *kind == Kind::Packed));
2026 assert!(sizes.iter().all(|(_, size)| *size > 0));
2027 }
2028
2029 #[test]
2030 fn a_chunk_can_be_read_from_the_front_of_a_longer_buffer() {
2031 let first = encode(&[1, 2, 3]).unwrap();
2034 let second: Vec<i64> = (0..3000).map(|index| index % 11).collect();
2035 let second_bytes = encode(&second).unwrap();
2036 let mut joined = first.clone();
2037 joined.extend_from_slice(&second_bytes);
2038 joined.extend_from_slice(b"and then something else");
2039
2040 let (values, used) = decode_prefix(&joined).unwrap();
2041 assert_eq!(values, vec![1, 2, 3]);
2042 assert_eq!(used, first.len());
2043 let (more, used_again) = decode_prefix(&joined[used..]).unwrap();
2044 assert_eq!(more, second);
2045 assert_eq!(used_again, second_bytes.len());
2046
2047 let (text, described) = describe_prefix(&joined).unwrap();
2048 assert_eq!(described, first.len());
2049 assert_eq!(text, describe(&first).unwrap());
2050 }
2051
2052 #[test]
2053 fn a_truncated_chunk_is_still_an_error_when_read_as_a_prefix() {
2054 let bytes = encode(&(0..2000).collect::<Vec<i64>>()).unwrap();
2055 for len in 0..bytes.len() {
2056 assert!(decode_prefix(&bytes[..len]).is_err(), "{len} bytes decoded");
2057 }
2058 }
2059}