Skip to main content

reifydb_core/value/column/data/
canonical.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 ReifyDB
3
4use std::{any::Any, sync::Arc};
5
6use reifydb_value::{
7	Result, reifydb_assertions,
8	value::{Value, value_type::ValueType},
9};
10
11use crate::value::column::{
12	buffer::ColumnBuffer,
13	data::{Column, ColumnData},
14	encoding::EncodingId,
15	nones::NoneBitmap,
16	stats::StatsSet,
17};
18
19#[derive(Clone, Debug)]
20pub struct Canonical {
21	pub ty: ValueType,
22	pub nullable: bool,
23	pub nones: Option<NoneBitmap>,
24	pub buffer: ColumnBuffer,
25	stats: StatsSet,
26}
27
28impl Canonical {
29	pub fn new(ty: ValueType, nullable: bool, nones: Option<NoneBitmap>, buffer: ColumnBuffer) -> Self {
30		reifydb_assertions! {
31			assert!(
32				!matches!(buffer, ColumnBuffer::Option { .. }),
33				"Canonical.buffer must not be a ColumnBuffer::Option; nullability is lifted"
34			);
35		}
36		Self {
37			ty,
38			nullable,
39			nones,
40			buffer,
41			stats: StatsSet::new(),
42		}
43	}
44
45	pub fn from_buffer(b: ColumnBuffer) -> Self {
46		match b {
47			ColumnBuffer::Option {
48				inner,
49				bitvec,
50			} => {
51				let mut inner_c = Self::from_buffer(*inner);
52				inner_c.nullable = true;
53				inner_c.nones = Some(NoneBitmap::from_defined_bitvec(&bitvec));
54				inner_c
55			}
56			other => {
57				let ty = other.get_type();
58				Self {
59					ty,
60					nullable: false,
61					nones: None,
62					buffer: other,
63					stats: StatsSet::new(),
64				}
65			}
66		}
67	}
68
69	pub fn from_column_buffer(cd: &ColumnBuffer) -> Result<Self> {
70		Ok(Self::from_buffer(cd.clone()))
71	}
72
73	pub fn into_buffer(self) -> ColumnBuffer {
74		match self.nones {
75			None => self.buffer,
76			Some(nones) => ColumnBuffer::Option {
77				inner: Box::new(self.buffer),
78				bitvec: nones.to_defined_bitvec(),
79			},
80		}
81	}
82
83	pub fn to_buffer(&self) -> ColumnBuffer {
84		match &self.nones {
85			None => self.buffer.clone(),
86			Some(nones) => ColumnBuffer::Option {
87				inner: Box::new(self.buffer.clone()),
88				bitvec: nones.to_defined_bitvec(),
89			},
90		}
91	}
92
93	pub fn to_column_buffer(&self) -> Result<ColumnBuffer> {
94		Ok(self.to_buffer())
95	}
96
97	pub fn len(&self) -> usize {
98		self.buffer.len()
99	}
100
101	pub fn is_empty(&self) -> bool {
102		self.len() == 0
103	}
104
105	pub fn stats(&self) -> &StatsSet {
106		&self.stats
107	}
108}
109
110fn encoding_for_type(ty: &ValueType) -> EncodingId {
111	match ty {
112		ValueType::Boolean => EncodingId::CANONICAL_BOOL,
113		ValueType::Utf8 | ValueType::Blob => EncodingId::CANONICAL_VARLEN,
114		ValueType::Int | ValueType::Uint | ValueType::Decimal => EncodingId::CANONICAL_BIGNUM,
115		_ => EncodingId::CANONICAL_FIXED,
116	}
117}
118
119static UNIT_METADATA: () = ();
120static EMPTY_CHILDREN: Vec<Column> = Vec::new();
121
122impl ColumnData for Canonical {
123	fn ty(&self) -> ValueType {
124		self.ty.clone()
125	}
126
127	fn is_nullable(&self) -> bool {
128		self.nullable
129	}
130
131	fn len(&self) -> usize {
132		self.buffer.len()
133	}
134
135	fn encoding(&self) -> EncodingId {
136		encoding_for_type(&self.ty)
137	}
138
139	fn stats(&self) -> &StatsSet {
140		&self.stats
141	}
142
143	fn nones(&self) -> Option<&NoneBitmap> {
144		self.nones.as_ref()
145	}
146
147	fn get_value(&self, idx: usize) -> Value {
148		if self.nones.as_ref().map(|n| n.is_none(idx)).unwrap_or(false) {
149			Value::none_of(self.ty.clone())
150		} else {
151			self.buffer.get_value(idx)
152		}
153	}
154
155	fn as_string(&self, idx: usize) -> String {
156		self.buffer.as_string(idx)
157	}
158
159	fn as_any(&self) -> &dyn Any {
160		self
161	}
162
163	fn as_any_mut(&mut self) -> &mut dyn Any {
164		self
165	}
166
167	fn children(&self) -> &[Column] {
168		&EMPTY_CHILDREN
169	}
170
171	fn metadata(&self) -> &dyn Any {
172		&UNIT_METADATA
173	}
174
175	fn to_canonical(&self) -> Result<Arc<Canonical>> {
176		Ok(Arc::new(self.clone()))
177	}
178}