1use std::marker::PhantomData;
49
50use crate::egress::column_kind::ColumnKind;
51use crate::egress::symbol_dict::SymbolDict;
52use crate::error::{Result, fmt};
53
54#[derive(Debug, Clone, Copy)]
63#[non_exhaustive]
64pub enum Validity<'a> {
65 None,
67 Bitmap { bytes: &'a [u8], row_count: usize },
69}
70
71impl<'a> Validity<'a> {
72 #[inline]
83 pub fn from_bitmap(bytes: &'a [u8], row_count: usize) -> Result<Self> {
84 let needed = row_count.div_ceil(8);
85 if bytes.len() < needed {
86 return Err(fmt!(
87 InvalidApiCall,
88 "Validity::from_bitmap: bitmap is {} bytes but row_count={} needs at least {}",
89 bytes.len(),
90 row_count,
91 needed
92 ));
93 }
94 Ok(Validity::Bitmap { bytes, row_count })
95 }
96
97 #[inline]
98 pub fn has_nulls(&self) -> bool {
99 matches!(self, Validity::Bitmap { .. })
100 }
101
102 #[inline]
111 pub fn is_null(&self, row: usize) -> bool {
112 match self {
113 Validity::None => false,
114 Validity::Bitmap { bytes, row_count } => {
115 if row >= *row_count {
116 return false;
117 }
118 match bytes.get(row >> 3) {
119 Some(byte) => (byte >> (row & 7)) & 1 != 0,
120 None => false,
121 }
122 }
123 }
124 }
125
126 #[inline]
128 pub fn bytes(&self) -> Option<&'a [u8]> {
129 match self {
130 Validity::None => None,
131 Validity::Bitmap { bytes, .. } => Some(bytes),
132 }
133 }
134}
135
136pub trait FixedWidth: Copy {
142 const SIZE: usize;
143 fn from_le(bytes: &[u8]) -> Self;
144}
145
146macro_rules! impl_fixed {
147 ($t:ty, $sz:expr) => {
148 impl FixedWidth for $t {
149 const SIZE: usize = $sz;
150 #[inline]
151 fn from_le(bytes: &[u8]) -> Self {
152 <$t>::from_le_bytes(bytes.try_into().expect("FixedWidth slice length"))
153 }
154 }
155 };
156}
157
158impl_fixed!(i16, 2);
159impl_fixed!(i32, 4);
160impl_fixed!(i64, 8);
161impl_fixed!(u16, 2);
162impl_fixed!(u32, 4);
163impl_fixed!(u64, 8);
164impl_fixed!(f32, 4);
165impl_fixed!(f64, 8);
166
167impl FixedWidth for i8 {
168 const SIZE: usize = 1;
169 #[inline]
170 fn from_le(bytes: &[u8]) -> Self {
171 bytes[0] as i8
172 }
173}
174
175impl FixedWidth for u8 {
176 const SIZE: usize = 1;
177 #[inline]
178 fn from_le(bytes: &[u8]) -> Self {
179 bytes[0]
180 }
181}
182
183#[derive(Debug, Clone, Copy)]
185pub struct FixedColumn<'a, T: FixedWidth> {
186 raw: &'a [u8],
187 validity: Validity<'a>,
188 _phantom: PhantomData<T>,
189}
190
191impl<'a, T: FixedWidth> FixedColumn<'a, T> {
192 #[inline]
202 pub(crate) fn new(raw: &'a [u8], validity: Validity<'a>) -> Self {
203 debug_assert_eq!(
204 raw.len() % T::SIZE,
205 0,
206 "raw length must be multiple of element size"
207 );
208 Self {
209 raw,
210 validity,
211 _phantom: PhantomData,
212 }
213 }
214
215 #[inline]
216 pub fn len(&self) -> usize {
217 self.raw.len() / T::SIZE
218 }
219
220 #[inline]
221 pub fn is_empty(&self) -> bool {
222 self.raw.is_empty()
223 }
224
225 #[inline]
226 pub fn validity(&self) -> Validity<'a> {
227 self.validity
228 }
229
230 #[inline]
231 pub fn is_null(&self, row: usize) -> bool {
232 self.validity.is_null(row)
233 }
234
235 #[inline]
237 pub fn raw(&self) -> &'a [u8] {
238 self.raw
239 }
240
241 #[inline]
248 #[track_caller]
249 pub fn value(&self, row: usize) -> T {
250 let s = row * T::SIZE;
251 T::from_le(&self.raw[s..s + T::SIZE])
252 }
253
254 #[inline]
256 pub fn iter(&self) -> FixedIter<'_, 'a, T> {
257 FixedIter {
258 col: self,
259 row: 0,
260 len: self.len(),
261 }
262 }
263}
264
265pub struct FixedIter<'c, 'a, T: FixedWidth> {
266 col: &'c FixedColumn<'a, T>,
267 row: usize,
268 len: usize,
269}
270
271impl<'c, 'a, T: FixedWidth> Iterator for FixedIter<'c, 'a, T> {
272 type Item = Option<T>;
273 #[inline]
274 fn next(&mut self) -> Option<Self::Item> {
275 if self.row >= self.len {
276 return None;
277 }
278 let r = self.row;
279 self.row += 1;
280 if self.col.is_null(r) {
281 Some(None)
282 } else {
283 Some(Some(self.col.value(r)))
284 }
285 }
286}
287
288#[derive(Debug, Clone, Copy)]
294pub struct FixedBytesColumn<'a, const N: usize> {
295 raw: &'a [u8],
296 validity: Validity<'a>,
297}
298
299impl<'a, const N: usize> FixedBytesColumn<'a, N> {
300 #[inline]
303 pub(crate) fn new(raw: &'a [u8], validity: Validity<'a>) -> Self {
304 debug_assert_eq!(raw.len() % N, 0);
305 Self { raw, validity }
306 }
307
308 #[inline]
309 pub fn len(&self) -> usize {
310 self.raw.len() / N
311 }
312
313 #[inline]
314 pub fn is_empty(&self) -> bool {
315 self.raw.is_empty()
316 }
317
318 #[inline]
319 pub fn validity(&self) -> Validity<'a> {
320 self.validity
321 }
322
323 #[inline]
324 pub fn is_null(&self, row: usize) -> bool {
325 self.validity.is_null(row)
326 }
327
328 #[inline]
329 pub fn raw(&self) -> &'a [u8] {
330 self.raw
331 }
332
333 #[inline]
338 #[track_caller]
339 pub fn value(&self, row: usize) -> &'a [u8; N] {
340 let s = row * N;
341 (&self.raw[s..s + N])
342 .try_into()
343 .expect("FixedBytesColumn slice length")
344 }
345}
346
347pub type UuidColumn<'a> = FixedBytesColumn<'a, 16>;
348pub type Long256Column<'a> = FixedBytesColumn<'a, 32>;
349
350#[derive(Debug, Clone, Copy)]
362pub struct SymbolColumn<'a> {
363 codes: &'a [u32],
364 validity: Validity<'a>,
365 dict: &'a SymbolDict,
366}
367
368impl<'a> SymbolColumn<'a> {
369 #[inline]
375 pub(crate) fn new(codes: &'a [u32], validity: Validity<'a>, dict: &'a SymbolDict) -> Self {
376 Self {
377 codes,
378 validity,
379 dict,
380 }
381 }
382
383 #[inline]
384 pub fn len(&self) -> usize {
385 self.codes.len()
386 }
387
388 #[inline]
389 pub fn is_empty(&self) -> bool {
390 self.codes.is_empty()
391 }
392
393 #[inline]
394 pub fn validity(&self) -> Validity<'a> {
395 self.validity
396 }
397
398 #[inline]
399 pub fn is_null(&self, row: usize) -> bool {
400 self.validity.is_null(row)
401 }
402
403 #[inline]
405 pub fn codes(&self) -> &'a [u32] {
406 self.codes
407 }
408
409 #[inline]
410 pub fn dict(&self) -> &'a SymbolDict {
411 self.dict
412 }
413
414 #[inline]
416 pub fn resolve(&self, row: usize) -> Option<&'a str> {
417 if self.is_null(row) {
418 return None;
419 }
420 let code = *self.codes.get(row)?;
421 self.dict.get(code)
422 }
423}
424
425#[derive(Debug, Clone, Copy)]
432pub struct Decimal64Column<'a> {
433 values: FixedColumn<'a, i64>,
434 scale: i8,
435}
436
437impl<'a> Decimal64Column<'a> {
438 #[inline]
441 pub(crate) fn new(raw: &'a [u8], validity: Validity<'a>, scale: i8) -> Self {
442 Self {
443 values: FixedColumn::new(raw, validity),
444 scale,
445 }
446 }
447
448 #[inline]
449 pub fn len(&self) -> usize {
450 self.values.len()
451 }
452
453 #[inline]
454 pub fn is_empty(&self) -> bool {
455 self.values.is_empty()
456 }
457
458 #[inline]
459 pub fn validity(&self) -> Validity<'a> {
460 self.values.validity()
461 }
462
463 #[inline]
464 pub fn is_null(&self, row: usize) -> bool {
465 self.values.is_null(row)
466 }
467
468 #[inline]
469 pub fn scale(&self) -> i8 {
470 self.scale
471 }
472
473 #[inline]
474 pub fn raw(&self) -> &'a [u8] {
475 self.values.raw()
476 }
477
478 #[inline]
483 #[track_caller]
484 pub fn value(&self, row: usize) -> i64 {
485 self.values.value(row)
486 }
487}
488
489#[derive(Debug, Clone, Copy)]
503struct VarlenLayout<'a> {
504 offsets: &'a [u32],
505 data: &'a [u8],
506 validity: Validity<'a>,
507}
508
509impl<'a> VarlenLayout<'a> {
510 #[inline]
511 fn len(&self) -> usize {
512 self.offsets.len().saturating_sub(1)
513 }
514
515 #[inline]
516 fn slice(&self, row: usize) -> Option<&'a [u8]> {
517 if self.validity.is_null(row) {
518 return None;
519 }
520 let s = *self.offsets.get(row)? as usize;
521 let e = *self.offsets.get(row + 1)? as usize;
522 self.data.get(s..e)
523 }
524}
525
526#[derive(Debug, Clone, Copy)]
528pub struct VarcharColumn<'a> {
529 inner: VarlenLayout<'a>,
530}
531
532impl<'a> VarcharColumn<'a> {
533 pub(crate) unsafe fn new(offsets: &'a [u32], data: &'a [u8], validity: Validity<'a>) -> Self {
548 Self {
549 inner: VarlenLayout {
550 offsets,
551 data,
552 validity,
553 },
554 }
555 }
556
557 #[inline]
558 pub fn len(&self) -> usize {
559 self.inner.len()
560 }
561
562 #[inline]
563 pub fn is_empty(&self) -> bool {
564 self.inner.len() == 0
565 }
566
567 #[inline]
568 pub fn validity(&self) -> Validity<'a> {
569 self.inner.validity
570 }
571
572 #[inline]
573 pub fn is_null(&self, row: usize) -> bool {
574 self.inner.validity.is_null(row)
575 }
576
577 #[inline]
578 pub fn offsets(&self) -> &'a [u32] {
579 self.inner.offsets
580 }
581
582 #[inline]
583 pub fn data(&self) -> &'a [u8] {
584 self.inner.data
585 }
586
587 #[inline]
592 #[track_caller]
593 pub fn value(&self, row: usize) -> Option<&'a str> {
594 let bytes = self.inner.slice(row)?;
595 Some(unsafe { std::str::from_utf8_unchecked(bytes) })
599 }
600}
601
602#[derive(Debug, Clone, Copy)]
605pub struct BinaryColumn<'a> {
606 inner: VarlenLayout<'a>,
607}
608
609impl<'a> BinaryColumn<'a> {
610 #[inline]
615 pub(crate) fn new(offsets: &'a [u32], data: &'a [u8], validity: Validity<'a>) -> Self {
616 Self {
617 inner: VarlenLayout {
618 offsets,
619 data,
620 validity,
621 },
622 }
623 }
624
625 #[inline]
626 pub fn len(&self) -> usize {
627 self.inner.len()
628 }
629
630 #[inline]
631 pub fn is_empty(&self) -> bool {
632 self.inner.len() == 0
633 }
634
635 #[inline]
636 pub fn validity(&self) -> Validity<'a> {
637 self.inner.validity
638 }
639
640 #[inline]
641 pub fn is_null(&self, row: usize) -> bool {
642 self.inner.validity.is_null(row)
643 }
644
645 #[inline]
646 pub fn offsets(&self) -> &'a [u32] {
647 self.inner.offsets
648 }
649
650 #[inline]
651 pub fn data(&self) -> &'a [u8] {
652 self.inner.data
653 }
654
655 #[inline]
660 #[track_caller]
661 pub fn value(&self, row: usize) -> Option<&'a [u8]> {
662 self.inner.slice(row)
663 }
664}
665
666#[derive(Debug, Clone, Copy)]
677pub struct GeohashColumn<'a> {
678 raw: &'a [u8],
679 byte_width: u8,
680 precision_bits: u8,
681 validity: Validity<'a>,
682}
683
684impl<'a> GeohashColumn<'a> {
685 #[inline]
688 pub(crate) fn new(
689 raw: &'a [u8],
690 byte_width: u8,
691 precision_bits: u8,
692 validity: Validity<'a>,
693 ) -> Self {
694 debug_assert!((1..=8).contains(&byte_width));
695 debug_assert_eq!(raw.len() % byte_width as usize, 0);
696 Self {
697 raw,
698 byte_width,
699 precision_bits,
700 validity,
701 }
702 }
703
704 #[inline]
705 pub fn precision_bits(&self) -> u8 {
706 self.precision_bits
707 }
708
709 #[inline]
710 pub fn byte_width(&self) -> u8 {
711 self.byte_width
712 }
713
714 #[inline]
715 pub fn len(&self) -> usize {
716 if self.byte_width == 0 {
717 0
718 } else {
719 self.raw.len() / self.byte_width as usize
720 }
721 }
722
723 #[inline]
724 pub fn is_empty(&self) -> bool {
725 self.raw.is_empty()
726 }
727
728 #[inline]
729 pub fn validity(&self) -> Validity<'a> {
730 self.validity
731 }
732
733 #[inline]
734 pub fn is_null(&self, row: usize) -> bool {
735 self.validity.is_null(row)
736 }
737
738 #[inline]
739 pub fn raw(&self) -> &'a [u8] {
740 self.raw
741 }
742
743 #[track_caller]
748 #[inline]
749 pub fn value(&self, row: usize) -> u64 {
750 let bw = self.byte_width as usize;
751 let s = row * bw;
752 let mut buf = [0u8; 8];
753 buf[..bw].copy_from_slice(&self.raw[s..s + bw]);
754 u64::from_le_bytes(buf)
755 }
756}
757
758#[derive(Debug, Clone, Copy)]
765pub struct Decimal128Column<'a> {
766 raw: &'a [u8],
767 scale: i8,
768 validity: Validity<'a>,
769}
770
771impl<'a> Decimal128Column<'a> {
772 #[inline]
775 pub(crate) fn new(raw: &'a [u8], validity: Validity<'a>, scale: i8) -> Self {
776 debug_assert_eq!(raw.len() % 16, 0);
777 Self {
778 raw,
779 scale,
780 validity,
781 }
782 }
783
784 #[inline]
785 pub fn len(&self) -> usize {
786 self.raw.len() / 16
787 }
788
789 #[inline]
790 pub fn is_empty(&self) -> bool {
791 self.raw.is_empty()
792 }
793
794 #[inline]
795 pub fn scale(&self) -> i8 {
796 self.scale
797 }
798
799 #[inline]
800 pub fn validity(&self) -> Validity<'a> {
801 self.validity
802 }
803
804 #[inline]
805 pub fn is_null(&self, row: usize) -> bool {
806 self.validity.is_null(row)
807 }
808
809 #[inline]
810 pub fn raw(&self) -> &'a [u8] {
811 self.raw
812 }
813
814 #[inline]
820 #[track_caller]
821 pub fn value(&self, row: usize) -> i128 {
822 let s = row * 16;
823 i128::from_le_bytes(self.raw[s..s + 16].try_into().expect("16-byte row"))
824 }
825}
826
827#[derive(Debug, Clone, Copy)]
833pub struct Decimal256Column<'a> {
834 raw: &'a [u8],
835 scale: i8,
836 validity: Validity<'a>,
837}
838
839impl<'a> Decimal256Column<'a> {
840 #[inline]
843 pub(crate) fn new(raw: &'a [u8], validity: Validity<'a>, scale: i8) -> Self {
844 debug_assert_eq!(raw.len() % 32, 0);
845 Self {
846 raw,
847 scale,
848 validity,
849 }
850 }
851
852 #[inline]
853 pub fn len(&self) -> usize {
854 self.raw.len() / 32
855 }
856
857 #[inline]
858 pub fn is_empty(&self) -> bool {
859 self.raw.is_empty()
860 }
861
862 #[inline]
863 pub fn scale(&self) -> i8 {
864 self.scale
865 }
866
867 #[inline]
868 pub fn validity(&self) -> Validity<'a> {
869 self.validity
870 }
871
872 #[inline]
873 pub fn is_null(&self, row: usize) -> bool {
874 self.validity.is_null(row)
875 }
876
877 #[inline]
878 pub fn raw(&self) -> &'a [u8] {
879 self.raw
880 }
881
882 #[inline]
887 #[track_caller]
888 pub fn value(&self, row: usize) -> &'a [u8; 32] {
889 let s = row * 32;
890 (&self.raw[s..s + 32]).try_into().expect("32-byte row")
891 }
892}
893
894#[derive(Debug, Clone, Copy)]
904pub struct DecimalColumn<'a> {
905 kind: ColumnKind,
906 raw: &'a [u8],
907 scale: i8,
908 validity: Validity<'a>,
909}
910
911impl<'a> DecimalColumn<'a> {
912 #[inline]
913 fn new(kind: ColumnKind, raw: &'a [u8], validity: Validity<'a>, scale: i8) -> Self {
914 debug_assert!(matches!(
915 kind,
916 ColumnKind::Decimal64 | ColumnKind::Decimal128 | ColumnKind::Decimal256
917 ));
918 let column = Self {
919 kind,
920 raw,
921 scale,
922 validity,
923 };
924 debug_assert_eq!(raw.len() % usize::from(column.byte_width()), 0);
925 column
926 }
927
928 #[inline]
930 pub fn kind(&self) -> ColumnKind {
931 self.kind
932 }
933
934 #[inline]
936 pub fn byte_width(&self) -> u8 {
937 match self.kind {
938 ColumnKind::Decimal64 => 8,
939 ColumnKind::Decimal128 => 16,
940 ColumnKind::Decimal256 => 32,
941 _ => unreachable!("DecimalColumn contains a non-decimal kind"),
942 }
943 }
944
945 #[inline]
951 pub fn max_precision(&self) -> u8 {
952 match self.kind {
953 ColumnKind::Decimal64 => 18,
954 ColumnKind::Decimal128 => 38,
955 ColumnKind::Decimal256 => 76,
956 _ => unreachable!("DecimalColumn contains a non-decimal kind"),
957 }
958 }
959
960 #[inline]
961 pub fn scale(&self) -> i8 {
962 self.scale
963 }
964
965 #[inline]
966 pub fn len(&self) -> usize {
967 self.raw.len() / usize::from(self.byte_width())
968 }
969
970 #[inline]
971 pub fn is_empty(&self) -> bool {
972 self.raw.is_empty()
973 }
974
975 #[inline]
976 pub fn validity(&self) -> Validity<'a> {
977 self.validity
978 }
979
980 #[inline]
981 pub fn is_null(&self, row: usize) -> bool {
982 self.validity.is_null(row)
983 }
984
985 #[inline]
987 pub fn raw(&self) -> &'a [u8] {
988 self.raw
989 }
990
991 #[inline]
1000 #[track_caller]
1001 pub fn mantissa_le(&self, row: usize) -> &'a [u8] {
1002 let len = self.len();
1003 assert!(
1004 row < len,
1005 "DecimalColumn::mantissa_le: row {row} out of range (len={len})"
1006 );
1007 let width = usize::from(self.byte_width());
1008 let start = row * width;
1009 &self.raw[start..start + width]
1010 }
1011}
1012
1013#[derive(Debug, Clone, Copy)]
1023struct ArrayLayout<'a> {
1024 data_offsets: &'a [u32],
1026 data: &'a [u8],
1028 shapes: &'a [u32],
1030 shape_offsets: &'a [u32],
1032 validity: Validity<'a>,
1033}
1034
1035impl<'a> ArrayLayout<'a> {
1036 #[inline]
1037 fn len(&self) -> usize {
1038 self.data_offsets.len().saturating_sub(1)
1039 }
1040
1041 #[inline]
1042 fn shape(&self, row: usize) -> Option<&'a [u32]> {
1043 if self.validity.is_null(row) {
1044 return None;
1045 }
1046 let s = *self.shape_offsets.get(row)? as usize;
1047 let e = *self.shape_offsets.get(row + 1)? as usize;
1048 self.shapes.get(s..e)
1049 }
1050
1051 #[inline]
1052 fn raw(&self, row: usize) -> Option<&'a [u8]> {
1053 if self.validity.is_null(row) {
1054 return None;
1055 }
1056 let s = *self.data_offsets.get(row)? as usize;
1057 let e = *self.data_offsets.get(row + 1)? as usize;
1058 self.data.get(s..e)
1059 }
1060}
1061
1062#[derive(Debug, Clone, Copy)]
1065pub struct DoubleArrayColumn<'a> {
1066 inner: ArrayLayout<'a>,
1067}
1068
1069impl<'a> DoubleArrayColumn<'a> {
1070 #[inline]
1077 pub(crate) fn new(
1078 data_offsets: &'a [u32],
1079 data: &'a [u8],
1080 shapes: &'a [u32],
1081 shape_offsets: &'a [u32],
1082 validity: Validity<'a>,
1083 ) -> Self {
1084 Self {
1085 inner: ArrayLayout {
1086 data_offsets,
1087 data,
1088 shapes,
1089 shape_offsets,
1090 validity,
1091 },
1092 }
1093 }
1094
1095 #[inline]
1096 pub fn len(&self) -> usize {
1097 self.inner.len()
1098 }
1099
1100 #[inline]
1101 pub fn is_empty(&self) -> bool {
1102 self.inner.len() == 0
1103 }
1104
1105 #[inline]
1106 pub fn validity(&self) -> Validity<'a> {
1107 self.inner.validity
1108 }
1109
1110 #[inline]
1111 pub fn is_null(&self, row: usize) -> bool {
1112 self.inner.validity.is_null(row)
1113 }
1114
1115 #[inline]
1117 pub fn shape(&self, row: usize) -> Option<&'a [u32]> {
1118 self.inner.shape(row)
1119 }
1120
1121 #[inline]
1124 pub fn raw(&self, row: usize) -> Option<&'a [u8]> {
1125 self.inner.raw(row)
1126 }
1127
1128 #[inline]
1130 pub fn element_count(&self, row: usize) -> usize {
1131 self.raw(row).map(|b| b.len() / 8).unwrap_or(0)
1132 }
1133
1134 #[inline]
1137 pub fn element(&self, row: usize, idx: usize) -> Option<f64> {
1138 let bytes = self.raw(row)?;
1139 let s = idx.checked_mul(8)?;
1140 let chunk = bytes.get(s..s + 8)?;
1141 Some(f64::from_le_bytes(chunk.try_into().expect("8 bytes")))
1142 }
1143
1144 #[inline]
1147 pub fn data(&self) -> &'a [u8] {
1148 self.inner.data
1149 }
1150
1151 #[inline]
1154 pub fn data_offsets(&self) -> &'a [u32] {
1155 self.inner.data_offsets
1156 }
1157
1158 #[inline]
1161 pub fn shapes(&self) -> &'a [u32] {
1162 self.inner.shapes
1163 }
1164
1165 #[inline]
1167 pub fn shape_offsets(&self) -> &'a [u32] {
1168 self.inner.shape_offsets
1169 }
1170}
1171
1172#[derive(Debug, Clone, Copy)]
1175pub struct LongArrayColumn<'a> {
1176 inner: ArrayLayout<'a>,
1177}
1178
1179impl<'a> LongArrayColumn<'a> {
1180 #[inline]
1183 pub(crate) fn new(
1184 data_offsets: &'a [u32],
1185 data: &'a [u8],
1186 shapes: &'a [u32],
1187 shape_offsets: &'a [u32],
1188 validity: Validity<'a>,
1189 ) -> Self {
1190 Self {
1191 inner: ArrayLayout {
1192 data_offsets,
1193 data,
1194 shapes,
1195 shape_offsets,
1196 validity,
1197 },
1198 }
1199 }
1200
1201 #[inline]
1202 pub fn len(&self) -> usize {
1203 self.inner.len()
1204 }
1205
1206 #[inline]
1207 pub fn is_empty(&self) -> bool {
1208 self.inner.len() == 0
1209 }
1210
1211 #[inline]
1212 pub fn validity(&self) -> Validity<'a> {
1213 self.inner.validity
1214 }
1215
1216 #[inline]
1217 pub fn is_null(&self, row: usize) -> bool {
1218 self.inner.validity.is_null(row)
1219 }
1220
1221 #[inline]
1222 pub fn shape(&self, row: usize) -> Option<&'a [u32]> {
1223 self.inner.shape(row)
1224 }
1225
1226 #[inline]
1227 pub fn raw(&self, row: usize) -> Option<&'a [u8]> {
1228 self.inner.raw(row)
1229 }
1230
1231 #[inline]
1232 pub fn element_count(&self, row: usize) -> usize {
1233 self.raw(row).map(|b| b.len() / 8).unwrap_or(0)
1234 }
1235
1236 #[inline]
1237 pub fn element(&self, row: usize, idx: usize) -> Option<i64> {
1238 let bytes = self.raw(row)?;
1239 let s = idx.checked_mul(8)?;
1240 let chunk = bytes.get(s..s + 8)?;
1241 Some(i64::from_le_bytes(chunk.try_into().expect("8 bytes")))
1242 }
1243
1244 #[inline]
1247 pub fn data(&self) -> &'a [u8] {
1248 self.inner.data
1249 }
1250
1251 #[inline]
1254 pub fn data_offsets(&self) -> &'a [u32] {
1255 self.inner.data_offsets
1256 }
1257
1258 #[inline]
1261 pub fn shapes(&self) -> &'a [u32] {
1262 self.inner.shapes
1263 }
1264
1265 #[inline]
1267 pub fn shape_offsets(&self) -> &'a [u32] {
1268 self.inner.shape_offsets
1269 }
1270}
1271
1272#[derive(Debug, Clone, Copy)]
1283#[non_exhaustive]
1284pub enum ColumnView<'a> {
1285 Boolean(FixedColumn<'a, u8>),
1286 Byte(FixedColumn<'a, i8>),
1287 Short(FixedColumn<'a, i16>),
1288 Int(FixedColumn<'a, i32>),
1289 Long(FixedColumn<'a, i64>),
1290 Float(FixedColumn<'a, f32>),
1291 Double(FixedColumn<'a, f64>),
1292 Symbol(SymbolColumn<'a>),
1293 Timestamp(FixedColumn<'a, i64>),
1295 Date(FixedColumn<'a, i64>),
1297 Uuid(UuidColumn<'a>),
1298 Long256(Long256Column<'a>),
1299 TimestampNanos(FixedColumn<'a, i64>),
1301 Decimal64(Decimal64Column<'a>),
1302 Char(FixedColumn<'a, u16>),
1304 Ipv4(FixedColumn<'a, u32>),
1306 Varchar(VarcharColumn<'a>),
1307 Binary(BinaryColumn<'a>),
1308 Geohash(GeohashColumn<'a>),
1309 Decimal128(Decimal128Column<'a>),
1310 Decimal256(Decimal256Column<'a>),
1311 DoubleArray(DoubleArrayColumn<'a>),
1312 LongArray(LongArrayColumn<'a>),
1313}
1314
1315impl<'a> ColumnView<'a> {
1316 #[inline]
1317 pub fn kind(&self) -> ColumnKind {
1318 match self {
1319 ColumnView::Boolean(_) => ColumnKind::Boolean,
1320 ColumnView::Byte(_) => ColumnKind::Byte,
1321 ColumnView::Short(_) => ColumnKind::Short,
1322 ColumnView::Int(_) => ColumnKind::Int,
1323 ColumnView::Long(_) => ColumnKind::Long,
1324 ColumnView::Float(_) => ColumnKind::Float,
1325 ColumnView::Double(_) => ColumnKind::Double,
1326 ColumnView::Symbol(_) => ColumnKind::Symbol,
1327 ColumnView::Timestamp(_) => ColumnKind::Timestamp,
1328 ColumnView::Date(_) => ColumnKind::Date,
1329 ColumnView::Uuid(_) => ColumnKind::Uuid,
1330 ColumnView::Long256(_) => ColumnKind::Long256,
1331 ColumnView::TimestampNanos(_) => ColumnKind::TimestampNanos,
1332 ColumnView::Decimal64(_) => ColumnKind::Decimal64,
1333 ColumnView::Char(_) => ColumnKind::Char,
1334 ColumnView::Ipv4(_) => ColumnKind::Ipv4,
1335 ColumnView::Varchar(_) => ColumnKind::Varchar,
1336 ColumnView::Binary(_) => ColumnKind::Binary,
1337 ColumnView::Geohash(_) => ColumnKind::Geohash,
1338 ColumnView::Decimal128(_) => ColumnKind::Decimal128,
1339 ColumnView::Decimal256(_) => ColumnKind::Decimal256,
1340 ColumnView::DoubleArray(_) => ColumnKind::DoubleArray,
1341 ColumnView::LongArray(_) => ColumnKind::LongArray,
1342 }
1343 }
1344
1345 #[inline]
1350 pub fn as_decimal(&self) -> Option<DecimalColumn<'a>> {
1351 match self {
1352 ColumnView::Decimal64(c) => Some(DecimalColumn::new(
1353 ColumnKind::Decimal64,
1354 c.raw(),
1355 c.validity(),
1356 c.scale(),
1357 )),
1358 ColumnView::Decimal128(c) => Some(DecimalColumn::new(
1359 ColumnKind::Decimal128,
1360 c.raw(),
1361 c.validity(),
1362 c.scale(),
1363 )),
1364 ColumnView::Decimal256(c) => Some(DecimalColumn::new(
1365 ColumnKind::Decimal256,
1366 c.raw(),
1367 c.validity(),
1368 c.scale(),
1369 )),
1370 _ => None,
1371 }
1372 }
1373
1374 #[inline]
1375 pub fn len(&self) -> usize {
1376 match self {
1377 ColumnView::Boolean(c) => c.len(),
1378 ColumnView::Byte(c) => c.len(),
1379 ColumnView::Short(c) => c.len(),
1380 ColumnView::Int(c) => c.len(),
1381 ColumnView::Long(c) => c.len(),
1382 ColumnView::Float(c) => c.len(),
1383 ColumnView::Double(c) => c.len(),
1384 ColumnView::Symbol(c) => c.len(),
1385 ColumnView::Timestamp(c) => c.len(),
1386 ColumnView::Date(c) => c.len(),
1387 ColumnView::Uuid(c) => c.len(),
1388 ColumnView::Long256(c) => c.len(),
1389 ColumnView::TimestampNanos(c) => c.len(),
1390 ColumnView::Decimal64(c) => c.len(),
1391 ColumnView::Char(c) => c.len(),
1392 ColumnView::Ipv4(c) => c.len(),
1393 ColumnView::Varchar(c) => c.len(),
1394 ColumnView::Binary(c) => c.len(),
1395 ColumnView::Geohash(c) => c.len(),
1396 ColumnView::Decimal128(c) => c.len(),
1397 ColumnView::Decimal256(c) => c.len(),
1398 ColumnView::DoubleArray(c) => c.len(),
1399 ColumnView::LongArray(c) => c.len(),
1400 }
1401 }
1402
1403 #[inline]
1404 pub fn is_empty(&self) -> bool {
1405 self.len() == 0
1406 }
1407
1408 #[inline]
1409 pub fn is_null(&self, row: usize) -> bool {
1410 match self {
1411 ColumnView::Boolean(c) => c.is_null(row),
1412 ColumnView::Byte(c) => c.is_null(row),
1413 ColumnView::Short(c) => c.is_null(row),
1414 ColumnView::Int(c) => c.is_null(row),
1415 ColumnView::Long(c) => c.is_null(row),
1416 ColumnView::Float(c) => c.is_null(row),
1417 ColumnView::Double(c) => c.is_null(row),
1418 ColumnView::Symbol(c) => c.is_null(row),
1419 ColumnView::Timestamp(c) => c.is_null(row),
1420 ColumnView::Date(c) => c.is_null(row),
1421 ColumnView::Uuid(c) => c.is_null(row),
1422 ColumnView::Long256(c) => c.is_null(row),
1423 ColumnView::TimestampNanos(c) => c.is_null(row),
1424 ColumnView::Decimal64(c) => c.is_null(row),
1425 ColumnView::Char(c) => c.is_null(row),
1426 ColumnView::Ipv4(c) => c.is_null(row),
1427 ColumnView::Varchar(c) => c.is_null(row),
1428 ColumnView::Binary(c) => c.is_null(row),
1429 ColumnView::Geohash(c) => c.is_null(row),
1430 ColumnView::Decimal128(c) => c.is_null(row),
1431 ColumnView::Decimal256(c) => c.is_null(row),
1432 ColumnView::DoubleArray(c) => c.is_null(row),
1433 ColumnView::LongArray(c) => c.is_null(row),
1434 }
1435 }
1436
1437 #[inline]
1438 pub fn validity<'b>(&'b self) -> Validity<'b> {
1439 match self {
1440 ColumnView::Boolean(c) => c.validity(),
1441 ColumnView::Byte(c) => c.validity(),
1442 ColumnView::Short(c) => c.validity(),
1443 ColumnView::Int(c) => c.validity(),
1444 ColumnView::Long(c) => c.validity(),
1445 ColumnView::Float(c) => c.validity(),
1446 ColumnView::Double(c) => c.validity(),
1447 ColumnView::Symbol(c) => c.validity(),
1448 ColumnView::Timestamp(c) => c.validity(),
1449 ColumnView::Date(c) => c.validity(),
1450 ColumnView::Uuid(c) => c.validity(),
1451 ColumnView::Long256(c) => c.validity(),
1452 ColumnView::TimestampNanos(c) => c.validity(),
1453 ColumnView::Decimal64(c) => c.validity(),
1454 ColumnView::Char(c) => c.validity(),
1455 ColumnView::Ipv4(c) => c.validity(),
1456 ColumnView::Varchar(c) => c.validity(),
1457 ColumnView::Binary(c) => c.validity(),
1458 ColumnView::Geohash(c) => c.validity(),
1459 ColumnView::Decimal128(c) => c.validity(),
1460 ColumnView::Decimal256(c) => c.validity(),
1461 ColumnView::DoubleArray(c) => c.validity(),
1462 ColumnView::LongArray(c) => c.validity(),
1463 }
1464 }
1465}
1466
1467#[cfg(test)]
1472mod tests {
1473 use super::*;
1474
1475 fn le_i64s(values: &[i64]) -> Vec<u8> {
1476 let mut out = Vec::with_capacity(values.len() * 8);
1477 for v in values {
1478 out.extend_from_slice(&v.to_le_bytes());
1479 }
1480 out
1481 }
1482
1483 fn le_f64s(values: &[f64]) -> Vec<u8> {
1484 let mut out = Vec::with_capacity(values.len() * 8);
1485 for v in values {
1486 out.extend_from_slice(&v.to_le_bytes());
1487 }
1488 out
1489 }
1490
1491 #[test]
1492 fn validity_no_bitmap() {
1493 let v = Validity::None;
1494 assert!(!v.has_nulls());
1495 for r in 0..10 {
1496 assert!(!v.is_null(r));
1497 }
1498 }
1499
1500 #[test]
1501 fn validity_bitmap_lsb_first_one_is_null() {
1502 let bytes = [0x05];
1505 let v = Validity::from_bitmap(&bytes, 8).unwrap();
1506 assert!(v.is_null(0));
1507 assert!(!v.is_null(1));
1508 assert!(v.is_null(2));
1509 for r in 3..8 {
1510 assert!(!v.is_null(r));
1511 }
1512 }
1513
1514 #[test]
1515 fn validity_bitmap_spans_bytes() {
1516 let bytes = [0x00, 0x02];
1518 let v = Validity::from_bitmap(&bytes, 10).unwrap();
1519 for r in 0..9 {
1520 assert!(!v.is_null(r));
1521 }
1522 assert!(v.is_null(9));
1523 }
1524
1525 #[test]
1526 fn validity_bitmap_exact_length_accepted() {
1527 let bytes = [0x00u8; 13]; let v = Validity::from_bitmap(&bytes, 100).unwrap();
1531 for r in 0..100 {
1532 assert!(!v.is_null(r));
1533 }
1534 }
1535
1536 #[test]
1537 fn validity_bitmap_short_rejected_in_constructor() {
1538 let bytes: [u8; 0] = [];
1542 let err = Validity::from_bitmap(&bytes, 100).unwrap_err();
1543 assert_eq!(err.code(), crate::ErrorCode::InvalidApiCall);
1544 assert!(err.msg().contains("Validity::from_bitmap: bitmap is"));
1545 }
1546
1547 #[test]
1548 fn validity_bitmap_off_by_one_rejected() {
1549 let bytes = [0xFFu8];
1551 let err = Validity::from_bitmap(&bytes, 9).unwrap_err();
1552 assert_eq!(err.code(), crate::ErrorCode::InvalidApiCall);
1553 }
1554
1555 #[test]
1556 fn validity_bitmap_direct_construction_short_does_not_panic() {
1557 let bytes: [u8; 0] = [];
1565 let v = Validity::Bitmap {
1566 bytes: &bytes,
1567 row_count: 100,
1568 };
1569 assert!(!v.is_null(50));
1570 }
1571
1572 #[test]
1573 fn fixed_i64_value_and_iter() {
1574 let raw = le_i64s(&[1, -2, 0x0102_0304_0506_0708]);
1575 let col = FixedColumn::<i64>::new(&raw, Validity::None);
1576 assert_eq!(col.len(), 3);
1577 assert_eq!(col.value(0), 1);
1578 assert_eq!(col.value(1), -2);
1579 assert_eq!(col.value(2), 0x0102_0304_0506_0708);
1580 let collected: Vec<_> = col.iter().collect();
1581 assert_eq!(
1582 collected,
1583 vec![Some(1i64), Some(-2), Some(0x0102_0304_0506_0708)]
1584 );
1585 }
1586
1587 #[test]
1588 fn fixed_f64_with_nulls() {
1589 let raw = le_f64s(&[1.0, 2.0, 3.0, 4.0]);
1590 let bm = [0x02];
1592 let col = FixedColumn::<f64>::new(&raw, Validity::from_bitmap(&bm, 4).unwrap());
1593 let collected: Vec<_> = col.iter().collect();
1594 assert_eq!(collected, vec![Some(1.0), None, Some(3.0), Some(4.0)]);
1595 }
1596
1597 #[test]
1598 fn fixed_i32_le() {
1599 let raw = vec![0x04u8, 0x03, 0x02, 0x01]; let col = FixedColumn::<i32>::new(&raw, Validity::None);
1601 assert_eq!(col.len(), 1);
1602 assert_eq!(col.value(0), 0x01020304);
1603 }
1604
1605 #[test]
1606 fn fixed_bool_via_u8() {
1607 let raw = vec![0x00u8, 0x01, 0x00];
1608 let col = FixedColumn::<u8>::new(&raw, Validity::None);
1609 assert_eq!(col.value(0), 0);
1610 assert_eq!(col.value(1), 1);
1611 }
1612
1613 #[test]
1614 fn uuid_value_returns_array() {
1615 let raw: Vec<u8> = (0..32u8).collect();
1616 let col = UuidColumn::new(&raw, Validity::None);
1617 assert_eq!(col.len(), 2);
1618 assert_eq!(col.value(0)[0], 0);
1619 assert_eq!(col.value(0)[15], 15);
1620 assert_eq!(col.value(1)[0], 16);
1621 assert_eq!(col.value(1)[15], 31);
1622 }
1623
1624 #[test]
1625 fn long256_value_returns_32_bytes() {
1626 let raw: Vec<u8> = (0..32u8).collect();
1627 let col = Long256Column::new(&raw, Validity::None);
1628 assert_eq!(col.len(), 1);
1629 assert_eq!(col.value(0).len(), 32);
1630 assert_eq!(col.value(0)[31], 31);
1631 }
1632
1633 #[test]
1634 fn symbol_resolves_codes_through_dict() {
1635 let mut dict = SymbolDict::new();
1636 dict.apply_delta(
1637 0,
1638 [b"AAPL".as_slice(), b"MSFT".as_slice(), b"GOOG".as_slice()],
1639 )
1640 .unwrap();
1641
1642 let codes = [0u32, 0, 1, 2];
1645 let bm = [0x02u8];
1646 let col = SymbolColumn::new(&codes, Validity::from_bitmap(&bm, 4).unwrap(), &dict);
1647
1648 assert_eq!(col.len(), 4);
1649 assert_eq!(col.resolve(0), Some("AAPL"));
1650 assert_eq!(col.resolve(1), None);
1651 assert_eq!(col.resolve(2), Some("MSFT"));
1652 assert_eq!(col.resolve(3), Some("GOOG"));
1653 }
1654
1655 #[test]
1656 fn symbol_no_nulls_path() {
1657 let mut dict = SymbolDict::new();
1658 dict.apply_delta(0, [b"x".as_slice(), b"y".as_slice()])
1659 .unwrap();
1660 let codes = [1u32, 0, 1];
1661 let col = SymbolColumn::new(&codes, Validity::None, &dict);
1662 assert_eq!(col.resolve(0), Some("y"));
1663 assert_eq!(col.resolve(1), Some("x"));
1664 assert_eq!(col.resolve(2), Some("y"));
1665 }
1666
1667 #[test]
1668 fn decimal64_carries_scale() {
1669 let raw = le_i64s(&[12345, 6789]);
1670 let col = Decimal64Column::new(&raw, Validity::None, 2);
1671 assert_eq!(col.scale(), 2);
1672 assert_eq!(col.value(0), 12345);
1673 assert_eq!(col.value(1), 6789);
1674 }
1675
1676 #[test]
1677 fn column_view_as_decimal_unifies_widths() {
1678 let raw64 = le_i64s(&[12345, -678]);
1679 let bitmap = [0x02u8];
1680 let view64 = ColumnView::Decimal64(Decimal64Column::new(
1681 &raw64,
1682 Validity::from_bitmap(&bitmap, 2).unwrap(),
1683 2,
1684 ));
1685 let decimal64 = view64.as_decimal().unwrap();
1686 assert_eq!(decimal64.kind(), ColumnKind::Decimal64);
1687 assert_eq!(decimal64.byte_width(), 8);
1688 assert_eq!(decimal64.max_precision(), 18);
1689 assert_eq!(decimal64.scale(), 2);
1690 assert_eq!(decimal64.len(), 2);
1691 assert!(!decimal64.is_empty());
1692 assert_eq!(decimal64.raw(), raw64.as_slice());
1693 assert_eq!(decimal64.mantissa_le(0), &raw64[..8]);
1694 assert!(decimal64.is_null(1));
1695 assert_eq!(decimal64.mantissa_le(1), &raw64[8..16]);
1696 assert_eq!(decimal64.validity().bytes(), Some(bitmap.as_slice()));
1697
1698 let raw128 = (-1_i128).to_le_bytes();
1699 let view128 = ColumnView::Decimal128(Decimal128Column::new(&raw128, Validity::None, 4));
1700 let decimal128 = view128.as_decimal().unwrap();
1701 assert_eq!(decimal128.kind(), ColumnKind::Decimal128);
1702 assert_eq!(decimal128.byte_width(), 16);
1703 assert_eq!(decimal128.max_precision(), 38);
1704 assert_eq!(decimal128.scale(), 4);
1705 assert_eq!(decimal128.mantissa_le(0), raw128.as_slice());
1706
1707 let raw256 = [0xFFu8; 32];
1708 let view256 = ColumnView::Decimal256(Decimal256Column::new(&raw256, Validity::None, 6));
1709 let decimal256 = view256.as_decimal().unwrap();
1710 assert_eq!(decimal256.kind(), ColumnKind::Decimal256);
1711 assert_eq!(decimal256.byte_width(), 32);
1712 assert_eq!(decimal256.max_precision(), 76);
1713 assert_eq!(decimal256.scale(), 6);
1714 assert_eq!(decimal256.mantissa_le(0), raw256.as_slice());
1715
1716 let non_decimal = ColumnView::Long(FixedColumn::<i64>::new(&raw64, Validity::None));
1717 assert!(non_decimal.as_decimal().is_none());
1718 }
1719
1720 #[test]
1721 #[should_panic(expected = "DecimalColumn::mantissa_le: row 1 out of range (len=1)")]
1722 fn decimal_column_mantissa_le_panics_out_of_range() {
1723 let raw = 1_i64.to_le_bytes();
1724 let view = ColumnView::Decimal64(Decimal64Column::new(&raw, Validity::None, 0));
1725 view.as_decimal().unwrap().mantissa_le(1);
1726 }
1727
1728 #[test]
1729 #[should_panic(expected = "DecimalColumn::mantissa_le: row")]
1730 fn decimal_column_mantissa_le_panics_before_offset_wraps() {
1731 let raw = 1_i64.to_le_bytes();
1732 let view = ColumnView::Decimal64(Decimal64Column::new(&raw, Validity::None, 0));
1733 let wrapping_row = 1usize << (usize::BITS - 3);
1734 view.as_decimal().unwrap().mantissa_le(wrapping_row);
1735 }
1736
1737 #[test]
1738 fn column_view_kind_matches_inner() {
1739 let raw = le_i64s(&[1, 2]);
1740 let v = ColumnView::Long(FixedColumn::<i64>::new(&raw, Validity::None));
1741 assert_eq!(v.kind(), ColumnKind::Long);
1742 assert_eq!(v.len(), 2);
1743
1744 let v = ColumnView::TimestampNanos(FixedColumn::<i64>::new(&raw, Validity::None));
1745 assert_eq!(v.kind(), ColumnKind::TimestampNanos);
1746
1747 let v = ColumnView::Decimal64(Decimal64Column::new(&raw, Validity::None, 4));
1748 assert_eq!(v.kind(), ColumnKind::Decimal64);
1749 }
1750
1751 #[test]
1752 fn column_view_is_null_dispatches() {
1753 let raw = le_i64s(&[1, 2, 3]);
1754 let bm = [0x02u8]; let v = ColumnView::Long(FixedColumn::<i64>::new(
1756 &raw,
1757 Validity::from_bitmap(&bm, 3).unwrap(),
1758 ));
1759 assert!(!v.is_null(0));
1760 assert!(v.is_null(1));
1761 assert!(!v.is_null(2));
1762 }
1763}