Skip to main content

reifydb_engine/arena/
convert.rs

1// SPDX-License-Identifier: AGPL-3.0-or-later
2// Copyright (c) 2025 ReifyDB
3
4use std::fmt::Debug;
5
6use bumpalo::Bump as BumpAlloc;
7use reifydb_core::value::column::{Column, data::ColumnData};
8use reifydb_type::{
9	storage::{Cow, DataBitVec, DataVec, Storage},
10	util::{bitvec::BitVec, cowvec::CowVec},
11	value::{
12		Value,
13		blob::Blob,
14		container::{
15			any::AnyContainer, blob::BlobContainer, bool::BoolContainer, dictionary::DictionaryContainer,
16			identity_id::IdentityIdContainer, number::NumberContainer, temporal::TemporalContainer,
17			utf8::Utf8Container, uuid::UuidContainer,
18		},
19		dictionary::DictionaryEntryId,
20		identity::IdentityId,
21		is::{IsNumber, IsTemporal, IsUuid},
22	},
23};
24
25use super::{Bump, BumpBitVec, BumpVec};
26
27fn bitvec_to_cow<S: Storage>(src: &S::BitVec) -> BitVec {
28	let len = DataBitVec::len(src);
29	let mut dst = BitVec::with_capacity(len);
30	for i in 0..len {
31		dst.push(DataBitVec::get(src, i));
32	}
33	dst
34}
35
36fn bitvec_to_bump<'bump, S: Storage>(src: &S::BitVec, bump: &'bump BumpAlloc) -> BumpBitVec<'bump> {
37	let len = DataBitVec::len(src);
38	let mut dst = BumpBitVec::with_capacity_in(len, bump);
39	for i in 0..len {
40		DataBitVec::push(&mut dst, DataBitVec::get(src, i));
41	}
42	dst
43}
44
45fn vec_to_cow<T: Clone + PartialEq + 'static, S: Storage>(src: &S::Vec<T>) -> CowVec<T> {
46	let mut dst = CowVec::with_capacity(DataVec::len(src));
47	dst.extend_from_slice(DataVec::as_slice(src));
48	dst
49}
50
51fn vec_to_bump<'bump, T: Clone + PartialEq + 'static, S: Storage>(
52	src: &S::Vec<T>,
53	bump: &'bump BumpAlloc,
54) -> BumpVec<'bump, T> {
55	let mut dst = BumpVec::with_capacity_in(DataVec::len(src), bump);
56	DataVec::extend_from_slice(&mut dst, DataVec::as_slice(src));
57	dst
58}
59
60fn number_to_cow<T: IsNumber + Clone + Debug + Default, S: Storage>(
61	src: &NumberContainer<T, S>,
62) -> NumberContainer<T, Cow> {
63	NumberContainer::from_parts(vec_to_cow::<T, S>(src.data()))
64}
65
66fn number_to_bump<'bump, T: IsNumber + Clone + Debug + Default, S: Storage>(
67	src: &NumberContainer<T, S>,
68	bump: &'bump BumpAlloc,
69) -> NumberContainer<T, Bump<'bump>> {
70	NumberContainer::from_parts(vec_to_bump::<T, S>(src.data(), bump))
71}
72
73fn bool_to_cow<S: Storage>(src: &BoolContainer<S>) -> BoolContainer<Cow> {
74	BoolContainer::from_parts(bitvec_to_cow::<S>(src.data()))
75}
76
77fn bool_to_bump<'bump, S: Storage>(src: &BoolContainer<S>, bump: &'bump BumpAlloc) -> BoolContainer<Bump<'bump>> {
78	BoolContainer::from_parts(bitvec_to_bump::<S>(src.data(), bump))
79}
80
81fn temporal_to_cow<T: IsTemporal + Clone + Debug + Default, S: Storage>(
82	src: &TemporalContainer<T, S>,
83) -> TemporalContainer<T, Cow> {
84	TemporalContainer::from_parts(vec_to_cow::<T, S>(src.data()))
85}
86
87fn temporal_to_bump<'bump, T: IsTemporal + Clone + Debug + Default, S: Storage>(
88	src: &TemporalContainer<T, S>,
89	bump: &'bump BumpAlloc,
90) -> TemporalContainer<T, Bump<'bump>> {
91	TemporalContainer::from_parts(vec_to_bump::<T, S>(src.data(), bump))
92}
93
94fn uuid_to_cow<T: IsUuid + Clone + Debug + Default, S: Storage>(src: &UuidContainer<T, S>) -> UuidContainer<T, Cow> {
95	UuidContainer::from_parts(vec_to_cow::<T, S>(src.data()))
96}
97
98fn uuid_to_bump<'bump, T: IsUuid + Clone + Debug + Default, S: Storage>(
99	src: &UuidContainer<T, S>,
100	bump: &'bump BumpAlloc,
101) -> UuidContainer<T, Bump<'bump>> {
102	UuidContainer::from_parts(vec_to_bump::<T, S>(src.data(), bump))
103}
104
105fn utf8_to_cow<S: Storage>(src: &Utf8Container<S>) -> Utf8Container<Cow> {
106	Utf8Container::from_parts(vec_to_cow::<String, S>(src.data()))
107}
108
109fn utf8_to_bump<'bump, S: Storage>(src: &Utf8Container<S>, bump: &'bump BumpAlloc) -> Utf8Container<Bump<'bump>> {
110	Utf8Container::from_parts(vec_to_bump::<String, S>(src.data(), bump))
111}
112
113fn blob_to_cow<S: Storage>(src: &BlobContainer<S>) -> BlobContainer<Cow> {
114	BlobContainer::from_parts(vec_to_cow::<Blob, S>(src.data()))
115}
116
117fn blob_to_bump<'bump, S: Storage>(src: &BlobContainer<S>, bump: &'bump BumpAlloc) -> BlobContainer<Bump<'bump>> {
118	BlobContainer::from_parts(vec_to_bump::<Blob, S>(src.data(), bump))
119}
120
121fn identity_id_to_cow<S: Storage>(src: &IdentityIdContainer<S>) -> IdentityIdContainer<Cow> {
122	IdentityIdContainer::from_parts(vec_to_cow::<IdentityId, S>(src.data()))
123}
124
125fn identity_id_to_bump<'bump, S: Storage>(
126	src: &IdentityIdContainer<S>,
127	bump: &'bump BumpAlloc,
128) -> IdentityIdContainer<Bump<'bump>> {
129	IdentityIdContainer::from_parts(vec_to_bump::<IdentityId, S>(src.data(), bump))
130}
131
132fn any_to_cow<S: Storage>(src: &AnyContainer<S>) -> AnyContainer<Cow> {
133	AnyContainer::from_parts(vec_to_cow::<Box<Value>, S>(src.data()))
134}
135
136fn any_to_bump<'bump, S: Storage>(src: &AnyContainer<S>, bump: &'bump BumpAlloc) -> AnyContainer<Bump<'bump>> {
137	AnyContainer::from_parts(vec_to_bump::<Box<Value>, S>(src.data(), bump))
138}
139
140fn dictionary_to_cow<S: Storage>(src: &DictionaryContainer<S>) -> DictionaryContainer<Cow> {
141	DictionaryContainer::from_parts(vec_to_cow::<DictionaryEntryId, S>(src.data()), src.dictionary_id())
142}
143
144fn dictionary_to_bump<'bump, S: Storage>(
145	src: &DictionaryContainer<S>,
146	bump: &'bump BumpAlloc,
147) -> DictionaryContainer<Bump<'bump>> {
148	DictionaryContainer::from_parts(vec_to_bump::<DictionaryEntryId, S>(src.data(), bump), src.dictionary_id())
149}
150
151pub fn column_data_to_cow<S: Storage>(src: &ColumnData<S>) -> ColumnData<Cow> {
152	match src {
153		ColumnData::Bool(c) => ColumnData::Bool(bool_to_cow(c)),
154		ColumnData::Float4(c) => ColumnData::Float4(number_to_cow(c)),
155		ColumnData::Float8(c) => ColumnData::Float8(number_to_cow(c)),
156		ColumnData::Int1(c) => ColumnData::Int1(number_to_cow(c)),
157		ColumnData::Int2(c) => ColumnData::Int2(number_to_cow(c)),
158		ColumnData::Int4(c) => ColumnData::Int4(number_to_cow(c)),
159		ColumnData::Int8(c) => ColumnData::Int8(number_to_cow(c)),
160		ColumnData::Int16(c) => ColumnData::Int16(number_to_cow(c)),
161		ColumnData::Uint1(c) => ColumnData::Uint1(number_to_cow(c)),
162		ColumnData::Uint2(c) => ColumnData::Uint2(number_to_cow(c)),
163		ColumnData::Uint4(c) => ColumnData::Uint4(number_to_cow(c)),
164		ColumnData::Uint8(c) => ColumnData::Uint8(number_to_cow(c)),
165		ColumnData::Uint16(c) => ColumnData::Uint16(number_to_cow(c)),
166		ColumnData::Utf8 {
167			container,
168			max_bytes,
169		} => ColumnData::Utf8 {
170			container: utf8_to_cow(container),
171			max_bytes: *max_bytes,
172		},
173		ColumnData::Date(c) => ColumnData::Date(temporal_to_cow(c)),
174		ColumnData::DateTime(c) => ColumnData::DateTime(temporal_to_cow(c)),
175		ColumnData::Time(c) => ColumnData::Time(temporal_to_cow(c)),
176		ColumnData::Duration(c) => ColumnData::Duration(temporal_to_cow(c)),
177		ColumnData::IdentityId(c) => ColumnData::IdentityId(identity_id_to_cow(c)),
178		ColumnData::Uuid4(c) => ColumnData::Uuid4(uuid_to_cow(c)),
179		ColumnData::Uuid7(c) => ColumnData::Uuid7(uuid_to_cow(c)),
180		ColumnData::Blob {
181			container,
182			max_bytes,
183		} => ColumnData::Blob {
184			container: blob_to_cow(container),
185			max_bytes: *max_bytes,
186		},
187		ColumnData::Int {
188			container,
189			max_bytes,
190		} => ColumnData::Int {
191			container: number_to_cow(container),
192			max_bytes: *max_bytes,
193		},
194		ColumnData::Uint {
195			container,
196			max_bytes,
197		} => ColumnData::Uint {
198			container: number_to_cow(container),
199			max_bytes: *max_bytes,
200		},
201		ColumnData::Decimal {
202			container,
203			precision,
204			scale,
205		} => ColumnData::Decimal {
206			container: number_to_cow(container),
207			precision: *precision,
208			scale: *scale,
209		},
210		ColumnData::Any(c) => ColumnData::Any(any_to_cow(c)),
211		ColumnData::DictionaryId(c) => ColumnData::DictionaryId(dictionary_to_cow(c)),
212		ColumnData::Option {
213			inner,
214			bitvec,
215		} => ColumnData::Option {
216			inner: Box::new(column_data_to_cow(inner)),
217			bitvec: bitvec_to_cow::<S>(bitvec),
218		},
219	}
220}
221
222pub fn column_data_to_bump<'bump, S: Storage>(src: &ColumnData<S>, bump: &'bump BumpAlloc) -> ColumnData<Bump<'bump>> {
223	match src {
224		ColumnData::Bool(c) => ColumnData::Bool(bool_to_bump(c, bump)),
225		ColumnData::Float4(c) => ColumnData::Float4(number_to_bump(c, bump)),
226		ColumnData::Float8(c) => ColumnData::Float8(number_to_bump(c, bump)),
227		ColumnData::Int1(c) => ColumnData::Int1(number_to_bump(c, bump)),
228		ColumnData::Int2(c) => ColumnData::Int2(number_to_bump(c, bump)),
229		ColumnData::Int4(c) => ColumnData::Int4(number_to_bump(c, bump)),
230		ColumnData::Int8(c) => ColumnData::Int8(number_to_bump(c, bump)),
231		ColumnData::Int16(c) => ColumnData::Int16(number_to_bump(c, bump)),
232		ColumnData::Uint1(c) => ColumnData::Uint1(number_to_bump(c, bump)),
233		ColumnData::Uint2(c) => ColumnData::Uint2(number_to_bump(c, bump)),
234		ColumnData::Uint4(c) => ColumnData::Uint4(number_to_bump(c, bump)),
235		ColumnData::Uint8(c) => ColumnData::Uint8(number_to_bump(c, bump)),
236		ColumnData::Uint16(c) => ColumnData::Uint16(number_to_bump(c, bump)),
237		ColumnData::Utf8 {
238			container,
239			max_bytes,
240		} => ColumnData::Utf8 {
241			container: utf8_to_bump(container, bump),
242			max_bytes: *max_bytes,
243		},
244		ColumnData::Date(c) => ColumnData::Date(temporal_to_bump(c, bump)),
245		ColumnData::DateTime(c) => ColumnData::DateTime(temporal_to_bump(c, bump)),
246		ColumnData::Time(c) => ColumnData::Time(temporal_to_bump(c, bump)),
247		ColumnData::Duration(c) => ColumnData::Duration(temporal_to_bump(c, bump)),
248		ColumnData::IdentityId(c) => ColumnData::IdentityId(identity_id_to_bump(c, bump)),
249		ColumnData::Uuid4(c) => ColumnData::Uuid4(uuid_to_bump(c, bump)),
250		ColumnData::Uuid7(c) => ColumnData::Uuid7(uuid_to_bump(c, bump)),
251		ColumnData::Blob {
252			container,
253			max_bytes,
254		} => ColumnData::Blob {
255			container: blob_to_bump(container, bump),
256			max_bytes: *max_bytes,
257		},
258		ColumnData::Int {
259			container,
260			max_bytes,
261		} => ColumnData::Int {
262			container: number_to_bump(container, bump),
263			max_bytes: *max_bytes,
264		},
265		ColumnData::Uint {
266			container,
267			max_bytes,
268		} => ColumnData::Uint {
269			container: number_to_bump(container, bump),
270			max_bytes: *max_bytes,
271		},
272		ColumnData::Decimal {
273			container,
274			precision,
275			scale,
276		} => ColumnData::Decimal {
277			container: number_to_bump(container, bump),
278			precision: *precision,
279			scale: *scale,
280		},
281		ColumnData::Any(c) => ColumnData::Any(any_to_bump(c, bump)),
282		ColumnData::DictionaryId(c) => ColumnData::DictionaryId(dictionary_to_bump(c, bump)),
283		ColumnData::Option {
284			inner,
285			bitvec,
286		} => ColumnData::Option {
287			inner: Box::new(column_data_to_bump(inner, bump)),
288			bitvec: bitvec_to_bump::<S>(bitvec, bump),
289		},
290	}
291}
292
293pub fn column_to_cow<S: Storage>(src: &Column<S>) -> Column<Cow> {
294	Column::new(src.name().clone(), column_data_to_cow(src.data()))
295}
296
297pub fn column_to_bump<'bump, S: Storage>(src: &Column<S>, bump: &'bump BumpAlloc) -> Column<Bump<'bump>> {
298	Column::new(src.name().clone(), column_data_to_bump(src.data(), bump))
299}
300
301#[cfg(test)]
302mod tests {
303	use reifydb_core::value::column::Column;
304	use reifydb_type::value::r#type::Type;
305
306	use super::*;
307
308	#[test]
309	fn test_column_data_cow_roundtrip() {
310		let original = ColumnData::int4(vec![10, 20, 30]);
311		let bump_alloc = BumpAlloc::new();
312
313		// Cow -> Bump
314		let bump_data = column_data_to_bump::<Cow>(&original, &bump_alloc);
315		assert_eq!(bump_data.len(), 3);
316
317		// Bump -> Cow
318		let cow_data = column_data_to_cow::<Bump>(&bump_data);
319		assert_eq!(cow_data, original);
320	}
321
322	#[test]
323	fn test_column_data_bool_roundtrip() {
324		let original = ColumnData::bool(vec![true, false, true]);
325		let bump_alloc = BumpAlloc::new();
326
327		let bump_data = column_data_to_bump::<Cow>(&original, &bump_alloc);
328		let cow_data = column_data_to_cow::<Bump>(&bump_data);
329		assert_eq!(cow_data, original);
330	}
331
332	#[test]
333	fn test_column_data_utf8_roundtrip() {
334		let original = ColumnData::utf8(vec![String::from("hello"), String::from("world")]);
335		let bump_alloc = BumpAlloc::new();
336
337		let bump_data = column_data_to_bump::<Cow>(&original, &bump_alloc);
338		let cow_data = column_data_to_cow::<Bump>(&bump_data);
339		assert_eq!(cow_data, original);
340	}
341
342	#[test]
343	fn test_column_data_float8_roundtrip() {
344		let original = ColumnData::float8(vec![1.5, 2.7, 3.9]);
345		let bump_alloc = BumpAlloc::new();
346
347		let bump_data = column_data_to_bump::<Cow>(&original, &bump_alloc);
348		let cow_data = column_data_to_cow::<Bump>(&bump_data);
349		assert_eq!(cow_data, original);
350	}
351
352	#[test]
353	fn test_column_data_none_roundtrip() {
354		let original = ColumnData::none_typed(Type::Boolean, 5);
355		let bump_alloc = BumpAlloc::new();
356
357		let bump_data = column_data_to_bump::<Cow>(&original, &bump_alloc);
358		let cow_data = column_data_to_cow::<Bump>(&bump_data);
359		assert_eq!(cow_data, original);
360	}
361
362	#[test]
363	fn test_column_roundtrip() {
364		let original = Column::int4("age", vec![25, 30, 35]);
365		let bump_alloc = BumpAlloc::new();
366
367		let bump_col = column_to_bump::<Cow>(&original, &bump_alloc);
368		let cow_col = column_to_cow::<Bump>(&bump_col);
369		assert_eq!(cow_col, original);
370	}
371}