Skip to main content

reifydb_codec/extern_c/
cells.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 ReifyDB
3
4use arrow_buffer::i256;
5use reifydb_value::value::{
6	Value,
7	constraint::{precision::Precision, scale::Scale},
8	decimal::Decimal,
9	dictionary::DictionaryEntryId,
10	duration::Duration,
11};
12
13use crate::{
14	error::{DecodeError, EncodeError},
15	reader::Reader,
16	tag::ValueKind,
17	unscaled::{NARROW, WIDE, decimal_unscaled, extend_le, read_le, width},
18	value::{decode_value, encode_value_into},
19};
20
21pub fn encode_decimal_cell(
22	value: &Decimal,
23	precision: Precision,
24	scale: Scale,
25	buf: &mut Vec<u8>,
26) -> Result<(), EncodeError> {
27	let unscaled = decimal_unscaled(value, precision, scale).ok_or_else(|| {
28		EncodeError::UnsupportedType(format!(
29			"decimal {value} does not fit precision {} and scale {}",
30			precision.value(),
31			scale.value()
32		))
33	})?;
34	extend_le(unscaled, width(precision), buf);
35	Ok(())
36}
37
38pub fn decode_decimal_cell(bytes: &[u8], scale: Scale) -> Result<Decimal, DecodeError> {
39	let unscaled = read_cell(ValueKind::Decimal, bytes)?;
40	Decimal::from_parts(unscaled, scale.value()).ok_or_else(|| {
41		DecodeError::InvalidData(format!(
42			"decimal cell {unscaled} at scale {} exceeds 76 digits",
43			scale.value()
44		))
45	})
46}
47
48fn read_cell(kind: ValueKind, bytes: &[u8]) -> Result<i256, DecodeError> {
49	match bytes.len() {
50		NARROW | WIDE => Ok(read_le(bytes)),
51		other => Err(DecodeError::InvalidData(format!("{kind:?} cell is {other} bytes, expected 16 or 32"))),
52	}
53}
54
55pub fn encode_any_cell(value: &Value, buf: &mut Vec<u8>) -> Result<(), EncodeError> {
56	encode_value_into(value, buf)
57}
58
59pub fn decode_any_cell(bytes: &[u8]) -> Result<Value, DecodeError> {
60	decode_value(bytes)
61}
62
63pub fn encode_dictionary_id_cell(id: &DictionaryEntryId, buf: &mut Vec<u8>) {
64	match id {
65		DictionaryEntryId::U1(v) => {
66			buf.push(1);
67			buf.extend_from_slice(&v.to_le_bytes());
68		}
69		DictionaryEntryId::U2(v) => {
70			buf.push(2);
71			buf.extend_from_slice(&v.to_le_bytes());
72		}
73		DictionaryEntryId::U4(v) => {
74			buf.push(4);
75			buf.extend_from_slice(&v.to_le_bytes());
76		}
77		DictionaryEntryId::U8(v) => {
78			buf.push(8);
79			buf.extend_from_slice(&v.to_le_bytes());
80		}
81		DictionaryEntryId::U16(v) => {
82			buf.push(16);
83			buf.extend_from_slice(&v.to_le_bytes());
84		}
85	}
86}
87
88pub fn decode_dictionary_id_cell(bytes: &[u8]) -> Result<DictionaryEntryId, DecodeError> {
89	let mut r = Reader::new(bytes);
90	let width = r.u8()?;
91	let id = match width {
92		1 => DictionaryEntryId::U1(r.u8()?),
93		2 => DictionaryEntryId::U2(r.u16()?),
94		4 => DictionaryEntryId::U4(r.u32()?),
95		8 => DictionaryEntryId::U8(r.u64()?),
96		16 => DictionaryEntryId::U16(r.u128()?),
97		other => {
98			return Err(DecodeError::InvalidData(format!("invalid dictionary id width: {other}")));
99		}
100	};
101	if !r.is_empty() {
102		return Err(DecodeError::TrailingBytes(r.remaining()));
103	}
104	Ok(id)
105}
106
107pub fn encode_duration_cell(value: &Duration, buf: &mut Vec<u8>) {
108	buf.extend_from_slice(&value.get_months().to_le_bytes());
109	buf.extend_from_slice(&value.get_days().to_le_bytes());
110	buf.extend_from_slice(&value.get_nanos().to_le_bytes());
111}
112
113pub fn decode_duration_cell(bytes: &[u8]) -> Result<Duration, DecodeError> {
114	let mut r = Reader::new(bytes);
115	let months = r.i32()?;
116	let days = r.i32()?;
117	let nanos = r.i64()?;
118	if !r.is_empty() {
119		return Err(DecodeError::TrailingBytes(r.remaining()));
120	}
121	Duration::new(months, days, nanos).map_err(|e| DecodeError::InvalidData(format!("invalid duration: {e}")))
122}