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