use bytes::{BufMut, BytesMut};
#[allow(dead_code)]
const WIRE_VARINT: u8 = 0;
#[allow(dead_code)]
const WIRE_LEN: u8 = 2;
#[allow(dead_code)]
const WIRE_FIXED32: u8 = 5;
const SEARCH_COLLECTION: u8 = 0x0A;
const SEARCH_VECTOR: u8 = 0x12;
#[allow(dead_code)]
const SEARCH_FILTER: u8 = 0x1A;
const SEARCH_LIMIT: u8 = 0x20;
const SEARCH_WITH_PAYLOAD: u8 = 0x32;
const SEARCH_SCORE_THRESHOLD: u8 = 0x45;
const SEARCH_VECTOR_NAME: u8 = 0x52;
const UPSERT_COLLECTION: u8 = 0x0A;
const UPSERT_WAIT: u8 = 0x10;
const UPSERT_POINTS: u8 = 0x1A;
const POINT_ID: u8 = 0x0A;
const POINT_VECTORS: u8 = 0x1A;
#[allow(dead_code)]
const POINT_PAYLOAD: u8 = 0x22;
const POINT_ID_NUM: u8 = 0x08;
const POINT_ID_UUID: u8 = 0x12;
#[inline]
pub fn encode_varint(buf: &mut BytesMut, mut value: usize) {
loop {
let byte = (value & 0x7F) as u8;
value >>= 7;
if value == 0 {
buf.put_u8(byte);
break;
} else {
buf.put_u8(byte | 0x80);
}
}
}
#[inline]
pub fn encode_varint_u64(buf: &mut BytesMut, mut value: u64) {
loop {
let byte = (value & 0x7F) as u8;
value >>= 7;
if value == 0 {
buf.put_u8(byte);
break;
} else {
buf.put_u8(byte | 0x80);
}
}
}
pub fn encode_search_proto(
buf: &mut BytesMut,
collection: &str,
vector: &[f32],
limit: u64,
score_threshold: Option<f32>,
vector_name: Option<&str>,
) {
buf.clear();
buf.put_u8(SEARCH_COLLECTION);
encode_varint(buf, collection.len());
buf.extend_from_slice(collection.as_bytes());
buf.put_u8(SEARCH_VECTOR);
let vector_bytes_len = vector.len() * 4; encode_varint(buf, vector_bytes_len);
let float_bytes = unsafe {
std::slice::from_raw_parts(vector.as_ptr() as *const u8, vector_bytes_len)
};
buf.extend_from_slice(float_bytes);
buf.put_u8(SEARCH_LIMIT);
encode_varint_u64(buf, limit);
if let Some(threshold) = score_threshold {
buf.put_u8(SEARCH_SCORE_THRESHOLD);
buf.put_f32_le(threshold);
}
if let Some(name) = vector_name {
buf.put_u8(SEARCH_VECTOR_NAME);
encode_varint(buf, name.len());
buf.extend_from_slice(name.as_bytes());
}
}
pub fn encode_with_payload_true(buf: &mut BytesMut) {
buf.put_u8(SEARCH_WITH_PAYLOAD);
encode_varint(buf, 2); buf.put_u8(0x08); buf.put_u8(0x01); }
pub fn encode_upsert_proto(
buf: &mut BytesMut,
collection: &str,
points: &[crate::Point],
wait: bool,
) {
buf.clear();
buf.put_u8(UPSERT_COLLECTION);
encode_varint(buf, collection.len());
buf.extend_from_slice(collection.as_bytes());
if wait {
buf.put_u8(UPSERT_WAIT);
buf.put_u8(0x01);
}
for point in points {
encode_point_struct(buf, point);
}
}
fn encode_point_struct(buf: &mut BytesMut, point: &crate::Point) {
let mut point_buf = BytesMut::with_capacity(point.vector.len() * 4 + 64);
match &point.id {
crate::PointId::Num(n) => {
point_buf.put_u8(POINT_ID);
let id_len = 1 + varint_len(*n); encode_varint(&mut point_buf, id_len);
point_buf.put_u8(POINT_ID_NUM);
encode_varint_u64(&mut point_buf, *n);
}
crate::PointId::Uuid(s) => {
point_buf.put_u8(POINT_ID);
let id_len = 1 + varint_len(s.len() as u64) + s.len();
encode_varint(&mut point_buf, id_len);
point_buf.put_u8(POINT_ID_UUID);
encode_varint(&mut point_buf, s.len());
point_buf.extend_from_slice(s.as_bytes());
}
}
let vector_bytes_len = point.vector.len() * 4;
let dense_len = 1 + varint_len(vector_bytes_len as u64) + vector_bytes_len;
let vector_len = varint_len((101 << 3 | 2) as u64) + varint_len(dense_len as u64) + dense_len;
let vectors_len = 1 + varint_len(vector_len as u64) + vector_len;
point_buf.put_u8(POINT_VECTORS);
encode_varint(&mut point_buf, vectors_len);
point_buf.put_u8(0x0A);
encode_varint(&mut point_buf, vector_len);
encode_varint(&mut point_buf, (101 << 3) | 2);
encode_varint(&mut point_buf, dense_len);
point_buf.put_u8(0x0A);
encode_varint(&mut point_buf, vector_bytes_len);
let float_bytes = unsafe {
std::slice::from_raw_parts(point.vector.as_ptr() as *const u8, vector_bytes_len)
};
point_buf.extend_from_slice(float_bytes);
buf.put_u8(UPSERT_POINTS);
encode_varint(buf, point_buf.len());
buf.extend_from_slice(&point_buf);
}
#[inline]
fn varint_len(value: u64) -> usize {
if value == 0 {
1
} else {
let bits = 64 - value.leading_zeros() as usize;
bits.div_ceil(7)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_varint_encoding() {
let mut buf = BytesMut::new();
encode_varint(&mut buf, 1);
assert_eq!(&buf[..], &[0x01]);
buf.clear();
encode_varint(&mut buf, 127);
assert_eq!(&buf[..], &[0x7F]);
buf.clear();
encode_varint(&mut buf, 128);
assert_eq!(&buf[..], &[0x80, 0x01]);
buf.clear();
encode_varint(&mut buf, 300);
assert_eq!(&buf[..], &[0xAC, 0x02]);
}
#[test]
fn test_encode_search_basic() {
let mut buf = BytesMut::with_capacity(1024);
let vector = vec![0.1f32, 0.2, 0.3, 0.4];
encode_search_proto(&mut buf, "test_collection", &vector, 10, None, None);
assert_eq!(buf[0], SEARCH_COLLECTION);
assert!(buf.len() > 20);
}
#[test]
fn test_zero_copy_vector() {
let mut buf = BytesMut::with_capacity(1024);
let vector = vec![1.0f32, 2.0, 3.0, 4.0];
encode_search_proto(&mut buf, "test", &vector, 5, None, None);
let vector_start = 8;
let vector_bytes = &buf[vector_start..vector_start + 16];
let float_bytes: [u8; 4] = 1.0f32.to_le_bytes();
assert_eq!(&vector_bytes[0..4], &float_bytes);
}
#[test]
fn test_varint_len() {
assert_eq!(varint_len(0), 1);
assert_eq!(varint_len(1), 1);
assert_eq!(varint_len(127), 1);
assert_eq!(varint_len(128), 2);
assert_eq!(varint_len(16383), 2);
assert_eq!(varint_len(16384), 3);
}
}