Skip to main content

reifydb_codec/row/shape/
columns.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 ReifyDB
3
4use reifydb_value::{
5	Result,
6	error::{Diagnostic, Error},
7	value::{
8		column_view::{ColumnView, ViewData},
9		container::{
10			decimal_array::decimal_at,
11			dictionary_array, digest_array,
12			temporal_array::{dates, datetimes, durations, times},
13			uuid_array::{identity_ids, uuid4s, uuid7s},
14			wide_int_array::wide_at,
15		},
16		date::Date,
17		datetime::DateTime,
18		duration::Duration,
19		identity::IdentityId,
20		time::Time,
21		uuid::{Uuid4, Uuid7},
22		value_type::ValueType,
23	},
24};
25
26use super::RowShape;
27use crate::row::bytes::RowBuilder;
28
29impl RowShape {
30	pub fn write_columns<B: RowBuilder>(&self, rows: &mut [B], columns: &[ColumnView]) -> Result<()> {
31		if columns.len() != self.fields().len() || columns.iter().any(|column| column.len() != rows.len()) {
32			return Err(Error(Box::new(Diagnostic {
33				code: "INTERNAL_ERROR".to_string(),
34				message: format!(
35					"cannot write columns of lengths {:?} into {} rows of a shape with {} fields",
36					columns.iter().map(ColumnView::len).collect::<Vec<_>>(),
37					rows.len(),
38					self.fields().len()
39				),
40				..Diagnostic::default()
41			})));
42		}
43		for (index, (field, view)) in self.fields().iter().zip(columns).enumerate() {
44			let field_type = match field.constraint.get_type() {
45				ValueType::Option(inner) => *inner,
46				other => other,
47			};
48			match (field_type, &view.data) {
49				(ValueType::Boolean, ViewData::Bool(a)) => typed(self, rows, index, view, |row, i| {
50					self.set::<bool>(row, index, a.value(i))
51				}),
52				(ValueType::Float4, ViewData::Float4(a)) => typed(self, rows, index, view, |row, i| {
53					let value = a.value(i);
54					if value.is_nan() {
55						self.set_none(row, index);
56					} else {
57						self.set::<f32>(
58							row,
59							index,
60							if value == 0.0 {
61								0.0
62							} else {
63								value
64							},
65						);
66					}
67				}),
68				(ValueType::Float8, ViewData::Float8(a)) => typed(self, rows, index, view, |row, i| {
69					let value = a.value(i);
70					if value.is_nan() {
71						self.set_none(row, index);
72					} else {
73						self.set::<f64>(
74							row,
75							index,
76							if value == 0.0 {
77								0.0
78							} else {
79								value
80							},
81						);
82					}
83				}),
84				(ValueType::Int1, ViewData::Int1(a)) => {
85					typed(self, rows, index, view, |row, i| self.set::<i8>(row, index, a.value(i)))
86				}
87				(ValueType::Int2, ViewData::Int2(a)) => {
88					typed(self, rows, index, view, |row, i| self.set::<i16>(row, index, a.value(i)))
89				}
90				(ValueType::Int4, ViewData::Int4(a)) => {
91					typed(self, rows, index, view, |row, i| self.set::<i32>(row, index, a.value(i)))
92				}
93				(ValueType::Int8, ViewData::Int8(a)) => {
94					typed(self, rows, index, view, |row, i| self.set::<i64>(row, index, a.value(i)))
95				}
96				(ValueType::Int16, ViewData::Int16(a)) => {
97					typed(self, rows, index, view, |row, i| match wide_at::<i128>(a, i) {
98						Some(value) => self.set::<i128>(row, index, value),
99						None => self.set_none(row, index),
100					})
101				}
102				(ValueType::Uint1, ViewData::Uint1(a)) => {
103					typed(self, rows, index, view, |row, i| self.set::<u8>(row, index, a.value(i)))
104				}
105				(ValueType::Uint2, ViewData::Uint2(a)) => {
106					typed(self, rows, index, view, |row, i| self.set::<u16>(row, index, a.value(i)))
107				}
108				(ValueType::Uint4, ViewData::Uint4(a)) => {
109					typed(self, rows, index, view, |row, i| self.set::<u32>(row, index, a.value(i)))
110				}
111				(ValueType::Uint8, ViewData::Uint8(a)) => {
112					typed(self, rows, index, view, |row, i| self.set::<u64>(row, index, a.value(i)))
113				}
114				(ValueType::Uint16, ViewData::Uint16(a)) => {
115					typed(self, rows, index, view, |row, i| match wide_at::<u128>(a, i) {
116						Some(value) => self.set::<u128>(row, index, value),
117						None => self.set_none(row, index),
118					})
119				}
120				(
121					ValueType::Utf8,
122					ViewData::Utf8 {
123						container,
124						..
125					},
126				) => typed(self, rows, index, view, |row, i| {
127					self.set_utf8(row, index, container.value(i))
128				}),
129				(
130					ValueType::Blob,
131					ViewData::Blob {
132						container,
133						..
134					},
135				) => typed(self, rows, index, view, |row, i| {
136					self.set_blob_from_slice(row, index, container.value(i))
137				}),
138				(ValueType::Date, ViewData::Date(a)) => {
139					let values = dates(a);
140					typed(self, rows, index, view, |row, i| self.set::<Date>(row, index, values[i]))
141				}
142				(ValueType::DateTime, ViewData::DateTime(a)) => {
143					let values = datetimes(a);
144					typed(self, rows, index, view, |row, i| {
145						self.set::<DateTime>(row, index, values[i])
146					})
147				}
148				(ValueType::Time, ViewData::Time(a)) => {
149					let values = times(a);
150					typed(self, rows, index, view, |row, i| self.set::<Time>(row, index, values[i]))
151				}
152				(ValueType::Duration, ViewData::Duration(a)) => {
153					let values = durations(a);
154					typed(self, rows, index, view, |row, i| {
155						self.set::<Duration>(row, index, values[i])
156					})
157				}
158				(ValueType::IdentityId, ViewData::IdentityId(a)) => {
159					let values = identity_ids(a);
160					typed(self, rows, index, view, |row, i| {
161						self.set::<IdentityId>(row, index, values[i])
162					})
163				}
164				(ValueType::Uuid4, ViewData::Uuid4(a)) => {
165					let values = uuid4s(a);
166					typed(self, rows, index, view, |row, i| {
167						self.set::<Uuid4>(row, index, values[i])
168					})
169				}
170				(ValueType::Uuid7, ViewData::Uuid7(a)) => {
171					let values = uuid7s(a);
172					typed(self, rows, index, view, |row, i| {
173						self.set::<Uuid7>(row, index, values[i])
174					})
175				}
176				(
177					ValueType::Decimal {
178						..
179					},
180					ViewData::Decimal(d),
181				) => typed(self, rows, index, view, |row, i| match decimal_at(d, i) {
182					Some(value) => self.set_decimal(row, index, &value),
183					None => self.set_none(row, index),
184				}),
185				(
186					ValueType::DictionaryId,
187					ViewData::DictionaryId {
188						container,
189						..
190					},
191				) => typed(self, rows, index, view, |row, i| {
192					match dictionary_array::get(container, i) {
193						Some(id) => self.set_dictionary_id(row, index, &id),
194						None => self.set_none(row, index),
195					}
196				}),
197				(
198					ValueType::Digest {
199						..
200					},
201					ViewData::Digest {
202						container,
203						..
204					},
205				) => typed(self, rows, index, view, |row, i| match digest_array::get(container, i) {
206					Some(digest) => self.set_digest(row, index, &digest),
207					None => self.set_none(row, index),
208				}),
209				_ => {
210					for (i, row) in rows.iter_mut().enumerate() {
211						self.set_value(row, index, &view.get_value(i));
212					}
213				}
214			}
215		}
216		Ok(())
217	}
218}
219
220fn typed<B: RowBuilder>(
221	shape: &RowShape,
222	rows: &mut [B],
223	index: usize,
224	view: &ColumnView,
225	mut write: impl FnMut(&mut B, usize),
226) {
227	for (i, row) in rows.iter_mut().enumerate() {
228		if view.none_at(i) {
229			shape.set_none(row, index);
230			continue;
231		}
232		write(row, i);
233	}
234}