Skip to main content

reifydb_codec/
typeinfo.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 ReifyDB
3
4use std::str::from_utf8;
5
6use reifydb_value::value::value_type::ValueType;
7
8use crate::{
9	error::{DecodeError, EncodeError},
10	reader::Reader,
11	tag::{EXTENDED_TYPE_TAG, MAX_OPTION_DEPTH, TypeTag, ValueKind, peel_options},
12};
13
14pub fn encode_value_type(ty: &ValueType, buf: &mut Vec<u8>) -> Result<(), EncodeError> {
15	let (base, depth) = peel_options(ty);
16	if depth > MAX_OPTION_DEPTH as u32 {
17		if depth > u8::MAX as u32 {
18			return Err(EncodeError::OptionDepthTooDeep {
19				depth,
20				max: u8::MAX,
21			});
22		}
23		buf.push(EXTENDED_TYPE_TAG);
24		buf.push(depth as u8);
25		encode_base(base, 0, buf)
26	} else {
27		encode_base(base, depth as u8, buf)
28	}
29}
30
31fn encode_base(base: &ValueType, depth: u8, buf: &mut Vec<u8>) -> Result<(), EncodeError> {
32	let tag = TypeTag::new(ValueKind::of_type(base), depth)?;
33	buf.push(tag.byte());
34	match base {
35		ValueType::List(element) => encode_value_type(element, buf)?,
36		ValueType::Record(fields) => {
37			buf.extend_from_slice(&(fields.len() as u16).to_le_bytes());
38			for (name, field_ty) in fields {
39				let name_bytes = name.as_bytes();
40				buf.extend_from_slice(&(name_bytes.len() as u16).to_le_bytes());
41				buf.extend_from_slice(name_bytes);
42				encode_value_type(field_ty, buf)?;
43			}
44		}
45		ValueType::Tuple(elements) => {
46			buf.extend_from_slice(&(elements.len() as u16).to_le_bytes());
47			for element in elements {
48				encode_value_type(element, buf)?;
49			}
50		}
51		_ => {}
52	}
53	Ok(())
54}
55
56pub fn decode_value_type(r: &mut Reader) -> Result<ValueType, DecodeError> {
57	let first = r.u8()?;
58	if first == EXTENDED_TYPE_TAG {
59		let depth = r.u8()?;
60		let base = decode_value_type(r)?;
61		return Ok((0..depth).fold(base, |ty, _| ValueType::Option(Box::new(ty))));
62	}
63	let tag = TypeTag::from_byte(first)?;
64	let kind = tag.kind().ok_or(DecodeError::UnknownTypeCode(first))?;
65	let base = match kind {
66		ValueKind::List => ValueType::List(Box::new(decode_value_type(r)?)),
67		ValueKind::Record => {
68			let count = r.u16()?;
69			let mut fields = Vec::with_capacity(count as usize);
70			for _ in 0..count {
71				let name_len = r.u16()? as usize;
72				let name = from_utf8(r.take(name_len)?)
73					.map_err(|e| {
74						DecodeError::InvalidData(format!(
75							"invalid UTF-8 in record field name: {e}"
76						))
77					})?
78					.to_string();
79				fields.push((name, decode_value_type(r)?));
80			}
81			ValueType::Record(fields)
82		}
83		ValueKind::Tuple => {
84			let count = r.u16()?;
85			let mut elements = Vec::with_capacity(count as usize);
86			for _ in 0..count {
87				elements.push(decode_value_type(r)?);
88			}
89			ValueType::Tuple(elements)
90		}
91		_ => return tag.to_type(),
92	};
93	Ok((0..tag.depth()).fold(base, |ty, _| ValueType::Option(Box::new(ty))))
94}