Skip to main content

reifydb_codec/frame/encoding/
plain.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 ReifyDB
3
4use std::iter;
5
6use reifydb_value::{
7	util::bitvec::BitVec,
8	value::{
9		Value,
10		container::{blob::BlobContainer, dictionary::DictionaryContainer, utf8::Utf8Container},
11		date::Date,
12		datetime::DateTime,
13		decimal::Decimal,
14		dictionary::DictionaryEntryId,
15		duration::Duration,
16		frame::data::FrameColumnData,
17		identity::IdentityId,
18		int::Int,
19		time::Time,
20		uint::Uint,
21		uuid::{Uuid4, Uuid7},
22		value_type::ValueType,
23	},
24};
25
26use crate::{error::EncodeError, frame::encode::any::encode_any_value, tag::ValueKind};
27
28macro_rules! encode_fixed {
29	($container:expr, $ty:expr, $elem_size:expr) => {{
30		let slice = &**$container;
31		let mut buf = Vec::with_capacity(slice.len() * $elem_size);
32		for v in slice {
33			buf.extend_from_slice(&v.to_le_bytes());
34		}
35		PlainEncoded {
36			data: buf,
37			offsets: vec![],
38			nones: vec![],
39			type_code: ValueKind::of_type(&$ty).byte(),
40			has_nones: false,
41		}
42	}};
43}
44
45pub struct PlainEncoded {
46	pub data: Vec<u8>,
47
48	pub offsets: Vec<u8>,
49
50	pub nones: Vec<u8>,
51
52	pub type_code: u8,
53
54	pub has_nones: bool,
55}
56
57pub fn encode_plain(col: &FrameColumnData) -> Result<PlainEncoded, EncodeError> {
58	match col {
59		FrameColumnData::Option {
60			inner,
61			bitvec,
62		} => {
63			let mut result = encode_plain_inner(inner)?;
64			result.nones = encode_bitvec(bitvec);
65			result.has_nones = true;
66			Ok(result)
67		}
68		other => encode_plain_inner(other),
69	}
70}
71
72fn encode_plain_inner(col: &FrameColumnData) -> Result<PlainEncoded, EncodeError> {
73	let result = match col {
74		FrameColumnData::Bool(c) => {
75			let bv: &BitVec = c;
76			PlainEncoded {
77				data: encode_bitvec(bv),
78				offsets: vec![],
79				nones: vec![],
80				type_code: ValueKind::Boolean.byte(),
81				has_nones: false,
82			}
83		}
84		FrameColumnData::Float4(c) => encode_fixed!(c, ValueType::Float4, 4),
85		FrameColumnData::Float8(c) => encode_fixed!(c, ValueType::Float8, 8),
86		FrameColumnData::Int1(c) => encode_fixed!(c, ValueType::Int1, 1),
87		FrameColumnData::Int2(c) => encode_fixed!(c, ValueType::Int2, 2),
88		FrameColumnData::Int4(c) => encode_fixed!(c, ValueType::Int4, 4),
89		FrameColumnData::Int8(c) => encode_fixed!(c, ValueType::Int8, 8),
90		FrameColumnData::Int16(c) => encode_fixed!(c, ValueType::Int16, 16),
91		FrameColumnData::Uint1(c) => encode_fixed!(c, ValueType::Uint1, 1),
92		FrameColumnData::Uint2(c) => encode_fixed!(c, ValueType::Uint2, 2),
93		FrameColumnData::Uint4(c) => encode_fixed!(c, ValueType::Uint4, 4),
94		FrameColumnData::Uint8(c) => encode_fixed!(c, ValueType::Uint8, 8),
95		FrameColumnData::Uint16(c) => encode_fixed!(c, ValueType::Uint16, 16),
96		FrameColumnData::Date(c) => {
97			let slice: &[Date] = c;
98			let mut buf = Vec::with_capacity(slice.len() * 4);
99			for v in slice {
100				buf.extend_from_slice(&v.to_days_since_epoch().to_le_bytes());
101			}
102			PlainEncoded {
103				data: buf,
104				offsets: vec![],
105				nones: vec![],
106				type_code: ValueKind::Date.byte(),
107				has_nones: false,
108			}
109		}
110		FrameColumnData::DateTime(c) => {
111			let slice: &[DateTime] = c;
112			let mut buf = Vec::with_capacity(slice.len() * 8);
113			for v in slice {
114				buf.extend_from_slice(&v.to_nanos().to_le_bytes());
115			}
116			PlainEncoded {
117				data: buf,
118				offsets: vec![],
119				nones: vec![],
120				type_code: ValueKind::DateTime.byte(),
121				has_nones: false,
122			}
123		}
124		FrameColumnData::Time(c) => {
125			let slice: &[Time] = c;
126			let mut buf = Vec::with_capacity(slice.len() * 8);
127			for v in slice {
128				buf.extend_from_slice(&v.to_nanos_since_midnight().to_le_bytes());
129			}
130			PlainEncoded {
131				data: buf,
132				offsets: vec![],
133				nones: vec![],
134				type_code: ValueKind::Time.byte(),
135				has_nones: false,
136			}
137		}
138		FrameColumnData::Duration(c) => {
139			let slice: &[Duration] = c;
140			let mut buf = Vec::with_capacity(slice.len() * 16);
141			for v in slice {
142				buf.extend_from_slice(&v.get_months().to_le_bytes());
143				buf.extend_from_slice(&v.get_days().to_le_bytes());
144				buf.extend_from_slice(&v.get_nanos().to_le_bytes());
145			}
146			PlainEncoded {
147				data: buf,
148				offsets: vec![],
149				nones: vec![],
150				type_code: ValueKind::Duration.byte(),
151				has_nones: false,
152			}
153		}
154		FrameColumnData::IdentityId(c) => {
155			let slice: &[IdentityId] = c;
156			let mut buf = Vec::with_capacity(slice.len() * 16);
157			for v in slice {
158				buf.extend_from_slice(v.0.0.as_bytes());
159			}
160			PlainEncoded {
161				data: buf,
162				offsets: vec![],
163				nones: vec![],
164				type_code: ValueKind::IdentityId.byte(),
165				has_nones: false,
166			}
167		}
168		FrameColumnData::Uuid4(c) => {
169			let slice: &[Uuid4] = c;
170			let mut buf = Vec::with_capacity(slice.len() * 16);
171			for v in slice {
172				buf.extend_from_slice(v.0.as_bytes());
173			}
174			PlainEncoded {
175				data: buf,
176				offsets: vec![],
177				nones: vec![],
178				type_code: ValueKind::Uuid4.byte(),
179				has_nones: false,
180			}
181		}
182		FrameColumnData::Uuid7(c) => {
183			let slice: &[Uuid7] = c;
184			let mut buf = Vec::with_capacity(slice.len() * 16);
185			for v in slice {
186				buf.extend_from_slice(v.0.as_bytes());
187			}
188			PlainEncoded {
189				data: buf,
190				offsets: vec![],
191				nones: vec![],
192				type_code: ValueKind::Uuid7.byte(),
193				has_nones: false,
194			}
195		}
196		FrameColumnData::Utf8(c) => encode_varlen_strings(c, ValueType::Utf8),
197		FrameColumnData::Blob(c) => encode_varlen_blobs(c, ValueType::Blob),
198		FrameColumnData::Int(c) => {
199			let slice: &[Int] = c;
200			encode_varlen(slice.len(), |i| slice[i].0.to_signed_bytes_le(), ValueType::Int)
201		}
202		FrameColumnData::Uint(c) => {
203			let slice: &[Uint] = c;
204			encode_varlen(slice.len(), |i| slice[i].0.to_signed_bytes_le(), ValueType::Uint)
205		}
206		FrameColumnData::Decimal(c) => {
207			let slice: &[Decimal] = c;
208			encode_varlen(slice.len(), |i| slice[i].to_string().into_bytes(), ValueType::Decimal)
209		}
210		FrameColumnData::Any(c) => {
211			let mut data = Vec::new();
212			let none = Value::none();
213			for i in 0..c.len() {
214				let val = c.get(i).unwrap_or(&none);
215				encode_any_value(val, &mut data)?;
216			}
217			return Ok(PlainEncoded {
218				data,
219				offsets: vec![],
220				nones: vec![],
221				type_code: ValueKind::Any.byte(),
222				has_nones: false,
223			});
224		}
225		FrameColumnData::DictionaryId(c) => encode_dictionary_ids(c),
226		FrameColumnData::Option {
227			..
228		} => unreachable!("Option handled in encode_plain"),
229	};
230	Ok(result)
231}
232
233fn encode_varlen(count: usize, get_bytes: impl Fn(usize) -> Vec<u8>, ty: ValueType) -> PlainEncoded {
234	let mut offsets = Vec::with_capacity((count + 1) * 4);
235	let mut data = Vec::new();
236	let mut offset: u32 = 0;
237	offsets.extend_from_slice(&offset.to_le_bytes());
238	for i in 0..count {
239		let bytes = get_bytes(i);
240		data.extend_from_slice(&bytes);
241		offset += bytes.len() as u32;
242		offsets.extend_from_slice(&offset.to_le_bytes());
243	}
244	PlainEncoded {
245		data,
246		offsets,
247		nones: vec![],
248		type_code: ValueKind::of_type(&ty).byte(),
249		has_nones: false,
250	}
251}
252
253fn encode_varlen_strings(c: &Utf8Container, ty: ValueType) -> PlainEncoded {
254	encode_varlen(c.len(), |i| c.get(i).unwrap().as_bytes().to_vec(), ty)
255}
256
257fn encode_varlen_blobs(c: &BlobContainer, ty: ValueType) -> PlainEncoded {
258	encode_varlen(c.len(), |i| c.get(i).unwrap_or(&[]).to_vec(), ty)
259}
260
261fn encode_dictionary_ids(c: &DictionaryContainer) -> PlainEncoded {
262	let mut buf = Vec::new();
263	if !c.is_empty() {
264		let mut disc = 1u8;
265		for i in 0..c.len() {
266			if let Some(id) = c.get(i) {
267				let d = match id {
268					DictionaryEntryId::U1(_) => 1u8,
269					DictionaryEntryId::U2(_) => 2u8,
270					DictionaryEntryId::U4(_) => 4u8,
271					DictionaryEntryId::U8(_) => 8u8,
272					DictionaryEntryId::U16(_) => 16u8,
273				};
274				if d > disc {
275					disc = d;
276				}
277			}
278		}
279
280		buf.push(disc);
281		for i in 0..c.len() {
282			if let Some(id) = c.get(i) {
283				match disc {
284					1 => buf.push(id.to_u128() as u8),
285					2 => buf.extend_from_slice(&(id.to_u128() as u16).to_le_bytes()),
286					4 => buf.extend_from_slice(&(id.to_u128() as u32).to_le_bytes()),
287					8 => buf.extend_from_slice(&(id.to_u128() as u64).to_le_bytes()),
288					16 => buf.extend_from_slice(&id.to_u128().to_le_bytes()),
289					_ => unreachable!(),
290				}
291			} else {
292				buf.extend(iter::repeat_n(0, disc as usize));
293			}
294		}
295	}
296	PlainEncoded {
297		data: buf,
298		offsets: vec![],
299		nones: vec![],
300		type_code: ValueKind::DictionaryId.byte(),
301		has_nones: false,
302	}
303}
304
305pub fn encode_bitvec(bv: &BitVec) -> Vec<u8> {
306	let len = bv.len();
307	let byte_count = len.div_ceil(8);
308	let mut buf = Vec::with_capacity(byte_count);
309	for i in 0..byte_count {
310		let mut byte = 0u8;
311		for bit in 0..8 {
312			let idx = i * 8 + bit;
313			if idx < len && bv.get(idx) {
314				byte |= 1 << bit;
315			}
316		}
317		buf.push(byte);
318	}
319	buf
320}