use std::borrow::{Borrow, Cow};
use std::fmt;
use std::marker::PhantomData;
use std::mem::transmute;
pub use binary::Binary;
pub use binary_quantized::BinaryQuantized;
use bytemuck::pod_collect_to_vec;
mod binary;
mod binary_quantized;
mod f32;
#[cfg(test)]
mod binary_quantized_test;
pub trait UnalignedVectorCodec: std::borrow::ToOwned + Sized {
fn from_bytes(bytes: &[u8]) -> Result<Cow<'_, UnalignedVector<Self>>, SizeMismatch>;
fn from_slice(slice: &[f32]) -> Cow<'_, UnalignedVector<Self>>;
fn from_vec(vec: Vec<f32>) -> Cow<'static, UnalignedVector<Self>>;
fn to_vec(vec: &UnalignedVector<Self>) -> Vec<f32>;
fn iter(vec: &UnalignedVector<Self>) -> impl ExactSizeIterator<Item = f32> + '_;
fn len(vec: &UnalignedVector<Self>) -> usize;
fn is_zero(vec: &UnalignedVector<Self>) -> bool;
fn word_size() -> usize {
1
}
}
#[repr(transparent)]
pub struct UnalignedVector<Codec: UnalignedVectorCodec> {
format: PhantomData<fn() -> Codec>,
vector: [u8],
}
impl<Codec: UnalignedVectorCodec> UnalignedVector<Codec> {
pub fn from_bytes(bytes: &[u8]) -> Result<Cow<'_, UnalignedVector<Codec>>, SizeMismatch> {
Codec::from_bytes(bytes)
}
pub fn from_slice(slice: &[f32]) -> Cow<'_, UnalignedVector<Codec>> {
Codec::from_slice(slice)
}
pub fn from_vec(vec: Vec<f32>) -> Cow<'static, UnalignedVector<Codec>> {
Codec::from_vec(vec)
}
pub fn iter(&self) -> impl ExactSizeIterator<Item = f32> + '_ {
Codec::iter(self)
}
pub fn is_zero(&self) -> bool {
Codec::is_zero(self)
}
pub fn to_vec(&self) -> Vec<f32> {
Codec::to_vec(self)
}
pub fn len(&self) -> usize {
Codec::len(self)
}
pub(crate) fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
unsafe { transmute(bytes) }
}
pub(crate) fn as_bytes(&self) -> &[u8] {
&self.vector
}
pub fn is_empty(&self) -> bool {
self.vector.is_empty()
}
pub(crate) fn as_ptr(&self) -> *const u8 {
self.vector.as_ptr()
}
}
#[derive(Debug, thiserror::Error)]
#[error(
"Slice of bytes contains {rem} too many bytes to be decoded with the {vector_codec} codec."
)]
pub struct SizeMismatch {
vector_codec: &'static str,
rem: usize,
}
impl<Codec: UnalignedVectorCodec> ToOwned for UnalignedVector<Codec> {
type Owned = Vec<u8>;
fn to_owned(&self) -> Self::Owned {
pod_collect_to_vec(&self.vector)
}
}
impl<Codec: UnalignedVectorCodec> Borrow<UnalignedVector<Codec>> for Vec<u8> {
fn borrow(&self) -> &UnalignedVector<Codec> {
UnalignedVector::from_bytes_unchecked(self)
}
}
impl<Codec: UnalignedVectorCodec> fmt::Debug for UnalignedVector<Codec> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut list = f.debug_list();
struct Number(f32);
impl fmt::Debug for Number {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:0.4}", self.0)
}
}
let vec = self.to_vec();
for v in vec.iter().take(10) {
list.entry(&Number(*v));
}
if vec.len() < 10 {
return list.finish();
}
if vec[10..].iter().all(|v| *v == 0.0) {
list.entry(&"0.0, ...");
} else {
list.entry(&"other ...");
}
list.finish()
}
}