Skip to main content

reifydb_core/value/column/data/
mod.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2025 ReifyDB
3
4pub mod extend;
5pub mod factory;
6pub mod filter;
7pub mod from;
8pub mod get;
9pub mod reorder;
10pub mod scatter;
11pub mod slice;
12pub mod take;
13
14use std::fmt;
15
16use reifydb_type::{
17	storage::{Cow, DataBitVec, Storage},
18	util::bitvec::BitVec,
19	value::{
20		Value,
21		constraint::{bytes::MaxBytes, precision::Precision, scale::Scale},
22		container::{
23			any::AnyContainer, blob::BlobContainer, bool::BoolContainer, dictionary::DictionaryContainer,
24			identity_id::IdentityIdContainer, number::NumberContainer, temporal::TemporalContainer,
25			utf8::Utf8Container, uuid::UuidContainer,
26		},
27		date::Date,
28		datetime::DateTime,
29		decimal::Decimal,
30		duration::Duration,
31		int::Int,
32		time::Time,
33		r#type::Type,
34		uint::Uint,
35		uuid::{Uuid4, Uuid7},
36	},
37};
38use serde::{Deserialize, Deserializer, Serialize, Serializer};
39
40pub enum ColumnData<S: Storage = Cow> {
41	Bool(BoolContainer<S>),
42	Float4(NumberContainer<f32, S>),
43	Float8(NumberContainer<f64, S>),
44	Int1(NumberContainer<i8, S>),
45	Int2(NumberContainer<i16, S>),
46	Int4(NumberContainer<i32, S>),
47	Int8(NumberContainer<i64, S>),
48	Int16(NumberContainer<i128, S>),
49	Uint1(NumberContainer<u8, S>),
50	Uint2(NumberContainer<u16, S>),
51	Uint4(NumberContainer<u32, S>),
52	Uint8(NumberContainer<u64, S>),
53	Uint16(NumberContainer<u128, S>),
54	Utf8 {
55		container: Utf8Container<S>,
56		max_bytes: MaxBytes,
57	},
58	Date(TemporalContainer<Date, S>),
59	DateTime(TemporalContainer<DateTime, S>),
60	Time(TemporalContainer<Time, S>),
61	Duration(TemporalContainer<Duration, S>),
62	IdentityId(IdentityIdContainer<S>),
63	Uuid4(UuidContainer<Uuid4, S>),
64	Uuid7(UuidContainer<Uuid7, S>),
65	Blob {
66		container: BlobContainer<S>,
67		max_bytes: MaxBytes,
68	},
69	Int {
70		container: NumberContainer<Int, S>,
71		max_bytes: MaxBytes,
72	},
73	Uint {
74		container: NumberContainer<Uint, S>,
75		max_bytes: MaxBytes,
76	},
77	Decimal {
78		container: NumberContainer<Decimal, S>,
79		precision: Precision,
80		scale: Scale,
81	},
82	// Container for Any type (heterogeneous values)
83	Any(AnyContainer<S>),
84	// Container for DictionaryEntryId values
85	DictionaryId(DictionaryContainer<S>),
86	// Nullable wrapper: inner holds the typed data, bitvec tracks definedness
87	Option {
88		inner: Box<ColumnData<S>>,
89		bitvec: S::BitVec,
90	},
91}
92
93impl<S: Storage> Clone for ColumnData<S> {
94	fn clone(&self) -> Self {
95		match self {
96			ColumnData::Bool(c) => ColumnData::Bool(c.clone()),
97			ColumnData::Float4(c) => ColumnData::Float4(c.clone()),
98			ColumnData::Float8(c) => ColumnData::Float8(c.clone()),
99			ColumnData::Int1(c) => ColumnData::Int1(c.clone()),
100			ColumnData::Int2(c) => ColumnData::Int2(c.clone()),
101			ColumnData::Int4(c) => ColumnData::Int4(c.clone()),
102			ColumnData::Int8(c) => ColumnData::Int8(c.clone()),
103			ColumnData::Int16(c) => ColumnData::Int16(c.clone()),
104			ColumnData::Uint1(c) => ColumnData::Uint1(c.clone()),
105			ColumnData::Uint2(c) => ColumnData::Uint2(c.clone()),
106			ColumnData::Uint4(c) => ColumnData::Uint4(c.clone()),
107			ColumnData::Uint8(c) => ColumnData::Uint8(c.clone()),
108			ColumnData::Uint16(c) => ColumnData::Uint16(c.clone()),
109			ColumnData::Utf8 {
110				container,
111				max_bytes,
112			} => ColumnData::Utf8 {
113				container: container.clone(),
114				max_bytes: *max_bytes,
115			},
116			ColumnData::Date(c) => ColumnData::Date(c.clone()),
117			ColumnData::DateTime(c) => ColumnData::DateTime(c.clone()),
118			ColumnData::Time(c) => ColumnData::Time(c.clone()),
119			ColumnData::Duration(c) => ColumnData::Duration(c.clone()),
120			ColumnData::IdentityId(c) => ColumnData::IdentityId(c.clone()),
121			ColumnData::Uuid4(c) => ColumnData::Uuid4(c.clone()),
122			ColumnData::Uuid7(c) => ColumnData::Uuid7(c.clone()),
123			ColumnData::Blob {
124				container,
125				max_bytes,
126			} => ColumnData::Blob {
127				container: container.clone(),
128				max_bytes: *max_bytes,
129			},
130			ColumnData::Int {
131				container,
132				max_bytes,
133			} => ColumnData::Int {
134				container: container.clone(),
135				max_bytes: *max_bytes,
136			},
137			ColumnData::Uint {
138				container,
139				max_bytes,
140			} => ColumnData::Uint {
141				container: container.clone(),
142				max_bytes: *max_bytes,
143			},
144			ColumnData::Decimal {
145				container,
146				precision,
147				scale,
148			} => ColumnData::Decimal {
149				container: container.clone(),
150				precision: *precision,
151				scale: *scale,
152			},
153			ColumnData::Any(c) => ColumnData::Any(c.clone()),
154			ColumnData::DictionaryId(c) => ColumnData::DictionaryId(c.clone()),
155			ColumnData::Option {
156				inner,
157				bitvec,
158			} => ColumnData::Option {
159				inner: inner.clone(),
160				bitvec: bitvec.clone(),
161			},
162		}
163	}
164}
165
166impl<S: Storage> PartialEq for ColumnData<S> {
167	fn eq(&self, other: &Self) -> bool {
168		match (self, other) {
169			(ColumnData::Bool(a), ColumnData::Bool(b)) => a == b,
170			(ColumnData::Float4(a), ColumnData::Float4(b)) => a == b,
171			(ColumnData::Float8(a), ColumnData::Float8(b)) => a == b,
172			(ColumnData::Int1(a), ColumnData::Int1(b)) => a == b,
173			(ColumnData::Int2(a), ColumnData::Int2(b)) => a == b,
174			(ColumnData::Int4(a), ColumnData::Int4(b)) => a == b,
175			(ColumnData::Int8(a), ColumnData::Int8(b)) => a == b,
176			(ColumnData::Int16(a), ColumnData::Int16(b)) => a == b,
177			(ColumnData::Uint1(a), ColumnData::Uint1(b)) => a == b,
178			(ColumnData::Uint2(a), ColumnData::Uint2(b)) => a == b,
179			(ColumnData::Uint4(a), ColumnData::Uint4(b)) => a == b,
180			(ColumnData::Uint8(a), ColumnData::Uint8(b)) => a == b,
181			(ColumnData::Uint16(a), ColumnData::Uint16(b)) => a == b,
182			(
183				ColumnData::Utf8 {
184					container: a,
185					max_bytes: am,
186				},
187				ColumnData::Utf8 {
188					container: b,
189					max_bytes: bm,
190				},
191			) => a == b && am == bm,
192			(ColumnData::Date(a), ColumnData::Date(b)) => a == b,
193			(ColumnData::DateTime(a), ColumnData::DateTime(b)) => a == b,
194			(ColumnData::Time(a), ColumnData::Time(b)) => a == b,
195			(ColumnData::Duration(a), ColumnData::Duration(b)) => a == b,
196			(ColumnData::IdentityId(a), ColumnData::IdentityId(b)) => a == b,
197			(ColumnData::Uuid4(a), ColumnData::Uuid4(b)) => a == b,
198			(ColumnData::Uuid7(a), ColumnData::Uuid7(b)) => a == b,
199			(
200				ColumnData::Blob {
201					container: a,
202					max_bytes: am,
203				},
204				ColumnData::Blob {
205					container: b,
206					max_bytes: bm,
207				},
208			) => a == b && am == bm,
209			(
210				ColumnData::Int {
211					container: a,
212					max_bytes: am,
213				},
214				ColumnData::Int {
215					container: b,
216					max_bytes: bm,
217				},
218			) => a == b && am == bm,
219			(
220				ColumnData::Uint {
221					container: a,
222					max_bytes: am,
223				},
224				ColumnData::Uint {
225					container: b,
226					max_bytes: bm,
227				},
228			) => a == b && am == bm,
229			(
230				ColumnData::Decimal {
231					container: a,
232					precision: ap,
233					scale: as_,
234				},
235				ColumnData::Decimal {
236					container: b,
237					precision: bp,
238					scale: bs,
239				},
240			) => a == b && ap == bp && as_ == bs,
241			(ColumnData::Any(a), ColumnData::Any(b)) => a == b,
242			(ColumnData::DictionaryId(a), ColumnData::DictionaryId(b)) => a == b,
243			(
244				ColumnData::Option {
245					inner: ai,
246					bitvec: ab,
247				},
248				ColumnData::Option {
249					inner: bi,
250					bitvec: bb,
251				},
252			) => ai == bi && ab == bb,
253			_ => false,
254		}
255	}
256}
257
258impl fmt::Debug for ColumnData<Cow> {
259	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
260		match self {
261			ColumnData::Bool(c) => f.debug_tuple("Bool").field(c).finish(),
262			ColumnData::Float4(c) => f.debug_tuple("Float4").field(c).finish(),
263			ColumnData::Float8(c) => f.debug_tuple("Float8").field(c).finish(),
264			ColumnData::Int1(c) => f.debug_tuple("Int1").field(c).finish(),
265			ColumnData::Int2(c) => f.debug_tuple("Int2").field(c).finish(),
266			ColumnData::Int4(c) => f.debug_tuple("Int4").field(c).finish(),
267			ColumnData::Int8(c) => f.debug_tuple("Int8").field(c).finish(),
268			ColumnData::Int16(c) => f.debug_tuple("Int16").field(c).finish(),
269			ColumnData::Uint1(c) => f.debug_tuple("Uint1").field(c).finish(),
270			ColumnData::Uint2(c) => f.debug_tuple("Uint2").field(c).finish(),
271			ColumnData::Uint4(c) => f.debug_tuple("Uint4").field(c).finish(),
272			ColumnData::Uint8(c) => f.debug_tuple("Uint8").field(c).finish(),
273			ColumnData::Uint16(c) => f.debug_tuple("Uint16").field(c).finish(),
274			ColumnData::Utf8 {
275				container,
276				max_bytes,
277			} => f.debug_struct("Utf8").field("container", container).field("max_bytes", max_bytes).finish(),
278			ColumnData::Date(c) => f.debug_tuple("Date").field(c).finish(),
279			ColumnData::DateTime(c) => f.debug_tuple("DateTime").field(c).finish(),
280			ColumnData::Time(c) => f.debug_tuple("Time").field(c).finish(),
281			ColumnData::Duration(c) => f.debug_tuple("Duration").field(c).finish(),
282			ColumnData::IdentityId(c) => f.debug_tuple("IdentityId").field(c).finish(),
283			ColumnData::Uuid4(c) => f.debug_tuple("Uuid4").field(c).finish(),
284			ColumnData::Uuid7(c) => f.debug_tuple("Uuid7").field(c).finish(),
285			ColumnData::Blob {
286				container,
287				max_bytes,
288			} => f.debug_struct("Blob").field("container", container).field("max_bytes", max_bytes).finish(),
289			ColumnData::Int {
290				container,
291				max_bytes,
292			} => f.debug_struct("Int").field("container", container).field("max_bytes", max_bytes).finish(),
293			ColumnData::Uint {
294				container,
295				max_bytes,
296			} => f.debug_struct("Uint").field("container", container).field("max_bytes", max_bytes).finish(),
297			ColumnData::Decimal {
298				container,
299				precision,
300				scale,
301			} => f.debug_struct("Decimal")
302				.field("container", container)
303				.field("precision", precision)
304				.field("scale", scale)
305				.finish(),
306			ColumnData::Any(c) => f.debug_tuple("Any").field(c).finish(),
307			ColumnData::DictionaryId(c) => f.debug_tuple("DictionaryId").field(c).finish(),
308			ColumnData::Option {
309				inner,
310				bitvec,
311			} => f.debug_struct("Option").field("inner", inner).field("bitvec", bitvec).finish(),
312		}
313	}
314}
315
316impl Serialize for ColumnData<Cow> {
317	fn serialize<Ser: Serializer>(&self, serializer: Ser) -> Result<Ser::Ok, Ser::Error> {
318		#[derive(Serialize)]
319		enum Helper<'a> {
320			Bool(&'a BoolContainer),
321			Float4(&'a NumberContainer<f32>),
322			Float8(&'a NumberContainer<f64>),
323			Int1(&'a NumberContainer<i8>),
324			Int2(&'a NumberContainer<i16>),
325			Int4(&'a NumberContainer<i32>),
326			Int8(&'a NumberContainer<i64>),
327			Int16(&'a NumberContainer<i128>),
328			Uint1(&'a NumberContainer<u8>),
329			Uint2(&'a NumberContainer<u16>),
330			Uint4(&'a NumberContainer<u32>),
331			Uint8(&'a NumberContainer<u64>),
332			Uint16(&'a NumberContainer<u128>),
333			Utf8 {
334				container: &'a Utf8Container,
335				max_bytes: MaxBytes,
336			},
337			Date(&'a TemporalContainer<Date>),
338			DateTime(&'a TemporalContainer<DateTime>),
339			Time(&'a TemporalContainer<Time>),
340			Duration(&'a TemporalContainer<Duration>),
341			IdentityId(&'a IdentityIdContainer),
342			Uuid4(&'a UuidContainer<Uuid4>),
343			Uuid7(&'a UuidContainer<Uuid7>),
344			Blob {
345				container: &'a BlobContainer,
346				max_bytes: MaxBytes,
347			},
348			Int {
349				container: &'a NumberContainer<Int>,
350				max_bytes: MaxBytes,
351			},
352			Uint {
353				container: &'a NumberContainer<Uint>,
354				max_bytes: MaxBytes,
355			},
356			Decimal {
357				container: &'a NumberContainer<Decimal>,
358				precision: Precision,
359				scale: Scale,
360			},
361			Any(&'a AnyContainer),
362			DictionaryId(&'a DictionaryContainer),
363			Option {
364				inner: &'a ColumnData,
365				bitvec: &'a BitVec,
366			},
367		}
368		let helper = match self {
369			ColumnData::Bool(c) => Helper::Bool(c),
370			ColumnData::Float4(c) => Helper::Float4(c),
371			ColumnData::Float8(c) => Helper::Float8(c),
372			ColumnData::Int1(c) => Helper::Int1(c),
373			ColumnData::Int2(c) => Helper::Int2(c),
374			ColumnData::Int4(c) => Helper::Int4(c),
375			ColumnData::Int8(c) => Helper::Int8(c),
376			ColumnData::Int16(c) => Helper::Int16(c),
377			ColumnData::Uint1(c) => Helper::Uint1(c),
378			ColumnData::Uint2(c) => Helper::Uint2(c),
379			ColumnData::Uint4(c) => Helper::Uint4(c),
380			ColumnData::Uint8(c) => Helper::Uint8(c),
381			ColumnData::Uint16(c) => Helper::Uint16(c),
382			ColumnData::Utf8 {
383				container,
384				max_bytes,
385			} => Helper::Utf8 {
386				container,
387				max_bytes: *max_bytes,
388			},
389			ColumnData::Date(c) => Helper::Date(c),
390			ColumnData::DateTime(c) => Helper::DateTime(c),
391			ColumnData::Time(c) => Helper::Time(c),
392			ColumnData::Duration(c) => Helper::Duration(c),
393			ColumnData::IdentityId(c) => Helper::IdentityId(c),
394			ColumnData::Uuid4(c) => Helper::Uuid4(c),
395			ColumnData::Uuid7(c) => Helper::Uuid7(c),
396			ColumnData::Blob {
397				container,
398				max_bytes,
399			} => Helper::Blob {
400				container,
401				max_bytes: *max_bytes,
402			},
403			ColumnData::Int {
404				container,
405				max_bytes,
406			} => Helper::Int {
407				container,
408				max_bytes: *max_bytes,
409			},
410			ColumnData::Uint {
411				container,
412				max_bytes,
413			} => Helper::Uint {
414				container,
415				max_bytes: *max_bytes,
416			},
417			ColumnData::Decimal {
418				container,
419				precision,
420				scale,
421			} => Helper::Decimal {
422				container,
423				precision: *precision,
424				scale: *scale,
425			},
426			ColumnData::Any(c) => Helper::Any(c),
427			ColumnData::DictionaryId(c) => Helper::DictionaryId(c),
428			ColumnData::Option {
429				inner,
430				bitvec,
431			} => Helper::Option {
432				inner: inner.as_ref(),
433				bitvec,
434			},
435		};
436		helper.serialize(serializer)
437	}
438}
439
440impl<'de> Deserialize<'de> for ColumnData<Cow> {
441	fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
442		#[derive(Deserialize)]
443		enum Helper {
444			Bool(BoolContainer),
445			Float4(NumberContainer<f32>),
446			Float8(NumberContainer<f64>),
447			Int1(NumberContainer<i8>),
448			Int2(NumberContainer<i16>),
449			Int4(NumberContainer<i32>),
450			Int8(NumberContainer<i64>),
451			Int16(NumberContainer<i128>),
452			Uint1(NumberContainer<u8>),
453			Uint2(NumberContainer<u16>),
454			Uint4(NumberContainer<u32>),
455			Uint8(NumberContainer<u64>),
456			Uint16(NumberContainer<u128>),
457			Utf8 {
458				container: Utf8Container,
459				max_bytes: MaxBytes,
460			},
461			Date(TemporalContainer<Date>),
462			DateTime(TemporalContainer<DateTime>),
463			Time(TemporalContainer<Time>),
464			Duration(TemporalContainer<Duration>),
465			IdentityId(IdentityIdContainer),
466			Uuid4(UuidContainer<Uuid4>),
467			Uuid7(UuidContainer<Uuid7>),
468			Blob {
469				container: BlobContainer,
470				max_bytes: MaxBytes,
471			},
472			Int {
473				container: NumberContainer<Int>,
474				max_bytes: MaxBytes,
475			},
476			Uint {
477				container: NumberContainer<Uint>,
478				max_bytes: MaxBytes,
479			},
480			Decimal {
481				container: NumberContainer<Decimal>,
482				precision: Precision,
483				scale: Scale,
484			},
485			Any(AnyContainer),
486			DictionaryId(DictionaryContainer),
487			Option {
488				inner: Box<ColumnData>,
489				bitvec: BitVec,
490			},
491		}
492		let helper = Helper::deserialize(deserializer)?;
493		Ok(match helper {
494			Helper::Bool(c) => ColumnData::Bool(c),
495			Helper::Float4(c) => ColumnData::Float4(c),
496			Helper::Float8(c) => ColumnData::Float8(c),
497			Helper::Int1(c) => ColumnData::Int1(c),
498			Helper::Int2(c) => ColumnData::Int2(c),
499			Helper::Int4(c) => ColumnData::Int4(c),
500			Helper::Int8(c) => ColumnData::Int8(c),
501			Helper::Int16(c) => ColumnData::Int16(c),
502			Helper::Uint1(c) => ColumnData::Uint1(c),
503			Helper::Uint2(c) => ColumnData::Uint2(c),
504			Helper::Uint4(c) => ColumnData::Uint4(c),
505			Helper::Uint8(c) => ColumnData::Uint8(c),
506			Helper::Uint16(c) => ColumnData::Uint16(c),
507			Helper::Utf8 {
508				container,
509				max_bytes,
510			} => ColumnData::Utf8 {
511				container,
512				max_bytes,
513			},
514			Helper::Date(c) => ColumnData::Date(c),
515			Helper::DateTime(c) => ColumnData::DateTime(c),
516			Helper::Time(c) => ColumnData::Time(c),
517			Helper::Duration(c) => ColumnData::Duration(c),
518			Helper::IdentityId(c) => ColumnData::IdentityId(c),
519			Helper::Uuid4(c) => ColumnData::Uuid4(c),
520			Helper::Uuid7(c) => ColumnData::Uuid7(c),
521			Helper::Blob {
522				container,
523				max_bytes,
524			} => ColumnData::Blob {
525				container,
526				max_bytes,
527			},
528			Helper::Int {
529				container,
530				max_bytes,
531			} => ColumnData::Int {
532				container,
533				max_bytes,
534			},
535			Helper::Uint {
536				container,
537				max_bytes,
538			} => ColumnData::Uint {
539				container,
540				max_bytes,
541			},
542			Helper::Decimal {
543				container,
544				precision,
545				scale,
546			} => ColumnData::Decimal {
547				container,
548				precision,
549				scale,
550			},
551			Helper::Any(c) => ColumnData::Any(c),
552			Helper::DictionaryId(c) => ColumnData::DictionaryId(c),
553			Helper::Option {
554				inner,
555				bitvec,
556			} => ColumnData::Option {
557				inner,
558				bitvec,
559			},
560		})
561	}
562}
563
564/// Extracts the container from every ColumnData variant and evaluates an expression.
565macro_rules! with_container {
566	($self:expr, |$c:ident| $body:expr) => {
567		match $self {
568			ColumnData::Bool($c) => $body,
569			ColumnData::Float4($c) => $body,
570			ColumnData::Float8($c) => $body,
571			ColumnData::Int1($c) => $body,
572			ColumnData::Int2($c) => $body,
573			ColumnData::Int4($c) => $body,
574			ColumnData::Int8($c) => $body,
575			ColumnData::Int16($c) => $body,
576			ColumnData::Uint1($c) => $body,
577			ColumnData::Uint2($c) => $body,
578			ColumnData::Uint4($c) => $body,
579			ColumnData::Uint8($c) => $body,
580			ColumnData::Uint16($c) => $body,
581			ColumnData::Utf8 {
582				container: $c,
583				..
584			} => $body,
585			ColumnData::Date($c) => $body,
586			ColumnData::DateTime($c) => $body,
587			ColumnData::Time($c) => $body,
588			ColumnData::Duration($c) => $body,
589			ColumnData::IdentityId($c) => $body,
590			ColumnData::Uuid4($c) => $body,
591			ColumnData::Uuid7($c) => $body,
592			ColumnData::Blob {
593				container: $c,
594				..
595			} => $body,
596			ColumnData::Int {
597				container: $c,
598				..
599			} => $body,
600			ColumnData::Uint {
601				container: $c,
602				..
603			} => $body,
604			ColumnData::Decimal {
605				container: $c,
606				..
607			} => $body,
608			ColumnData::Any($c) => $body,
609			ColumnData::DictionaryId($c) => $body,
610			ColumnData::Option {
611				..
612			} => {
613				unreachable!(
614					"with_container! must not be called on Option variant directly; handle it explicitly"
615				)
616			}
617		}
618	};
619}
620
621pub(crate) use with_container;
622
623impl<S: Storage> ColumnData<S> {
624	/// Unwrap Option to inner data + bitvec. Non-Option returns self + None.
625	pub fn unwrap_option(&self) -> (&ColumnData<S>, Option<&S::BitVec>) {
626		match self {
627			ColumnData::Option {
628				inner,
629				bitvec,
630			} => (inner.as_ref(), Some(bitvec)),
631			other => (other, None),
632		}
633	}
634
635	/// Owned version: consume self and return inner data + optional bitvec.
636	pub fn into_unwrap_option(self) -> (ColumnData<S>, Option<S::BitVec>) {
637		match self {
638			ColumnData::Option {
639				inner,
640				bitvec,
641			} => (*inner, Some(bitvec)),
642			other => (other, None),
643		}
644	}
645
646	pub fn get_type(&self) -> Type {
647		match self {
648			ColumnData::Bool(_) => Type::Boolean,
649			ColumnData::Float4(_) => Type::Float4,
650			ColumnData::Float8(_) => Type::Float8,
651			ColumnData::Int1(_) => Type::Int1,
652			ColumnData::Int2(_) => Type::Int2,
653			ColumnData::Int4(_) => Type::Int4,
654			ColumnData::Int8(_) => Type::Int8,
655			ColumnData::Int16(_) => Type::Int16,
656			ColumnData::Uint1(_) => Type::Uint1,
657			ColumnData::Uint2(_) => Type::Uint2,
658			ColumnData::Uint4(_) => Type::Uint4,
659			ColumnData::Uint8(_) => Type::Uint8,
660			ColumnData::Uint16(_) => Type::Uint16,
661			ColumnData::Utf8 {
662				..
663			} => Type::Utf8,
664			ColumnData::Date(_) => Type::Date,
665			ColumnData::DateTime(_) => Type::DateTime,
666			ColumnData::Time(_) => Type::Time,
667			ColumnData::Duration(_) => Type::Duration,
668			ColumnData::IdentityId(_) => Type::IdentityId,
669			ColumnData::Uuid4(_) => Type::Uuid4,
670			ColumnData::Uuid7(_) => Type::Uuid7,
671			ColumnData::Blob {
672				..
673			} => Type::Blob,
674			ColumnData::Int {
675				..
676			} => Type::Int,
677			ColumnData::Uint {
678				..
679			} => Type::Uint,
680			ColumnData::Decimal {
681				..
682			} => Type::Decimal,
683			ColumnData::DictionaryId(_) => Type::DictionaryId,
684			ColumnData::Any(_) => Type::Any,
685			ColumnData::Option {
686				inner,
687				..
688			} => Type::Option(Box::new(inner.get_type())),
689		}
690	}
691
692	pub fn is_defined(&self, idx: usize) -> bool {
693		match self {
694			ColumnData::Bool(c) => c.is_defined(idx),
695			ColumnData::Float4(c) => c.is_defined(idx),
696			ColumnData::Float8(c) => c.is_defined(idx),
697			ColumnData::Int1(c) => c.is_defined(idx),
698			ColumnData::Int2(c) => c.is_defined(idx),
699			ColumnData::Int4(c) => c.is_defined(idx),
700			ColumnData::Int8(c) => c.is_defined(idx),
701			ColumnData::Int16(c) => c.is_defined(idx),
702			ColumnData::Uint1(c) => c.is_defined(idx),
703			ColumnData::Uint2(c) => c.is_defined(idx),
704			ColumnData::Uint4(c) => c.is_defined(idx),
705			ColumnData::Uint8(c) => c.is_defined(idx),
706			ColumnData::Uint16(c) => c.is_defined(idx),
707			ColumnData::Utf8 {
708				container: c,
709				..
710			} => c.is_defined(idx),
711			ColumnData::Date(c) => c.is_defined(idx),
712			ColumnData::DateTime(c) => c.is_defined(idx),
713			ColumnData::Time(c) => c.is_defined(idx),
714			ColumnData::Duration(c) => c.is_defined(idx),
715			ColumnData::IdentityId(container) => container.get(idx).is_some(),
716			ColumnData::Uuid4(c) => c.is_defined(idx),
717			ColumnData::Uuid7(c) => c.is_defined(idx),
718			ColumnData::Blob {
719				container: c,
720				..
721			} => c.is_defined(idx),
722			ColumnData::Int {
723				container: c,
724				..
725			} => c.is_defined(idx),
726			ColumnData::Uint {
727				container: c,
728				..
729			} => c.is_defined(idx),
730			ColumnData::Decimal {
731				container: c,
732				..
733			} => c.is_defined(idx),
734			ColumnData::DictionaryId(c) => c.is_defined(idx),
735			ColumnData::Any(c) => c.is_defined(idx),
736			ColumnData::Option {
737				bitvec,
738				..
739			} => idx < DataBitVec::len(bitvec) && DataBitVec::get(bitvec, idx),
740		}
741	}
742
743	pub fn is_bool(&self) -> bool {
744		self.get_type() == Type::Boolean
745	}
746
747	pub fn is_float(&self) -> bool {
748		self.get_type() == Type::Float4 || self.get_type() == Type::Float8
749	}
750
751	pub fn is_utf8(&self) -> bool {
752		self.get_type() == Type::Utf8
753	}
754
755	pub fn is_number(&self) -> bool {
756		matches!(
757			self.get_type(),
758			Type::Float4
759				| Type::Float8 | Type::Int1 | Type::Int2
760				| Type::Int4 | Type::Int8 | Type::Int16
761				| Type::Uint1 | Type::Uint2 | Type::Uint4
762				| Type::Uint8 | Type::Uint16 | Type::Int
763				| Type::Uint | Type::Decimal
764		)
765	}
766
767	pub fn is_text(&self) -> bool {
768		self.get_type() == Type::Utf8
769	}
770
771	pub fn is_temporal(&self) -> bool {
772		matches!(self.get_type(), Type::Date | Type::DateTime | Type::Time | Type::Duration)
773	}
774
775	pub fn is_uuid(&self) -> bool {
776		matches!(self.get_type(), Type::Uuid4 | Type::Uuid7)
777	}
778}
779
780impl<S: Storage> ColumnData<S> {
781	pub fn none_count(&self) -> usize {
782		match self {
783			ColumnData::Option {
784				bitvec,
785				..
786			} => DataBitVec::count_zeros(bitvec),
787			_ => 0,
788		}
789	}
790}
791
792impl<S: Storage> ColumnData<S> {
793	pub fn len(&self) -> usize {
794		match self {
795			ColumnData::Option {
796				inner,
797				..
798			} => inner.len(),
799			_ => with_container!(self, |c| c.len()),
800		}
801	}
802
803	pub fn is_empty(&self) -> bool {
804		self.len() == 0
805	}
806
807	pub fn capacity(&self) -> usize {
808		match self {
809			ColumnData::Option {
810				inner,
811				..
812			} => inner.capacity(),
813			_ => with_container!(self, |c| c.capacity()),
814		}
815	}
816
817	/// Clear all data, retaining the allocated capacity for reuse.
818	pub fn clear(&mut self) {
819		match self {
820			ColumnData::Option {
821				inner,
822				bitvec,
823			} => {
824				inner.clear();
825				DataBitVec::clear(bitvec);
826			}
827			_ => with_container!(self, |c| c.clear()),
828		}
829	}
830
831	pub fn as_string(&self, index: usize) -> String {
832		match self {
833			ColumnData::Option {
834				inner,
835				bitvec,
836			} => {
837				if index < DataBitVec::len(bitvec) && DataBitVec::get(bitvec, index) {
838					inner.as_string(index)
839				} else {
840					"none".to_string()
841				}
842			}
843			_ => with_container!(self, |c| c.as_string(index)),
844		}
845	}
846}
847
848impl ColumnData {
849	pub fn with_capacity(target: Type, capacity: usize) -> Self {
850		match target {
851			Type::Boolean => Self::bool_with_capacity(capacity),
852			Type::Float4 => Self::float4_with_capacity(capacity),
853			Type::Float8 => Self::float8_with_capacity(capacity),
854			Type::Int1 => Self::int1_with_capacity(capacity),
855			Type::Int2 => Self::int2_with_capacity(capacity),
856			Type::Int4 => Self::int4_with_capacity(capacity),
857			Type::Int8 => Self::int8_with_capacity(capacity),
858			Type::Int16 => Self::int16_with_capacity(capacity),
859			Type::Uint1 => Self::uint1_with_capacity(capacity),
860			Type::Uint2 => Self::uint2_with_capacity(capacity),
861			Type::Uint4 => Self::uint4_with_capacity(capacity),
862			Type::Uint8 => Self::uint8_with_capacity(capacity),
863			Type::Uint16 => Self::uint16_with_capacity(capacity),
864			Type::Utf8 => Self::utf8_with_capacity(capacity),
865			Type::Date => Self::date_with_capacity(capacity),
866			Type::DateTime => Self::datetime_with_capacity(capacity),
867			Type::Time => Self::time_with_capacity(capacity),
868			Type::Duration => Self::duration_with_capacity(capacity),
869			Type::IdentityId => Self::identity_id_with_capacity(capacity),
870			Type::Uuid4 => Self::uuid4_with_capacity(capacity),
871			Type::Uuid7 => Self::uuid7_with_capacity(capacity),
872			Type::Blob => Self::blob_with_capacity(capacity),
873			Type::Int => Self::int_with_capacity(capacity),
874			Type::Uint => Self::uint_with_capacity(capacity),
875			Type::Decimal => Self::decimal_with_capacity(capacity),
876			Type::DictionaryId => Self::dictionary_id_with_capacity(capacity),
877			Type::Option(inner) => ColumnData::Option {
878				inner: Box::new(ColumnData::with_capacity(*inner, capacity)),
879				bitvec: BitVec::with_capacity(capacity),
880			},
881			Type::Any | Type::List(_) | Type::Record(_) | Type::Tuple(_) => {
882				Self::any_with_capacity(capacity)
883			}
884		}
885	}
886
887	pub fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = Value> + 'a> {
888		Box::new((0..self.len()).map(move |i| self.get_value(i)))
889	}
890}