1use kyu_common::InternalId;
8use kyu_types::{Interval, LogicalType, PhysicalType};
9
10use crate::null_mask::NullMask;
11use crate::storage_types::{ColumnChunkMetadata, ColumnChunkStats, ResidencyState, StorageValue};
12
13pub trait FixedSizeValue: Copy + Sized {
16 const SIZE: usize = std::mem::size_of::<Self>();
17 fn to_bytes(&self) -> Vec<u8>;
18 fn from_bytes(bytes: &[u8]) -> Self;
19 fn to_storage_value(&self) -> Option<StorageValue>;
20}
21
22macro_rules! impl_fixed_size_int {
23 ($ty:ty, $variant:ident) => {
24 impl FixedSizeValue for $ty {
25 fn to_bytes(&self) -> Vec<u8> {
26 self.to_ne_bytes().to_vec()
27 }
28 fn from_bytes(bytes: &[u8]) -> Self {
29 let mut arr = [0u8; std::mem::size_of::<$ty>()];
30 arr.copy_from_slice(&bytes[..std::mem::size_of::<$ty>()]);
31 <$ty>::from_ne_bytes(arr)
32 }
33 fn to_storage_value(&self) -> Option<StorageValue> {
34 Some(StorageValue::$variant(*self as _))
35 }
36 }
37 };
38}
39
40impl_fixed_size_int!(i8, SignedInt);
41impl_fixed_size_int!(i16, SignedInt);
42impl_fixed_size_int!(i32, SignedInt);
43impl_fixed_size_int!(i64, SignedInt);
44impl_fixed_size_int!(u8, UnsignedInt);
45impl_fixed_size_int!(u16, UnsignedInt);
46impl_fixed_size_int!(u32, UnsignedInt);
47impl_fixed_size_int!(u64, UnsignedInt);
48
49impl FixedSizeValue for i128 {
50 fn to_bytes(&self) -> Vec<u8> {
51 self.to_ne_bytes().to_vec()
52 }
53 fn from_bytes(bytes: &[u8]) -> Self {
54 let mut arr = [0u8; 16];
55 arr.copy_from_slice(&bytes[..16]);
56 i128::from_ne_bytes(arr)
57 }
58 fn to_storage_value(&self) -> Option<StorageValue> {
59 Some(StorageValue::SignedInt128(*self))
60 }
61}
62
63impl FixedSizeValue for f32 {
64 fn to_bytes(&self) -> Vec<u8> {
65 self.to_ne_bytes().to_vec()
66 }
67 fn from_bytes(bytes: &[u8]) -> Self {
68 let mut arr = [0u8; 4];
69 arr.copy_from_slice(&bytes[..4]);
70 f32::from_ne_bytes(arr)
71 }
72 fn to_storage_value(&self) -> Option<StorageValue> {
73 Some(StorageValue::Float(*self as f64))
74 }
75}
76
77impl FixedSizeValue for f64 {
78 fn to_bytes(&self) -> Vec<u8> {
79 self.to_ne_bytes().to_vec()
80 }
81 fn from_bytes(bytes: &[u8]) -> Self {
82 let mut arr = [0u8; 8];
83 arr.copy_from_slice(&bytes[..8]);
84 f64::from_ne_bytes(arr)
85 }
86 fn to_storage_value(&self) -> Option<StorageValue> {
87 Some(StorageValue::Float(*self))
88 }
89}
90
91impl FixedSizeValue for InternalId {
92 fn to_bytes(&self) -> Vec<u8> {
93 let mut buf = Vec::with_capacity(16);
94 buf.extend_from_slice(&self.table_id.to_ne_bytes());
95 buf.extend_from_slice(&self.offset.to_ne_bytes());
96 buf
97 }
98 fn from_bytes(bytes: &[u8]) -> Self {
99 let mut tid = [0u8; 8];
100 let mut off = [0u8; 8];
101 tid.copy_from_slice(&bytes[..8]);
102 off.copy_from_slice(&bytes[8..16]);
103 InternalId::new(u64::from_ne_bytes(tid), u64::from_ne_bytes(off))
104 }
105 fn to_storage_value(&self) -> Option<StorageValue> {
106 None
107 }
108}
109
110impl FixedSizeValue for Interval {
111 fn to_bytes(&self) -> Vec<u8> {
112 let mut buf = Vec::with_capacity(16);
113 buf.extend_from_slice(&self.months.to_ne_bytes());
114 buf.extend_from_slice(&self.days.to_ne_bytes());
115 buf.extend_from_slice(&self.micros.to_ne_bytes());
116 buf
117 }
118 fn from_bytes(bytes: &[u8]) -> Self {
119 let mut m = [0u8; 4];
120 let mut d = [0u8; 4];
121 let mut u = [0u8; 8];
122 m.copy_from_slice(&bytes[..4]);
123 d.copy_from_slice(&bytes[4..8]);
124 u.copy_from_slice(&bytes[8..16]);
125 Interval::new(
126 i32::from_ne_bytes(m),
127 i32::from_ne_bytes(d),
128 i64::from_ne_bytes(u),
129 )
130 }
131 fn to_storage_value(&self) -> Option<StorageValue> {
132 None
133 }
134}
135
136pub struct ColumnChunkData {
138 data_type: LogicalType,
139 num_bytes_per_value: usize,
140 buffer: Vec<u8>,
141 null_data: NullMask,
142 capacity: u64,
143 num_values: u64,
144 stats: ColumnChunkStats,
145 metadata: ColumnChunkMetadata,
146 residency_state: ResidencyState,
147}
148
149impl ColumnChunkData {
150 pub fn new(data_type: LogicalType, capacity: u64) -> Self {
152 let physical = data_type.physical_type();
153 let num_bytes_per_value = physical.fixed_size().unwrap_or(0);
154 Self {
155 data_type,
156 num_bytes_per_value,
157 buffer: vec![0u8; num_bytes_per_value * capacity as usize],
158 null_data: NullMask::new(capacity),
159 capacity,
160 num_values: 0,
161 stats: ColumnChunkStats::default(),
162 metadata: ColumnChunkMetadata::default(),
163 residency_state: ResidencyState::InMemory,
164 }
165 }
166
167 pub fn data_type(&self) -> &LogicalType {
168 &self.data_type
169 }
170
171 pub fn capacity(&self) -> u64 {
172 self.capacity
173 }
174
175 pub fn num_values(&self) -> u64 {
176 self.num_values
177 }
178
179 pub fn is_null(&self, pos: u64) -> bool {
180 self.null_data.is_null(pos)
181 }
182
183 pub fn set_null(&mut self, pos: u64, is_null: bool) {
184 self.null_data.set_null(pos, is_null);
185 }
186
187 pub fn null_mask(&self) -> &NullMask {
188 &self.null_data
189 }
190
191 pub fn null_mask_mut(&mut self) -> &mut NullMask {
192 &mut self.null_data
193 }
194
195 pub fn stats(&self) -> &ColumnChunkStats {
196 &self.stats
197 }
198
199 pub fn metadata(&self) -> &ColumnChunkMetadata {
200 &self.metadata
201 }
202
203 pub fn set_metadata(&mut self, metadata: ColumnChunkMetadata) {
204 self.metadata = metadata;
205 }
206
207 pub fn residency_state(&self) -> ResidencyState {
208 self.residency_state
209 }
210
211 pub fn set_residency_state(&mut self, state: ResidencyState) {
212 self.residency_state = state;
213 }
214
215 pub fn get_value<T: FixedSizeValue>(&self, pos: u64) -> T {
217 debug_assert!(pos < self.num_values);
218 let offset = pos as usize * self.num_bytes_per_value;
219 T::from_bytes(&self.buffer[offset..offset + self.num_bytes_per_value])
220 }
221
222 pub fn set_value<T: FixedSizeValue>(&mut self, pos: u64, val: T) {
224 debug_assert!(pos < self.capacity);
225 let offset = pos as usize * self.num_bytes_per_value;
226 let bytes = val.to_bytes();
227 self.buffer[offset..offset + self.num_bytes_per_value].copy_from_slice(&bytes);
228 self.null_data.set_null(pos, false);
229 if let Some(sv) = val.to_storage_value() {
230 self.stats.update(sv);
231 }
232 }
233
234 pub fn append_value<T: FixedSizeValue>(&mut self, val: T) {
236 let pos = self.num_values;
237 debug_assert!(pos < self.capacity);
238 self.set_value(pos, val);
239 self.num_values += 1;
240 }
241
242 pub fn append_null(&mut self) {
244 let pos = self.num_values;
245 debug_assert!(pos < self.capacity);
246 self.null_data.set_null(pos, true);
247 self.num_values += 1;
248 }
249
250 pub fn get_raw(&self, pos: u64) -> &[u8] {
252 let offset = pos as usize * self.num_bytes_per_value;
253 &self.buffer[offset..offset + self.num_bytes_per_value]
254 }
255
256 pub fn set_raw(&mut self, pos: u64, bytes: &[u8]) {
258 debug_assert!(pos < self.capacity);
259 debug_assert_eq!(bytes.len(), self.num_bytes_per_value);
260 let offset = pos as usize * self.num_bytes_per_value;
261 self.buffer[offset..offset + self.num_bytes_per_value].copy_from_slice(bytes);
262 self.null_data.set_null(pos, false);
263 }
264
265 pub fn scan_range<T: FixedSizeValue>(&self, start: u64, count: u64) -> Vec<Option<T>> {
267 let mut result = Vec::with_capacity(count as usize);
268 for i in start..start + count {
269 if self.null_data.is_null(i) {
270 result.push(None);
271 } else {
272 result.push(Some(self.get_value::<T>(i)));
273 }
274 }
275 result
276 }
277
278 pub fn buffer(&self) -> &[u8] {
280 &self.buffer
281 }
282
283 pub fn num_bytes_per_value(&self) -> usize {
285 self.num_bytes_per_value
286 }
287
288 pub fn set_num_values(&mut self, n: u64) {
290 self.num_values = n;
291 }
292}
293
294pub struct BoolChunkData {
296 data_type: LogicalType,
297 values: NullMask,
299 null_data: NullMask,
300 capacity: u64,
301 num_values: u64,
302 residency_state: ResidencyState,
303}
304
305impl BoolChunkData {
306 pub fn new(capacity: u64) -> Self {
307 Self {
308 data_type: LogicalType::Bool,
309 values: NullMask::new(capacity),
310 null_data: NullMask::new(capacity),
311 capacity,
312 num_values: 0,
313 residency_state: ResidencyState::InMemory,
314 }
315 }
316
317 pub fn data_type(&self) -> &LogicalType {
318 &self.data_type
319 }
320
321 pub fn capacity(&self) -> u64 {
322 self.capacity
323 }
324
325 pub fn num_values(&self) -> u64 {
326 self.num_values
327 }
328
329 pub fn is_null(&self, pos: u64) -> bool {
330 self.null_data.is_null(pos)
331 }
332
333 pub fn set_null(&mut self, pos: u64, is_null: bool) {
334 self.null_data.set_null(pos, is_null);
335 }
336
337 pub fn null_mask(&self) -> &NullMask {
338 &self.null_data
339 }
340
341 pub fn values_mask(&self) -> &NullMask {
343 &self.values
344 }
345
346 pub fn residency_state(&self) -> ResidencyState {
347 self.residency_state
348 }
349
350 pub fn get_bool(&self, pos: u64) -> bool {
353 self.values.is_null(pos)
354 }
355
356 pub fn set_bool(&mut self, pos: u64, val: bool) {
358 self.values.set_null(pos, val);
359 self.null_data.set_null(pos, false);
360 }
361
362 pub fn append_bool(&mut self, val: bool) {
364 let pos = self.num_values;
365 debug_assert!(pos < self.capacity);
366 self.set_bool(pos, val);
367 self.num_values += 1;
368 }
369
370 pub fn append_null(&mut self) {
372 let pos = self.num_values;
373 debug_assert!(pos < self.capacity);
374 self.null_data.set_null(pos, true);
375 self.num_values += 1;
376 }
377
378 pub fn scan_range(&self, start: u64, count: u64) -> Vec<Option<bool>> {
380 let mut result = Vec::with_capacity(count as usize);
381 for i in start..start + count {
382 if self.null_data.is_null(i) {
383 result.push(None);
384 } else {
385 result.push(Some(self.get_bool(i)));
386 }
387 }
388 result
389 }
390
391 pub fn set_num_values(&mut self, n: u64) {
393 self.num_values = n;
394 }
395}
396
397pub struct StringChunkData {
403 data: Vec<Option<smol_str::SmolStr>>,
404 capacity: u64,
405 num_values: u64,
406 residency_state: ResidencyState,
407}
408
409impl StringChunkData {
410 pub fn new(capacity: u64) -> Self {
411 let mut data = Vec::with_capacity(capacity as usize);
412 data.resize(capacity as usize, None);
413 Self {
414 data,
415 capacity,
416 num_values: 0,
417 residency_state: ResidencyState::InMemory,
418 }
419 }
420
421 pub fn capacity(&self) -> u64 {
422 self.capacity
423 }
424
425 pub fn num_values(&self) -> u64 {
426 self.num_values
427 }
428
429 pub fn is_null(&self, pos: u64) -> bool {
430 self.data[pos as usize].is_none()
431 }
432
433 pub fn set_null(&mut self, pos: u64, is_null: bool) {
434 if is_null {
435 self.data[pos as usize] = None;
436 }
437 }
438
439 pub fn residency_state(&self) -> ResidencyState {
440 self.residency_state
441 }
442
443 pub fn append_string(&mut self, val: smol_str::SmolStr) {
445 let pos = self.num_values as usize;
446 debug_assert!(self.num_values < self.capacity);
447 self.data[pos] = Some(val);
448 self.num_values += 1;
449 }
450
451 pub fn append_null(&mut self) {
453 debug_assert!(self.num_values < self.capacity);
454 self.num_values += 1;
456 }
457
458 pub fn set_string(&mut self, pos: u64, val: smol_str::SmolStr) {
460 self.data[pos as usize] = Some(val);
461 }
462
463 pub fn get(&self, pos: u64) -> Option<&smol_str::SmolStr> {
465 self.data[pos as usize].as_ref()
466 }
467
468 pub fn scan_range(&self, start: u64, count: u64) -> &[Option<smol_str::SmolStr>] {
470 &self.data[start as usize..(start + count) as usize]
471 }
472
473 pub fn data_slice(&self) -> &[Option<smol_str::SmolStr>] {
475 &self.data
476 }
477
478 pub fn set_num_values(&mut self, n: u64) {
480 self.num_values = n;
481 }
482}
483
484pub enum ColumnChunk {
486 Fixed(ColumnChunkData),
487 Bool(BoolChunkData),
488 String(StringChunkData),
489}
490
491impl ColumnChunk {
492 pub fn new(data_type: LogicalType, capacity: u64) -> Self {
494 let physical = data_type.physical_type();
495 if physical == PhysicalType::Bool {
496 ColumnChunk::Bool(BoolChunkData::new(capacity))
497 } else if physical == PhysicalType::String {
498 ColumnChunk::String(StringChunkData::new(capacity))
499 } else {
500 ColumnChunk::Fixed(ColumnChunkData::new(data_type, capacity))
501 }
502 }
503
504 pub fn data_type(&self) -> &LogicalType {
505 match self {
506 Self::Fixed(c) => c.data_type(),
507 Self::Bool(c) => c.data_type(),
508 Self::String(_) => &LogicalType::String,
509 }
510 }
511
512 pub fn num_values(&self) -> u64 {
513 match self {
514 Self::Fixed(c) => c.num_values(),
515 Self::Bool(c) => c.num_values(),
516 Self::String(c) => c.num_values(),
517 }
518 }
519
520 pub fn capacity(&self) -> u64 {
521 match self {
522 Self::Fixed(c) => c.capacity(),
523 Self::Bool(c) => c.capacity(),
524 Self::String(c) => c.capacity(),
525 }
526 }
527
528 pub fn is_null(&self, pos: u64) -> bool {
529 match self {
530 Self::Fixed(c) => c.is_null(pos),
531 Self::Bool(c) => c.is_null(pos),
532 Self::String(c) => c.is_null(pos),
533 }
534 }
535
536 pub fn set_null(&mut self, pos: u64, is_null: bool) {
537 match self {
538 Self::Fixed(c) => c.set_null(pos, is_null),
539 Self::Bool(c) => c.set_null(pos, is_null),
540 Self::String(c) => c.set_null(pos, is_null),
541 }
542 }
543
544 pub fn append_null(&mut self) {
545 match self {
546 Self::Fixed(c) => c.append_null(),
547 Self::Bool(c) => c.append_null(),
548 Self::String(c) => c.append_null(),
549 }
550 }
551
552 pub fn residency_state(&self) -> ResidencyState {
553 match self {
554 Self::Fixed(c) => c.residency_state(),
555 Self::Bool(c) => c.residency_state(),
556 Self::String(c) => c.residency_state(),
557 }
558 }
559
560 pub fn set_raw(&mut self, pos: u64, bytes: &[u8]) {
562 match self {
563 Self::Fixed(c) => c.set_raw(pos, bytes),
564 Self::Bool(_) => panic!("set_raw not supported for BoolChunkData"),
565 Self::String(_) => panic!("set_raw not supported for StringChunkData"),
566 }
567 }
568
569 pub fn set_num_values(&mut self, n: u64) {
571 match self {
572 Self::Fixed(c) => c.set_num_values(n),
573 Self::Bool(c) => c.set_num_values(n),
574 Self::String(c) => c.set_num_values(n),
575 }
576 }
577}
578
579#[cfg(test)]
580mod tests {
581 use super::*;
582
583 #[test]
584 fn fixed_size_value_i64_roundtrip() {
585 let val: i64 = -42;
586 let bytes = val.to_bytes();
587 assert_eq!(i64::from_bytes(&bytes), val);
588 }
589
590 #[test]
591 fn fixed_size_value_f64_roundtrip() {
592 let val: f64 = 3.14159;
593 let bytes = val.to_bytes();
594 assert_eq!(f64::from_bytes(&bytes), val);
595 }
596
597 #[test]
598 fn fixed_size_value_internal_id_roundtrip() {
599 let val = InternalId::new(3, 42);
600 let bytes = val.to_bytes();
601 assert_eq!(InternalId::from_bytes(&bytes), val);
602 }
603
604 #[test]
605 fn fixed_size_value_interval_roundtrip() {
606 let val = Interval::new(14, 5, 3_723_000_000);
607 let bytes = val.to_bytes();
608 assert_eq!(Interval::from_bytes(&bytes), val);
609 }
610
611 #[test]
612 fn fixed_size_value_i128_roundtrip() {
613 let val: i128 = -170_141_183_460_469_231_731_687_303_715_884_105_728;
614 let bytes = val.to_bytes();
615 assert_eq!(i128::from_bytes(&bytes), val);
616 }
617
618 #[test]
619 fn column_chunk_data_new() {
620 let chunk = ColumnChunkData::new(LogicalType::Int64, 100);
621 assert_eq!(chunk.num_values(), 0);
622 assert_eq!(chunk.capacity(), 100);
623 assert_eq!(chunk.num_bytes_per_value(), 8);
624 assert_eq!(chunk.residency_state(), ResidencyState::InMemory);
625 }
626
627 #[test]
628 fn column_chunk_data_append_and_get() {
629 let mut chunk = ColumnChunkData::new(LogicalType::Int64, 10);
630 chunk.append_value(42i64);
631 chunk.append_value(-7i64);
632 chunk.append_value(100i64);
633
634 assert_eq!(chunk.num_values(), 3);
635 assert_eq!(chunk.get_value::<i64>(0), 42);
636 assert_eq!(chunk.get_value::<i64>(1), -7);
637 assert_eq!(chunk.get_value::<i64>(2), 100);
638 }
639
640 #[test]
641 fn column_chunk_data_set_value() {
642 let mut chunk = ColumnChunkData::new(LogicalType::Int32, 10);
643 chunk.set_num_values(3);
644 chunk.set_value(0, 10i32);
645 chunk.set_value(1, 20i32);
646 chunk.set_value(2, 30i32);
647
648 assert_eq!(chunk.get_value::<i32>(0), 10);
649 assert_eq!(chunk.get_value::<i32>(1), 20);
650 assert_eq!(chunk.get_value::<i32>(2), 30);
651 }
652
653 #[test]
654 fn column_chunk_data_nulls() {
655 let mut chunk = ColumnChunkData::new(LogicalType::Int64, 10);
656 chunk.append_value(42i64);
657 chunk.append_null();
658 chunk.append_value(100i64);
659
660 assert!(!chunk.is_null(0));
661 assert!(chunk.is_null(1));
662 assert!(!chunk.is_null(2));
663 }
664
665 #[test]
666 fn column_chunk_data_scan_range() {
667 let mut chunk = ColumnChunkData::new(LogicalType::Int64, 10);
668 chunk.append_value(1i64);
669 chunk.append_null();
670 chunk.append_value(3i64);
671
672 let result = chunk.scan_range::<i64>(0, 3);
673 assert_eq!(result, vec![Some(1), None, Some(3)]);
674 }
675
676 #[test]
677 fn column_chunk_data_raw_access() {
678 let mut chunk = ColumnChunkData::new(LogicalType::Int32, 10);
679 chunk.set_num_values(1);
680 let val: i32 = 42;
681 chunk.set_raw(0, &val.to_ne_bytes());
682 assert_eq!(chunk.get_value::<i32>(0), 42);
683
684 let raw = chunk.get_raw(0);
685 assert_eq!(raw, &val.to_ne_bytes());
686 }
687
688 #[test]
689 fn column_chunk_data_stats_tracking() {
690 let mut chunk = ColumnChunkData::new(LogicalType::Int64, 10);
691 chunk.append_value(10i64);
692 chunk.append_value(-5i64);
693 chunk.append_value(20i64);
694
695 assert_eq!(chunk.stats().min, Some(StorageValue::SignedInt(-5)));
696 assert_eq!(chunk.stats().max, Some(StorageValue::SignedInt(20)));
697 }
698
699 #[test]
700 fn column_chunk_data_f64_stats() {
701 let mut chunk = ColumnChunkData::new(LogicalType::Double, 10);
702 chunk.append_value(1.5f64);
703 chunk.append_value(3.7f64);
704 chunk.append_value(0.1f64);
705
706 assert_eq!(chunk.stats().min, Some(StorageValue::Float(0.1)));
707 assert_eq!(chunk.stats().max, Some(StorageValue::Float(3.7)));
708 }
709
710 #[test]
711 fn column_chunk_data_internal_id() {
712 let mut chunk = ColumnChunkData::new(LogicalType::InternalId, 10);
713 let id = InternalId::new(3, 42);
714 chunk.append_value(id);
715 assert_eq!(chunk.get_value::<InternalId>(0), id);
716 }
717
718 #[test]
719 fn bool_chunk_data_new() {
720 let chunk = BoolChunkData::new(100);
721 assert_eq!(chunk.num_values(), 0);
722 assert_eq!(chunk.capacity(), 100);
723 assert_eq!(*chunk.data_type(), LogicalType::Bool);
724 }
725
726 #[test]
727 fn bool_chunk_data_append_and_get() {
728 let mut chunk = BoolChunkData::new(10);
729 chunk.append_bool(true);
730 chunk.append_bool(false);
731 chunk.append_bool(true);
732
733 assert_eq!(chunk.num_values(), 3);
734 assert!(chunk.get_bool(0));
735 assert!(!chunk.get_bool(1));
736 assert!(chunk.get_bool(2));
737 }
738
739 #[test]
740 fn bool_chunk_data_nulls() {
741 let mut chunk = BoolChunkData::new(10);
742 chunk.append_bool(true);
743 chunk.append_null();
744 chunk.append_bool(false);
745
746 assert!(!chunk.is_null(0));
747 assert!(chunk.is_null(1));
748 assert!(!chunk.is_null(2));
749 }
750
751 #[test]
752 fn bool_chunk_data_scan_range() {
753 let mut chunk = BoolChunkData::new(10);
754 chunk.append_bool(true);
755 chunk.append_null();
756 chunk.append_bool(false);
757
758 let result = chunk.scan_range(0, 3);
759 assert_eq!(result, vec![Some(true), None, Some(false)]);
760 }
761
762 #[test]
763 fn column_chunk_enum_fixed() {
764 let mut chunk = ColumnChunk::new(LogicalType::Int64, 10);
765 assert_eq!(*chunk.data_type(), LogicalType::Int64);
766 assert_eq!(chunk.capacity(), 10);
767
768 match &mut chunk {
769 ColumnChunk::Fixed(c) => c.append_value(42i64),
770 _ => panic!("expected Fixed"),
771 }
772 assert_eq!(chunk.num_values(), 1);
773 }
774
775 #[test]
776 fn column_chunk_enum_bool() {
777 let mut chunk = ColumnChunk::new(LogicalType::Bool, 10);
778 assert_eq!(*chunk.data_type(), LogicalType::Bool);
779
780 match &mut chunk {
781 ColumnChunk::Bool(c) => c.append_bool(true),
782 _ => panic!("expected Bool"),
783 }
784 assert_eq!(chunk.num_values(), 1);
785 }
786
787 #[test]
788 fn column_chunk_enum_null() {
789 let mut chunk = ColumnChunk::new(LogicalType::Int32, 10);
790 chunk.append_null();
791 assert_eq!(chunk.num_values(), 1);
792 assert!(chunk.is_null(0));
793 }
794
795 #[test]
796 fn column_chunk_set_raw() {
797 let mut chunk = ColumnChunk::new(LogicalType::Int32, 10);
798 chunk.set_num_values(1);
799 let val: i32 = 99;
800 chunk.set_raw(0, &val.to_ne_bytes());
801 match &chunk {
802 ColumnChunk::Fixed(c) => assert_eq!(c.get_value::<i32>(0), 99),
803 _ => panic!("expected Fixed"),
804 }
805 }
806
807 #[test]
808 fn column_chunk_multiple_types() {
809 let mut c = ColumnChunkData::new(LogicalType::UInt8, 4);
811 c.append_value(255u8);
812 assert_eq!(c.get_value::<u8>(0), 255);
813
814 let mut c = ColumnChunkData::new(LogicalType::UInt16, 4);
816 c.append_value(65535u16);
817 assert_eq!(c.get_value::<u16>(0), 65535);
818
819 let mut c = ColumnChunkData::new(LogicalType::UInt32, 4);
821 c.append_value(u32::MAX);
822 assert_eq!(c.get_value::<u32>(0), u32::MAX);
823
824 let mut c = ColumnChunkData::new(LogicalType::Float, 4);
826 c.append_value(1.5f32);
827 assert_eq!(c.get_value::<f32>(0), 1.5);
828 }
829}