use alloc::format;
use alloc::vec::Vec;
use core::fmt::{self, Debug};
use crate::types::{MutInPlaceValue, TypeName, Value};
pub struct FixedVec<const N: usize>;
impl<const N: usize> Debug for FixedVec<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "FixedVec<{N}>")
}
}
impl<const N: usize> Value for FixedVec<N> {
type SelfType<'a>
= [f32; N]
where
Self: 'a;
type AsBytes<'a>
= Vec<u8>
where
Self: 'a;
fn fixed_width() -> Option<usize> {
Some(N * core::mem::size_of::<f32>())
}
fn from_bytes<'a>(data: &'a [u8]) -> [f32; N]
where
Self: 'a,
{
let expected = N * core::mem::size_of::<f32>();
debug_assert!(
data.len() >= expected,
"FixedVec<{N}>::from_bytes: truncated data ({} < {expected}); \
this indicates on-disk corruption or a dimension mismatch \
between the table definition and stored data",
data.len(),
);
let usable = data.len().min(expected);
let mut result = [0.0f32; N];
#[cfg(target_endian = "little")]
{
unsafe {
core::ptr::copy_nonoverlapping(
data.as_ptr(),
result.as_mut_ptr().cast::<u8>(),
usable,
);
}
}
#[cfg(not(target_endian = "little"))]
{
let full_floats = usable / 4;
for i in 0..full_floats {
let start = i * 4;
result[i] = f32::from_le_bytes([
data[start],
data[start + 1],
data[start + 2],
data[start + 3],
]);
}
}
result
}
fn as_bytes<'a, 'b: 'a>(value: &'a [f32; N]) -> Vec<u8>
where
Self: 'b,
{
#[cfg(target_endian = "little")]
{
let byte_slice =
unsafe { core::slice::from_raw_parts(value.as_ptr().cast::<u8>(), N * 4) };
byte_slice.to_vec()
}
#[cfg(not(target_endian = "little"))]
{
let mut result = Vec::with_capacity(N * core::mem::size_of::<f32>());
for val in value {
result.extend_from_slice(&val.to_le_bytes());
}
result
}
}
fn type_name() -> TypeName {
TypeName::internal(&format!("redb::vec::FixedVec<{N}>"))
}
}
impl<const N: usize> MutInPlaceValue for FixedVec<N> {
type BaseRefType = [u8];
fn initialize(data: &mut [u8]) {
data.fill(0);
}
fn from_bytes_mut(data: &mut [u8]) -> &mut [u8] {
data
}
}
pub struct DynVec;
impl Debug for DynVec {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("DynVec")
}
}
impl Value for DynVec {
type SelfType<'a>
= Vec<f32>
where
Self: 'a;
type AsBytes<'a>
= Vec<u8>
where
Self: 'a;
fn fixed_width() -> Option<usize> {
None
}
fn from_bytes<'a>(data: &'a [u8]) -> Vec<f32>
where
Self: 'a,
{
let usable = data.len() - (data.len() % 4);
let dim = usable / 4;
#[cfg(target_endian = "little")]
{
let mut result = alloc::vec![0.0f32; dim];
unsafe {
core::ptr::copy_nonoverlapping(
data.as_ptr(),
result.as_mut_ptr().cast::<u8>(),
dim * 4,
);
}
result
}
#[cfg(not(target_endian = "little"))]
{
let mut result = Vec::with_capacity(dim);
for i in 0..dim {
let start = i * 4;
let bytes: [u8; 4] = [
data[start],
data[start + 1],
data[start + 2],
data[start + 3],
];
result.push(f32::from_le_bytes(bytes));
}
result
}
}
fn as_bytes<'a, 'b: 'a>(value: &'a Vec<f32>) -> Vec<u8>
where
Self: 'b,
{
#[cfg(target_endian = "little")]
{
let byte_slice = unsafe {
core::slice::from_raw_parts(value.as_ptr().cast::<u8>(), value.len() * 4)
};
byte_slice.to_vec()
}
#[cfg(not(target_endian = "little"))]
{
let mut result = Vec::with_capacity(value.len() * core::mem::size_of::<f32>());
for val in value {
result.extend_from_slice(&val.to_le_bytes());
}
result
}
}
fn type_name() -> TypeName {
TypeName::internal("redb::vec::DynVec")
}
}
pub struct BinaryQuantized<const N: usize>;
impl<const N: usize> Debug for BinaryQuantized<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "BinaryQuantized<{N}>")
}
}
impl<const N: usize> Value for BinaryQuantized<N> {
type SelfType<'a>
= [u8; N]
where
Self: 'a;
type AsBytes<'a>
= [u8; N]
where
Self: 'a;
fn fixed_width() -> Option<usize> {
Some(N)
}
fn from_bytes<'a>(data: &'a [u8]) -> [u8; N]
where
Self: 'a,
{
if let Ok(arr) = data.try_into() {
arr
} else {
let mut result = [0u8; N];
let copy_len = data.len().min(N);
result[..copy_len].copy_from_slice(&data[..copy_len]);
result
}
}
fn as_bytes<'a, 'b: 'a>(value: &'a [u8; N]) -> [u8; N]
where
Self: 'b,
{
*value
}
fn type_name() -> TypeName {
TypeName::internal(&format!("redb::vec::BinaryQuantized<{N}>"))
}
}
impl<const N: usize> MutInPlaceValue for BinaryQuantized<N> {
type BaseRefType = [u8];
fn initialize(data: &mut [u8]) {
data.fill(0);
}
fn from_bytes_mut(data: &mut [u8]) -> &mut [u8] {
data
}
}
pub struct ScalarQuantized<const N: usize>;
impl<const N: usize> Debug for ScalarQuantized<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "ScalarQuantized<{N}>")
}
}
const SQ_HEADER: usize = 8;
impl<const N: usize> Value for ScalarQuantized<N> {
type SelfType<'a>
= SQVec<N>
where
Self: 'a;
type AsBytes<'a>
= Vec<u8>
where
Self: 'a;
fn fixed_width() -> Option<usize> {
Some(SQ_HEADER + N)
}
fn from_bytes<'a>(data: &'a [u8]) -> SQVec<N>
where
Self: 'a,
{
if data.len() < SQ_HEADER + N {
return SQVec {
min_val: 0.0,
max_val: 0.0,
codes: [0u8; N],
};
}
let min_val = f32::from_le_bytes([data[0], data[1], data[2], data[3]]);
let max_val = f32::from_le_bytes([data[4], data[5], data[6], data[7]]);
if !min_val.is_finite() || !max_val.is_finite() {
return SQVec {
min_val: 0.0,
max_val: 0.0,
codes: [0u8; N],
};
}
let mut codes = [0u8; N];
codes.copy_from_slice(&data[SQ_HEADER..SQ_HEADER + N]);
SQVec {
min_val,
max_val,
codes,
}
}
fn as_bytes<'a, 'b: 'a>(value: &'a SQVec<N>) -> Vec<u8>
where
Self: 'b,
{
let mut result = Vec::with_capacity(SQ_HEADER + N);
result.extend_from_slice(&value.min_val.to_le_bytes());
result.extend_from_slice(&value.max_val.to_le_bytes());
result.extend_from_slice(&value.codes);
result
}
fn type_name() -> TypeName {
TypeName::internal(&format!("redb::vec::ScalarQuantized<{N}>"))
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct SQVec<const N: usize> {
pub min_val: f32,
pub max_val: f32,
pub codes: [u8; N],
}
impl<const N: usize> SQVec<N> {
#[inline]
pub fn dequantize(&self) -> [f32; N] {
let mut result = [0.0f32; N];
let range = self.max_val - self.min_val;
if range == 0.0 {
result.fill(self.min_val);
} else {
let scale = range / 255.0;
for (i, &code) in self.codes.iter().enumerate() {
result[i] = self.min_val + f32::from(code) * scale;
}
}
result
}
}