Skip to main content

reifydb_core/value/column/data/
mod.rs

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