1use std::io;
4use std::mem::size_of;
5
6use serde::{Deserialize, Serialize};
7
8use crate::directories::{AsyncFileRead, LazyFileSlice, OwnedBytes};
9use crate::dsl::DenseVectorQuantization;
10use crate::structures::simd::{batch_f32_to_f16, batch_f32_to_u8, f16_to_f32, u8_to_f32};
11
12const FLAT_BINARY_MAGIC: u32 = 0x46564433;
14
15const FLAT_BINARY_HEADER_SIZE: usize = 16;
17const DOC_ID_ENTRY_SIZE: usize = size_of::<u32>() + size_of::<u16>();
19
20pub struct FlatVectorData;
33
34impl FlatVectorData {
35 pub fn write_binary_header(
37 dim: usize,
38 num_vectors: usize,
39 quant: DenseVectorQuantization,
40 writer: &mut dyn std::io::Write,
41 ) -> std::io::Result<()> {
42 writer.write_all(&FLAT_BINARY_MAGIC.to_le_bytes())?;
43 writer.write_all(&(dim as u32).to_le_bytes())?;
44 writer.write_all(&(num_vectors as u32).to_le_bytes())?;
45 writer.write_all(&[quant.tag(), 0, 0, 0])?; Ok(())
47 }
48
49 pub fn serialized_binary_size(
51 dim: usize,
52 num_vectors: usize,
53 quant: DenseVectorQuantization,
54 ) -> usize {
55 FLAT_BINARY_HEADER_SIZE
56 + num_vectors * dim * quant.element_size()
57 + num_vectors * DOC_ID_ENTRY_SIZE
58 }
59
60 pub fn serialize_binary_from_flat_streaming(
65 dim: usize,
66 flat_vectors: &[f32],
67 doc_ids: &[(u32, u16)],
68 quant: DenseVectorQuantization,
69 writer: &mut dyn std::io::Write,
70 ) -> std::io::Result<()> {
71 let num_vectors = doc_ids.len();
72 Self::write_binary_header(dim, num_vectors, quant, writer)?;
73
74 match quant {
75 DenseVectorQuantization::F32 => {
76 let bytes: &[u8] = unsafe {
77 std::slice::from_raw_parts(
78 flat_vectors.as_ptr() as *const u8,
79 std::mem::size_of_val(flat_vectors),
80 )
81 };
82 writer.write_all(bytes)?;
83 }
84 DenseVectorQuantization::F16 => {
85 let mut buf = vec![0u16; dim];
86 for v in flat_vectors.chunks_exact(dim) {
87 batch_f32_to_f16(v, &mut buf);
88 let bytes: &[u8] =
89 unsafe { std::slice::from_raw_parts(buf.as_ptr() as *const u8, dim * 2) };
90 writer.write_all(bytes)?;
91 }
92 }
93 DenseVectorQuantization::UInt8 => {
94 let mut buf = vec![0u8; dim];
95 for v in flat_vectors.chunks_exact(dim) {
96 batch_f32_to_u8(v, &mut buf);
97 writer.write_all(&buf)?;
98 }
99 }
100 }
101
102 for &(doc_id, ordinal) in doc_ids {
103 writer.write_all(&doc_id.to_le_bytes())?;
104 writer.write_all(&ordinal.to_le_bytes())?;
105 }
106
107 Ok(())
108 }
109
110 pub fn write_raw_vector_bytes(
114 raw_bytes: &[u8],
115 writer: &mut dyn std::io::Write,
116 ) -> std::io::Result<()> {
117 writer.write_all(raw_bytes)
118 }
119}
120
121#[derive(Debug, Clone)]
133pub struct LazyFlatVectorData {
134 pub dim: usize,
136 pub num_vectors: usize,
138 pub quantization: DenseVectorQuantization,
140 pub doc_ids: Vec<(u32, u16)>,
142 handle: LazyFileSlice,
144 vectors_offset: u64,
146 element_size: usize,
148}
149
150impl LazyFlatVectorData {
151 pub async fn open(handle: LazyFileSlice) -> io::Result<Self> {
156 let header = handle
158 .read_bytes_range(0..FLAT_BINARY_HEADER_SIZE as u64)
159 .await?;
160 let hdr = header.as_slice();
161
162 let magic = u32::from_le_bytes([hdr[0], hdr[1], hdr[2], hdr[3]]);
163 if magic != FLAT_BINARY_MAGIC {
164 return Err(io::Error::new(
165 io::ErrorKind::InvalidData,
166 "Invalid FlatVectorData binary magic",
167 ));
168 }
169
170 let dim = u32::from_le_bytes([hdr[4], hdr[5], hdr[6], hdr[7]]) as usize;
171 let num_vectors = u32::from_le_bytes([hdr[8], hdr[9], hdr[10], hdr[11]]) as usize;
172 let quantization = DenseVectorQuantization::from_tag(hdr[12]).ok_or_else(|| {
173 io::Error::new(
174 io::ErrorKind::InvalidData,
175 format!("Unknown quantization tag: {}", hdr[12]),
176 )
177 })?;
178 let element_size = quantization.element_size();
179
180 let vectors_byte_len = num_vectors * dim * element_size;
182 let doc_ids_start = (FLAT_BINARY_HEADER_SIZE + vectors_byte_len) as u64;
183 let doc_ids_byte_len = (num_vectors * DOC_ID_ENTRY_SIZE) as u64;
184
185 let doc_ids_bytes = handle
186 .read_bytes_range(doc_ids_start..doc_ids_start + doc_ids_byte_len)
187 .await?;
188 let d = doc_ids_bytes.as_slice();
189
190 let mut doc_ids = Vec::with_capacity(num_vectors);
191 for i in 0..num_vectors {
192 let off = i * DOC_ID_ENTRY_SIZE;
193 let doc_id = u32::from_le_bytes([d[off], d[off + 1], d[off + 2], d[off + 3]]);
194 let ordinal = u16::from_le_bytes([d[off + 4], d[off + 5]]);
195 doc_ids.push((doc_id, ordinal));
196 }
197
198 Ok(Self {
199 dim,
200 num_vectors,
201 quantization,
202 doc_ids,
203 handle,
204 vectors_offset: FLAT_BINARY_HEADER_SIZE as u64,
205 element_size,
206 })
207 }
208
209 pub async fn read_vector_into(&self, idx: usize, out: &mut [f32]) -> io::Result<()> {
214 debug_assert!(out.len() >= self.dim);
215 let vec_byte_len = self.dim * self.element_size;
216 let byte_offset = self.vectors_offset + (idx * vec_byte_len) as u64;
217 let bytes = self
218 .handle
219 .read_bytes_range(byte_offset..byte_offset + vec_byte_len as u64)
220 .await?;
221 let raw = bytes.as_slice();
222
223 match self.quantization {
224 DenseVectorQuantization::F32 => unsafe {
225 std::ptr::copy_nonoverlapping(
226 raw.as_ptr(),
227 out.as_mut_ptr() as *mut u8,
228 vec_byte_len,
229 );
230 },
231 DenseVectorQuantization::F16 => {
232 let f16_slice =
233 unsafe { std::slice::from_raw_parts(raw.as_ptr() as *const u16, self.dim) };
234 for (i, &h) in f16_slice.iter().enumerate() {
235 out[i] = f16_to_f32(h);
236 }
237 }
238 DenseVectorQuantization::UInt8 => {
239 for (i, &b) in raw.iter().enumerate().take(self.dim) {
240 out[i] = u8_to_f32(b);
241 }
242 }
243 }
244 Ok(())
245 }
246
247 pub async fn get_vector(&self, idx: usize) -> io::Result<Vec<f32>> {
249 let mut vector = vec![0f32; self.dim];
250 self.read_vector_into(idx, &mut vector).await?;
251 Ok(vector)
252 }
253
254 pub async fn read_vector_raw_into(&self, idx: usize, out: &mut [u8]) -> io::Result<()> {
259 let vbs = self.vector_byte_size();
260 debug_assert!(out.len() >= vbs);
261 let byte_offset = self.vectors_offset + (idx * vbs) as u64;
262 let bytes = self
263 .handle
264 .read_bytes_range(byte_offset..byte_offset + vbs as u64)
265 .await?;
266 out[..vbs].copy_from_slice(bytes.as_slice());
267 Ok(())
268 }
269
270 pub async fn read_vectors_batch(
276 &self,
277 start_idx: usize,
278 count: usize,
279 ) -> io::Result<OwnedBytes> {
280 debug_assert!(start_idx + count <= self.num_vectors);
281 let vec_byte_len = self.dim * self.element_size;
282 let byte_offset = self.vectors_offset + (start_idx * vec_byte_len) as u64;
283 let byte_len = (count * vec_byte_len) as u64;
284 self.handle
285 .read_bytes_range(byte_offset..byte_offset + byte_len)
286 .await
287 }
288
289 pub fn flat_indexes_for_doc(&self, doc_id: u32) -> (usize, &[(u32, u16)]) {
297 let start = self.doc_ids.partition_point(|&(id, _)| id < doc_id);
298 let end = start + self.doc_ids[start..].partition_point(|&(id, _)| id == doc_id);
299 (start, &self.doc_ids[start..end])
300 }
301
302 #[inline]
304 pub fn get_doc_id(&self, idx: usize) -> (u32, u16) {
305 self.doc_ids[idx]
306 }
307
308 #[inline]
310 pub fn vector_byte_size(&self) -> usize {
311 self.dim * self.element_size
312 }
313
314 pub fn vector_bytes_len(&self) -> u64 {
316 (self.num_vectors as u64) * (self.vector_byte_size() as u64)
317 }
318
319 pub fn vectors_byte_offset(&self) -> u64 {
321 self.vectors_offset
322 }
323
324 pub fn handle(&self) -> &LazyFileSlice {
326 &self.handle
327 }
328
329 pub fn estimated_memory_bytes(&self) -> usize {
331 self.doc_ids.capacity() * size_of::<(u32, u16)>() + size_of::<Self>()
332 }
333}
334
335#[derive(Debug, Clone, Serialize, Deserialize)]
337pub struct IVFRaBitQIndexData {
338 pub index: crate::structures::IVFRaBitQIndex,
339 pub centroids: crate::structures::CoarseCentroids,
340 pub codebook: crate::structures::RaBitQCodebook,
341}
342
343impl IVFRaBitQIndexData {
344 pub fn to_bytes(&self) -> std::io::Result<Vec<u8>> {
345 serde_json::to_vec(self)
346 .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))
347 }
348
349 pub fn from_bytes(data: &[u8]) -> std::io::Result<Self> {
350 serde_json::from_slice(data)
351 .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))
352 }
353}
354
355#[derive(Debug, Clone, Serialize, Deserialize)]
357pub struct ScaNNIndexData {
358 pub index: crate::structures::IVFPQIndex,
359 pub centroids: crate::structures::CoarseCentroids,
360 pub codebook: crate::structures::PQCodebook,
361}
362
363impl ScaNNIndexData {
364 pub fn to_bytes(&self) -> std::io::Result<Vec<u8>> {
365 serde_json::to_vec(self)
366 .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))
367 }
368
369 pub fn from_bytes(data: &[u8]) -> std::io::Result<Self> {
370 serde_json::from_slice(data)
371 .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))
372 }
373}