use std::str;
use bigdecimal::BigDecimal;
use num_bigint::BigInt;
use reifydb_value::value::{
blob::Blob,
container::{blob::BlobContainer, number::NumberContainer, utf8::Utf8Container},
decimal::Decimal,
frame::data::FrameColumnData,
int::Int,
uint::Uint,
value_type::ValueType,
};
use super::column_type_from_code;
use crate::{error::DecodeError, frame::encoding::rle::decode_rle_varlen};
pub(crate) fn decode_varlen_plain(
type_code: u8,
row_count: usize,
data: &[u8],
offsets: &[u8],
) -> Option<Result<FrameColumnData, DecodeError>> {
let ty = match column_type_from_code(type_code) {
Ok(ty) => ty,
Err(e) => return Some(Err(e)),
};
let result = match ty {
ValueType::Utf8 => {
let strings = decode_varlen_strings(data, offsets, row_count);
match strings {
Ok(s) => Ok(FrameColumnData::Utf8(Utf8Container::new(s))),
Err(e) => Err(e),
}
}
ValueType::Blob => {
let blobs = decode_varlen_blobs(data, offsets, row_count);
match blobs {
Ok(b) => Ok(FrameColumnData::Blob(BlobContainer::new(b))),
Err(e) => Err(e),
}
}
ValueType::Int => {
let mut values = Vec::with_capacity(row_count);
let offset_arr = decode_u32_offsets(offsets, row_count);
for i in 0..row_count {
let start = offset_arr[i] as usize;
let end = offset_arr[i + 1] as usize;
let big = BigInt::from_signed_bytes_le(&data[start..end]);
values.push(Int(big));
}
Ok(FrameColumnData::Int(NumberContainer::new(values)))
}
ValueType::Uint => {
let mut values = Vec::with_capacity(row_count);
let offset_arr = decode_u32_offsets(offsets, row_count);
for i in 0..row_count {
let start = offset_arr[i] as usize;
let end = offset_arr[i + 1] as usize;
let big = BigInt::from_signed_bytes_le(&data[start..end]);
values.push(Uint(big));
}
Ok(FrameColumnData::Uint(NumberContainer::new(values)))
}
ValueType::Decimal => decode_decimal(data, offsets, row_count),
_ => return None,
};
Some(result)
}
pub(crate) fn decode_rle_varlen_column(
type_code: u8,
row_count: usize,
data: &[u8],
) -> Result<FrameColumnData, DecodeError> {
let ty = column_type_from_code(type_code)?;
let entries = decode_rle_varlen(data, row_count)?;
match ty {
ValueType::Int => {
let values: Vec<Int> =
entries.into_iter().map(|bytes| Int(BigInt::from_signed_bytes_le(&bytes))).collect();
Ok(FrameColumnData::Int(NumberContainer::new(values)))
}
ValueType::Uint => {
let values: Vec<Uint> =
entries.into_iter().map(|bytes| Uint(BigInt::from_signed_bytes_le(&bytes))).collect();
Ok(FrameColumnData::Uint(NumberContainer::new(values)))
}
ValueType::Decimal => {
let mut values = Vec::with_capacity(row_count);
for bytes in entries {
let s = str::from_utf8(&bytes).map_err(|e| {
DecodeError::InvalidData(format!("invalid decimal string: {}", e))
})?;
let dec: BigDecimal = s
.parse()
.map_err(|e| DecodeError::InvalidData(format!("invalid decimal: {}", e)))?;
values.push(Decimal::new(dec));
}
Ok(FrameColumnData::Decimal(NumberContainer::new(values)))
}
_ => Err(DecodeError::InvalidData(format!("varlen RLE not supported for type {:?}", ty))),
}
}
fn decode_decimal(data: &[u8], offsets: &[u8], row_count: usize) -> Result<FrameColumnData, DecodeError> {
let mut values = Vec::with_capacity(row_count);
let offset_arr = decode_u32_offsets(offsets, row_count);
for i in 0..row_count {
let start = offset_arr[i] as usize;
let end = offset_arr[i + 1] as usize;
let s = str::from_utf8(&data[start..end])
.map_err(|e| DecodeError::InvalidData(format!("invalid decimal string: {}", e)))?;
let dec: BigDecimal =
s.parse().map_err(|e| DecodeError::InvalidData(format!("invalid decimal: {}", e)))?;
values.push(Decimal::new(dec));
}
Ok(FrameColumnData::Decimal(NumberContainer::new(values)))
}
fn decode_u32_offsets(offsets: &[u8], row_count: usize) -> Vec<u32> {
let count = row_count + 1;
let mut result = Vec::with_capacity(count);
for i in 0..count {
result.push(u32::from_le_bytes([
offsets[i * 4],
offsets[i * 4 + 1],
offsets[i * 4 + 2],
offsets[i * 4 + 3],
]));
}
result
}
fn decode_varlen_strings(data: &[u8], offsets: &[u8], row_count: usize) -> Result<Vec<String>, DecodeError> {
let offset_arr = decode_u32_offsets(offsets, row_count);
let mut strings = Vec::with_capacity(row_count);
for i in 0..row_count {
let start = offset_arr[i] as usize;
let end = offset_arr[i + 1] as usize;
let s = str::from_utf8(&data[start..end])
.map_err(|e| DecodeError::InvalidData(format!("invalid UTF-8: {}", e)))?;
strings.push(s.to_string());
}
Ok(strings)
}
fn decode_varlen_blobs(data: &[u8], offsets: &[u8], row_count: usize) -> Result<Vec<Blob>, DecodeError> {
let offset_arr = decode_u32_offsets(offsets, row_count);
let mut blobs = Vec::with_capacity(row_count);
for i in 0..row_count {
let start = offset_arr[i] as usize;
let end = offset_arr[i + 1] as usize;
blobs.push(Blob::new(data[start..end].to_vec()));
}
Ok(blobs)
}