Skip to main content

reifydb_codec/value/
mod.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 ReifyDB
3
4use std::{collections::HashMap, str::from_utf8};
5
6use bigdecimal::BigDecimal;
7use num_bigint::BigInt;
8use reifydb_value::{
9	encoding::LeBytes,
10	params::Params,
11	value::{
12		Value,
13		blob::Blob,
14		date::Date,
15		datetime::DateTime,
16		decimal::Decimal,
17		dictionary::DictionaryEntryId,
18		duration::Duration,
19		identity::IdentityId,
20		int::Int,
21		ordered_f32::OrderedF32,
22		ordered_f64::OrderedF64,
23		time::Time,
24		uint::Uint,
25		uuid::{Uuid4, Uuid7},
26	},
27};
28
29use crate::{
30	error::{DecodeError, EncodeError},
31	reader::Reader,
32	tag::ValueKind,
33	typeinfo::{decode_value_type, encode_value_type},
34};
35
36pub fn encode_value(value: &Value) -> Result<Vec<u8>, EncodeError> {
37	let mut buf = Vec::new();
38	encode_value_into(value, &mut buf)?;
39	Ok(buf)
40}
41
42pub fn encode_value_into(value: &Value, buf: &mut Vec<u8>) -> Result<(), EncodeError> {
43	buf.push(ValueKind::of_value(value).byte());
44	match value {
45		Value::None {
46			inner,
47		} => encode_value_type(inner, buf)?,
48		Value::Boolean(b) => buf.push(*b as u8),
49		Value::Float4(f) => buf.extend_from_slice(&f.to_le_bytes()),
50		Value::Float8(f) => buf.extend_from_slice(&f.to_le_bytes()),
51		Value::Int1(v) => buf.extend_from_slice(&v.to_le_bytes()),
52		Value::Int2(v) => buf.extend_from_slice(&v.to_le_bytes()),
53		Value::Int4(v) => buf.extend_from_slice(&v.to_le_bytes()),
54		Value::Int8(v) => buf.extend_from_slice(&v.to_le_bytes()),
55		Value::Int16(v) => buf.extend_from_slice(&v.to_le_bytes()),
56		Value::Utf8(s) => encode_len_prefixed(s.as_bytes(), buf),
57		Value::Uint1(v) => buf.extend_from_slice(&v.to_le_bytes()),
58		Value::Uint2(v) => buf.extend_from_slice(&v.to_le_bytes()),
59		Value::Uint4(v) => buf.extend_from_slice(&v.to_le_bytes()),
60		Value::Uint8(v) => buf.extend_from_slice(&v.to_le_bytes()),
61		Value::Uint16(v) => buf.extend_from_slice(&v.to_le_bytes()),
62		Value::Date(d) => buf.extend_from_slice(d.to_le_bytes().as_ref()),
63		Value::DateTime(dt) => buf.extend_from_slice(dt.to_le_bytes().as_ref()),
64		Value::Time(t) => buf.extend_from_slice(t.to_le_bytes().as_ref()),
65		Value::Duration(d) => buf.extend_from_slice(d.to_le_bytes().as_ref()),
66		Value::IdentityId(id) => buf.extend_from_slice(id.to_le_bytes().as_ref()),
67		Value::Uuid4(u) => buf.extend_from_slice(u.to_le_bytes().as_ref()),
68		Value::Uuid7(u) => buf.extend_from_slice(u.to_le_bytes().as_ref()),
69		Value::Blob(b) => encode_len_prefixed(b.as_bytes(), buf),
70		Value::Int(v) => encode_len_prefixed(&v.0.to_signed_bytes_le(), buf),
71		Value::Uint(v) => encode_len_prefixed(&v.0.to_signed_bytes_le(), buf),
72		Value::Decimal(v) => encode_len_prefixed(v.to_string().as_bytes(), buf),
73		Value::Any(inner) => encode_value_into(inner, buf)?,
74		Value::DictionaryId(id) => match id {
75			DictionaryEntryId::U1(v) => {
76				buf.push(1);
77				buf.extend_from_slice(&v.to_le_bytes());
78			}
79			DictionaryEntryId::U2(v) => {
80				buf.push(2);
81				buf.extend_from_slice(&v.to_le_bytes());
82			}
83			DictionaryEntryId::U4(v) => {
84				buf.push(4);
85				buf.extend_from_slice(&v.to_le_bytes());
86			}
87			DictionaryEntryId::U8(v) => {
88				buf.push(8);
89				buf.extend_from_slice(&v.to_le_bytes());
90			}
91			DictionaryEntryId::U16(v) => {
92				buf.push(16);
93				buf.extend_from_slice(&v.to_le_bytes());
94			}
95		},
96		Value::Type(ty) => encode_value_type(ty, buf)?,
97		Value::List(items) | Value::Tuple(items) => {
98			buf.extend_from_slice(&(items.len() as u32).to_le_bytes());
99			for item in items {
100				encode_value_into(item, buf)?;
101			}
102		}
103		Value::Record(fields) => {
104			buf.extend_from_slice(&(fields.len() as u32).to_le_bytes());
105			for (key, field_value) in fields {
106				encode_len_prefixed(key.as_bytes(), buf);
107				encode_value_into(field_value, buf)?;
108			}
109		}
110	}
111	Ok(())
112}
113
114fn encode_len_prefixed(bytes: &[u8], buf: &mut Vec<u8>) {
115	buf.extend_from_slice(&(bytes.len() as u32).to_le_bytes());
116	buf.extend_from_slice(bytes);
117}
118
119pub fn decode_value(bytes: &[u8]) -> Result<Value, DecodeError> {
120	let mut r = Reader::new(bytes);
121	let value = decode_value_from(&mut r)?;
122	if !r.is_empty() {
123		return Err(DecodeError::TrailingBytes(r.remaining()));
124	}
125	Ok(value)
126}
127
128pub fn decode_value_from(r: &mut Reader) -> Result<Value, DecodeError> {
129	let byte = r.u8()?;
130	let kind = ValueKind::from_byte(byte).ok_or(DecodeError::UnknownTypeCode(byte))?;
131	match kind {
132		ValueKind::None => Ok(Value::None {
133			inner: decode_value_type(r)?,
134		}),
135		ValueKind::Boolean => Ok(Value::Boolean(r.u8()? != 0)),
136		ValueKind::Float4 => OrderedF32::try_from(r.f32()?)
137			.map(Value::Float4)
138			.map_err(|e| DecodeError::InvalidData(format!("invalid float4: {e}"))),
139		ValueKind::Float8 => OrderedF64::try_from(r.f64()?)
140			.map(Value::Float8)
141			.map_err(|e| DecodeError::InvalidData(format!("invalid float8: {e}"))),
142		ValueKind::Int1 => Ok(Value::Int1(r.i8()?)),
143		ValueKind::Int2 => Ok(Value::Int2(r.i16()?)),
144		ValueKind::Int4 => Ok(Value::Int4(r.i32()?)),
145		ValueKind::Int8 => Ok(Value::Int8(r.i64()?)),
146		ValueKind::Int16 => Ok(Value::Int16(r.i128()?)),
147		ValueKind::Utf8 => Ok(Value::Utf8(decode_len_prefixed_str(r)?.to_string())),
148		ValueKind::Uint1 => Ok(Value::Uint1(r.u8()?)),
149		ValueKind::Uint2 => Ok(Value::Uint2(r.u16()?)),
150		ValueKind::Uint4 => Ok(Value::Uint4(r.u32()?)),
151		ValueKind::Uint8 => Ok(Value::Uint8(r.u64()?)),
152		ValueKind::Uint16 => Ok(Value::Uint16(r.u128()?)),
153		ValueKind::Date => {
154			let days = r.i32()?;
155			Date::from_days_since_epoch(days)
156				.map(Value::Date)
157				.ok_or_else(|| DecodeError::InvalidData(format!("invalid date: {days}")))
158		}
159		ValueKind::DateTime => Ok(Value::DateTime(DateTime::read_le(r.take(DateTime::ENCODED_SIZE)?))),
160		ValueKind::Time => {
161			let nanos = r.u64()?;
162			Time::from_nanos_since_midnight(nanos)
163				.map(Value::Time)
164				.ok_or_else(|| DecodeError::InvalidData(format!("invalid time: {nanos}")))
165		}
166		ValueKind::Duration => {
167			let months = r.i32()?;
168			let days = r.i32()?;
169			let nanos = r.i64()?;
170			Duration::new(months, days, nanos)
171				.map(Value::Duration)
172				.map_err(|e| DecodeError::InvalidData(format!("invalid duration: {e}")))
173		}
174		ValueKind::IdentityId => Ok(Value::IdentityId(IdentityId::read_le(r.take(IdentityId::ENCODED_SIZE)?))),
175		ValueKind::Uuid4 => Ok(Value::Uuid4(Uuid4::read_le(r.take(Uuid4::ENCODED_SIZE)?))),
176		ValueKind::Uuid7 => Ok(Value::Uuid7(Uuid7::read_le(r.take(Uuid7::ENCODED_SIZE)?))),
177		ValueKind::Blob => Ok(Value::Blob(Blob::new(decode_len_prefixed_bytes(r)?.to_vec()))),
178		ValueKind::Int => Ok(Value::Int(Int(BigInt::from_signed_bytes_le(decode_len_prefixed_bytes(r)?)))),
179		ValueKind::Uint => Ok(Value::Uint(Uint(BigInt::from_signed_bytes_le(decode_len_prefixed_bytes(r)?)))),
180		ValueKind::Decimal => {
181			let s = decode_len_prefixed_str(r)?;
182			let dec: BigDecimal =
183				s.parse().map_err(|e| DecodeError::InvalidData(format!("invalid decimal: {e}")))?;
184			Ok(Value::Decimal(Decimal::new(dec)))
185		}
186		ValueKind::Any => Ok(Value::Any(Box::new(decode_value_from(r)?))),
187		ValueKind::DictionaryId => {
188			let width = r.u8()?;
189			let id = match width {
190				1 => DictionaryEntryId::U1(r.u8()?),
191				2 => DictionaryEntryId::U2(r.u16()?),
192				4 => DictionaryEntryId::U4(r.u32()?),
193				8 => DictionaryEntryId::U8(r.u64()?),
194				16 => DictionaryEntryId::U16(r.u128()?),
195				other => {
196					return Err(DecodeError::InvalidData(format!(
197						"invalid dictionary id width: {other}"
198					)));
199				}
200			};
201			Ok(Value::DictionaryId(id))
202		}
203		ValueKind::Type => Ok(Value::Type(decode_value_type(r)?)),
204		ValueKind::List => Ok(Value::List(decode_value_sequence(r)?)),
205		ValueKind::Tuple => Ok(Value::Tuple(decode_value_sequence(r)?)),
206		ValueKind::Record => {
207			let count = r.u32()?;
208			let mut fields = Vec::with_capacity((count as usize).min(4096));
209			for _ in 0..count {
210				let key = decode_len_prefixed_str(r)?.to_string();
211				fields.push((key, decode_value_from(r)?));
212			}
213			Ok(Value::Record(fields))
214		}
215	}
216}
217
218fn decode_value_sequence(r: &mut Reader) -> Result<Vec<Value>, DecodeError> {
219	let count = r.u32()?;
220	let mut items = Vec::with_capacity((count as usize).min(4096));
221	for _ in 0..count {
222		items.push(decode_value_from(r)?);
223	}
224	Ok(items)
225}
226
227fn decode_len_prefixed_bytes<'a>(r: &mut Reader<'a>) -> Result<&'a [u8], DecodeError> {
228	let len = r.u32()? as usize;
229	r.take(len)
230}
231
232fn decode_len_prefixed_str<'a>(r: &mut Reader<'a>) -> Result<&'a str, DecodeError> {
233	from_utf8(decode_len_prefixed_bytes(r)?).map_err(|e| DecodeError::InvalidData(format!("invalid UTF-8: {e}")))
234}
235
236pub fn encode_params(params: &Params) -> Result<Vec<u8>, EncodeError> {
237	let mut buf = Vec::new();
238	match params {
239		Params::None => buf.push(0),
240		Params::Positional(values) => {
241			buf.push(1);
242			buf.extend_from_slice(&(values.len() as u32).to_le_bytes());
243			for value in values.iter() {
244				encode_value_into(value, &mut buf)?;
245			}
246		}
247		Params::Named(map) => {
248			buf.push(2);
249			buf.extend_from_slice(&(map.len() as u32).to_le_bytes());
250			for (key, value) in map.iter() {
251				encode_len_prefixed(key.as_bytes(), &mut buf);
252				encode_value_into(value, &mut buf)?;
253			}
254		}
255	}
256	Ok(buf)
257}
258
259pub fn decode_params(bytes: &[u8]) -> Result<Params, DecodeError> {
260	let mut r = Reader::new(bytes);
261	let discriminant = r.u8()?;
262	let params = match discriminant {
263		0 => Params::None,
264		1 => {
265			let count = r.u32()?;
266			let mut values = Vec::with_capacity((count as usize).min(4096));
267			for _ in 0..count {
268				values.push(decode_value_from(&mut r)?);
269			}
270			Params::Positional(values.into())
271		}
272		2 => {
273			let count = r.u32()?;
274			let mut map = HashMap::with_capacity((count as usize).min(4096));
275			for _ in 0..count {
276				let key = decode_len_prefixed_str(&mut r)?.to_string();
277				map.insert(key, decode_value_from(&mut r)?);
278			}
279			Params::Named(map.into())
280		}
281		other => {
282			return Err(DecodeError::InvalidData(format!("invalid params discriminant: {other}")));
283		}
284	};
285	if !r.is_empty() {
286		return Err(DecodeError::TrailingBytes(r.remaining()));
287	}
288	Ok(params)
289}