1use crate::error::{QdrantError, QdrantResult};
12use crate::point::{Payload, PayloadValue, PointId, ScoredPoint};
13
14const WIRE_VARINT: u8 = 0;
19const WIRE_FIXED64: u8 = 1;
20const WIRE_LEN: u8 = 2;
21const WIRE_FIXED32: u8 = 5;
22
23const MAX_DECODE_DEPTH: usize = 32;
26const MAX_PROTO_FIELD_NUMBER: u64 = 536_870_911;
28
29fn ensure_non_empty_decoded_name(value: &str, label: &str) -> QdrantResult<()> {
30 if value.trim().is_empty() {
31 return Err(QdrantError::Decode(format!("{label} must not be empty")));
32 }
33 Ok(())
34}
35
36fn duplicate_decode_error(label: &str) -> QdrantError {
37 QdrantError::Decode(format!("Duplicate {label} fields in Qdrant response"))
38}
39
40fn set_decoded_point_id(
41 slot: &mut Option<PointId>,
42 next: PointId,
43 label: &str,
44) -> QdrantResult<()> {
45 if slot.is_some() {
46 return Err(duplicate_decode_error(label));
47 }
48 *slot = Some(next);
49 Ok(())
50}
51
52fn set_decoded_score(slot: &mut Option<f32>, next: f32, label: &str) -> QdrantResult<()> {
53 if slot.is_some() {
54 return Err(duplicate_decode_error(label));
55 }
56 *slot = Some(next);
57 Ok(())
58}
59
60fn set_decoded_string(slot: &mut Option<String>, next: String, label: &str) -> QdrantResult<()> {
61 if slot.is_some() {
62 return Err(duplicate_decode_error(label));
63 }
64 *slot = Some(next);
65 Ok(())
66}
67
68const SEARCH_RESULT: u32 = 1;
73
74const SCORED_POINT_ID: u32 = 1;
79const SCORED_POINT_PAYLOAD: u32 = 2;
80const SCORED_POINT_SCORE: u32 = 3;
81const SCORED_POINT_VECTORS: u32 = 6;
82
83const POINT_ID_NUM: u32 = 1;
88const POINT_ID_UUID: u32 = 2;
89
90const GET_RESULT: u32 = 1;
96
97const SCROLL_NEXT_OFFSET: u32 = 1;
99const SCROLL_RESULT: u32 = 2;
101
102const RETRIEVED_POINT_ID: u32 = 1;
104const RETRIEVED_POINT_PAYLOAD: u32 = 2;
105const RETRIEVED_POINT_VECTORS: u32 = 4;
106
107const VALUE_NULL: u32 = 1;
112const VALUE_DOUBLE: u32 = 2;
113const VALUE_INTEGER: u32 = 3;
114const VALUE_STRING: u32 = 4;
115const VALUE_BOOL: u32 = 5;
116const VALUE_STRUCT: u32 = 6;
117const VALUE_LIST: u32 = 7;
118
119const VECTORS_OUTPUT_VECTOR: u32 = 1;
124const VECTORS_OUTPUT_NAMED: u32 = 2;
125const NAMED_VECTORS_OUTPUT_ENTRY: u32 = 1;
126const NAMED_VECTOR_ENTRY_KEY: u32 = 1;
127const NAMED_VECTOR_ENTRY_VALUE: u32 = 2;
128const VECTOR_OUTPUT_DEPRECATED_DATA: u32 = 1;
129const VECTOR_OUTPUT_DENSE: u32 = 101;
130const DENSE_VECTOR_DATA: u32 = 1;
131
132#[inline]
138fn decode_varint(buf: &mut &[u8]) -> QdrantResult<u64> {
139 let mut result: u64 = 0;
140
141 for byte_index in 0..10 {
142 if buf.is_empty() {
143 return Err(QdrantError::Decode(
144 "Unexpected end of data in varint".to_string(),
145 ));
146 }
147
148 let byte = buf[0];
149 *buf = &buf[1..];
150 let payload = (byte & 0x7F) as u64;
151
152 if byte_index == 9 && payload > 1 {
153 return Err(QdrantError::Decode("Varint overflows u64".to_string()));
154 }
155
156 result |= payload << (byte_index * 7);
157
158 if byte & 0x80 == 0 {
159 return Ok(result);
160 }
161 }
162
163 Err(QdrantError::Decode("Varint too long".to_string()))
164}
165
166#[inline]
168fn decode_tag(buf: &mut &[u8]) -> QdrantResult<(u32, u8)> {
169 let tag = decode_varint(buf)?;
170 let field_number = tag >> 3;
171 if field_number == 0 || field_number > MAX_PROTO_FIELD_NUMBER {
172 return Err(QdrantError::Decode(format!(
173 "Invalid protobuf field number: {field_number}"
174 )));
175 }
176 let wire_type = (tag & 0x07) as u8;
177 Ok((field_number as u32, wire_type))
178}
179
180#[inline]
182fn skip_field(buf: &mut &[u8], wire_type: u8) -> QdrantResult<()> {
183 match wire_type {
184 WIRE_VARINT => {
185 decode_varint(buf)?;
186 }
187 WIRE_FIXED64 => {
188 if buf.len() < 8 {
189 return Err(QdrantError::Decode("Unexpected end of data".to_string()));
190 }
191 *buf = &buf[8..];
192 }
193 WIRE_LEN => {
194 let len = decode_varint(buf)? as usize;
195 if buf.len() < len {
196 return Err(QdrantError::Decode("Unexpected end of data".to_string()));
197 }
198 *buf = &buf[len..];
199 }
200 WIRE_FIXED32 => {
201 if buf.len() < 4 {
202 return Err(QdrantError::Decode("Unexpected end of data".to_string()));
203 }
204 *buf = &buf[4..];
205 }
206 _ => {
207 return Err(QdrantError::Decode(format!(
208 "Unknown wire type: {}",
209 wire_type
210 )));
211 }
212 }
213 Ok(())
214}
215
216#[inline]
218fn read_submessage<'a>(buf: &mut &'a [u8]) -> QdrantResult<&'a [u8]> {
219 let len = decode_varint(buf)? as usize;
220 if buf.len() < len {
221 return Err(QdrantError::Decode("Truncated submessage".to_string()));
222 }
223 let data = &buf[..len];
224 *buf = &buf[len..];
225 Ok(data)
226}
227
228fn read_fixed32_f32(buf: &mut &[u8], label: &str) -> QdrantResult<f32> {
229 if buf.len() < 4 {
230 return Err(QdrantError::Decode(format!("Truncated {label}")));
231 }
232 let bytes: [u8; 4] = buf[..4]
233 .try_into()
234 .map_err(|_| QdrantError::Decode(format!("Truncated {label}")))?;
235 let value = f32::from_le_bytes(bytes);
236 if !value.is_finite() {
237 return Err(QdrantError::Decode(format!("Invalid non-finite {label}")));
238 }
239 *buf = &buf[4..];
240 Ok(value)
241}
242
243pub fn decode_search_response(data: &[u8]) -> QdrantResult<Vec<ScoredPoint>> {
254 let mut results = Vec::new();
255 let mut buf = data;
256
257 while !buf.is_empty() {
258 let (field_number, wire_type) = decode_tag(&mut buf)?;
259
260 match field_number {
261 SEARCH_RESULT => {
262 if wire_type != WIRE_LEN {
263 return Err(QdrantError::Decode(
264 "Expected length-delimited for ScoredPoint".to_string(),
265 ));
266 }
267 let point_data = read_submessage(&mut buf)?;
268 let point = decode_scored_point(point_data)?;
269 results.push(point);
270 }
271 _ => {
272 skip_field(&mut buf, wire_type)?;
273 }
274 }
275 }
276
277 Ok(results)
278}
279
280fn decode_scored_point(data: &[u8]) -> QdrantResult<ScoredPoint> {
282 let mut id = None;
283 let mut score = None;
284 let mut payload = Payload::new();
285 let mut vector = None;
286 let mut buf = data;
287
288 while !buf.is_empty() {
289 let (field_number, wire_type) = decode_tag(&mut buf)?;
290
291 match field_number {
292 SCORED_POINT_ID => {
293 if wire_type != WIRE_LEN {
294 skip_field(&mut buf, wire_type)?;
295 continue;
296 }
297 let id_data = read_submessage(&mut buf)?;
298 set_decoded_point_id(&mut id, decode_point_id(id_data)?, "scored point id")?;
299 }
300 SCORED_POINT_PAYLOAD => {
301 if wire_type != WIRE_LEN {
302 skip_field(&mut buf, wire_type)?;
303 continue;
304 }
305 let entry_data = read_submessage(&mut buf)?;
306 let (key, value) = decode_map_entry(entry_data, 0)?;
308 insert_payload_entry(&mut payload, key, value, "scored point payload")?;
309 }
310 SCORED_POINT_SCORE => {
311 if wire_type != WIRE_FIXED32 {
312 skip_field(&mut buf, wire_type)?;
313 continue;
314 }
315 let decoded_score = read_fixed32_f32(&mut buf, "score value")?;
316 set_decoded_score(&mut score, decoded_score, "scored point score")?;
317 }
318 SCORED_POINT_VECTORS => {
319 if wire_type != WIRE_LEN {
320 skip_field(&mut buf, wire_type)?;
321 continue;
322 }
323 let vec_data = read_submessage(&mut buf)?;
324 if let Some(next) = decode_vectors(vec_data)? {
325 set_decoded_vector(&mut vector, next)?;
326 }
327 }
328 _ => {
329 skip_field(&mut buf, wire_type)?;
330 }
331 }
332 }
333
334 let id = id.ok_or_else(|| QdrantError::Decode("Missing point id".to_string()))?;
335
336 Ok(ScoredPoint {
337 id,
338 score: score.unwrap_or(0.0),
339 payload,
340 vector,
341 })
342}
343
344pub fn decode_get_response(data: &[u8]) -> QdrantResult<Vec<ScoredPoint>> {
353 let mut results = Vec::new();
354 let mut buf = data;
355
356 while !buf.is_empty() {
357 let (field_number, wire_type) = decode_tag(&mut buf)?;
358
359 match field_number {
360 GET_RESULT => {
361 if wire_type != WIRE_LEN {
362 skip_field(&mut buf, wire_type)?;
363 continue;
364 }
365 let point_data = read_submessage(&mut buf)?;
366 let point = decode_retrieved_point(point_data)?;
367 results.push(point);
368 }
369 _ => {
370 skip_field(&mut buf, wire_type)?;
371 }
372 }
373 }
374
375 Ok(results)
376}
377
378pub struct ScrollResult {
384 pub points: Vec<ScoredPoint>,
386 pub next_offset: Option<PointId>,
388}
389
390pub fn decode_scroll_response(data: &[u8]) -> QdrantResult<ScrollResult> {
392 let mut points = Vec::new();
393 let mut next_offset = None;
394 let mut buf = data;
395
396 while !buf.is_empty() {
397 let (field_number, wire_type) = decode_tag(&mut buf)?;
398
399 match field_number {
400 SCROLL_RESULT => {
401 if wire_type != WIRE_LEN {
402 skip_field(&mut buf, wire_type)?;
403 continue;
404 }
405 let point_data = read_submessage(&mut buf)?;
406 let point = decode_retrieved_point(point_data)?;
407 points.push(point);
408 }
409 SCROLL_NEXT_OFFSET => {
410 if wire_type != WIRE_LEN {
411 skip_field(&mut buf, wire_type)?;
412 continue;
413 }
414 let id_data = read_submessage(&mut buf)?;
415 set_decoded_point_id(
416 &mut next_offset,
417 decode_point_id(id_data)?,
418 "scroll next offset",
419 )?;
420 }
421 _ => {
422 skip_field(&mut buf, wire_type)?;
423 }
424 }
425 }
426
427 Ok(ScrollResult {
428 points,
429 next_offset,
430 })
431}
432
433fn decode_retrieved_point(data: &[u8]) -> QdrantResult<ScoredPoint> {
435 let mut id = None;
436 let mut payload = Payload::new();
437 let mut vector = None;
438 let mut buf = data;
439
440 while !buf.is_empty() {
441 let (field_number, wire_type) = decode_tag(&mut buf)?;
442
443 match field_number {
444 RETRIEVED_POINT_ID => {
445 if wire_type != WIRE_LEN {
446 skip_field(&mut buf, wire_type)?;
447 continue;
448 }
449 let id_data = read_submessage(&mut buf)?;
450 set_decoded_point_id(&mut id, decode_point_id(id_data)?, "retrieved point id")?;
451 }
452 RETRIEVED_POINT_PAYLOAD => {
453 if wire_type != WIRE_LEN {
454 skip_field(&mut buf, wire_type)?;
455 continue;
456 }
457 let entry_data = read_submessage(&mut buf)?;
458 let (key, value) = decode_map_entry(entry_data, 0)?;
459 insert_payload_entry(&mut payload, key, value, "retrieved point payload")?;
460 }
461 RETRIEVED_POINT_VECTORS => {
462 if wire_type != WIRE_LEN {
463 skip_field(&mut buf, wire_type)?;
464 continue;
465 }
466 let vec_data = read_submessage(&mut buf)?;
467 if let Some(next) = decode_vectors(vec_data)? {
468 set_decoded_vector(&mut vector, next)?;
469 }
470 }
471 _ => {
472 skip_field(&mut buf, wire_type)?;
473 }
474 }
475 }
476
477 let id = id.ok_or_else(|| QdrantError::Decode("Missing point id".to_string()))?;
478
479 Ok(ScoredPoint {
480 id,
481 score: 0.0,
482 payload,
483 vector,
484 })
485}
486
487fn decode_map_entry(data: &[u8], depth: usize) -> QdrantResult<(String, PayloadValue)> {
501 let mut key = None;
502 let mut value = None;
503 let mut buf = data;
504
505 while !buf.is_empty() {
506 let (field_number, wire_type) = decode_tag(&mut buf)?;
507
508 match field_number {
509 1 => {
510 if wire_type != WIRE_LEN {
512 return Err(QdrantError::Decode(
513 "Invalid wire type for payload map key".to_string(),
514 ));
515 }
516 let s_data = read_submessage(&mut buf)?;
517 let decoded_key = std::str::from_utf8(s_data).map_err(|e| {
518 QdrantError::Decode(format!("Invalid UTF-8 payload map key: {}", e))
519 })?;
520 set_decoded_string(&mut key, decoded_key.to_string(), "payload map key")?;
521 }
522 2 => {
523 if wire_type != WIRE_LEN {
525 return Err(QdrantError::Decode(
526 "Invalid wire type for payload map value".to_string(),
527 ));
528 }
529 let v_data = read_submessage(&mut buf)?;
530 set_decoded_payload_value(
531 &mut value,
532 decode_value_with_depth(v_data, depth)?,
533 "payload map value",
534 )?;
535 }
536 _ => {
537 skip_field(&mut buf, wire_type)?;
538 }
539 }
540 }
541
542 let key = key.ok_or_else(|| QdrantError::Decode("Missing payload map key".to_string()))?;
543 ensure_non_empty_decoded_name(&key, "Payload map key")?;
544 let value =
545 value.ok_or_else(|| QdrantError::Decode("Missing payload map value".to_string()))?;
546 Ok((key, value))
547}
548
549fn insert_payload_entry(
550 payload: &mut Payload,
551 key: String,
552 value: PayloadValue,
553 label: &str,
554) -> QdrantResult<()> {
555 if payload.contains_key(&key) {
556 return Err(QdrantError::Decode(format!(
557 "Duplicate payload key in {label}: {key}"
558 )));
559 }
560 payload.insert(key, value);
561 Ok(())
562}
563
564fn set_decoded_payload_value(
565 slot: &mut Option<PayloadValue>,
566 next: PayloadValue,
567 label: &str,
568) -> QdrantResult<()> {
569 if slot.is_some() {
570 return Err(duplicate_decode_error(label));
571 }
572 *slot = Some(next);
573 Ok(())
574}
575
576#[cfg(test)]
592fn decode_value(data: &[u8]) -> QdrantResult<PayloadValue> {
593 decode_value_with_depth(data, 0)
594}
595
596fn decode_value_with_depth(data: &[u8], depth: usize) -> QdrantResult<PayloadValue> {
598 if depth > MAX_DECODE_DEPTH {
599 return Err(QdrantError::Decode(
600 "Payload value nesting exceeds maximum depth".to_string(),
601 ));
602 }
603
604 let mut value = None;
605 let mut buf = data;
606
607 while !buf.is_empty() {
608 let (field_number, wire_type) = decode_tag(&mut buf)?;
609
610 match field_number {
611 VALUE_NULL => {
612 if wire_type == WIRE_VARINT {
614 let v = decode_varint(&mut buf)?;
615 if v != 0 {
616 return Err(QdrantError::Decode(format!(
617 "Invalid payload null enum value: {v}"
618 )));
619 }
620 } else {
621 return Err(QdrantError::Decode(
622 "Invalid wire type for payload null value".to_string(),
623 ));
624 }
625 set_decoded_payload_value(&mut value, PayloadValue::Null, "payload value kind")?;
626 }
627 VALUE_DOUBLE => {
628 if wire_type != WIRE_FIXED64 {
630 return Err(QdrantError::Decode(
631 "Invalid wire type for payload double value".to_string(),
632 ));
633 }
634 if buf.len() < 8 {
635 return Err(QdrantError::Decode(
636 "Truncated payload double value".to_string(),
637 ));
638 }
639 let bytes: [u8; 8] = buf[..8].try_into().map_err(|_| {
640 QdrantError::Decode("Truncated payload double value".to_string())
641 })?;
642 let float_value = f64::from_le_bytes(bytes);
643 buf = &buf[8..];
644 if !float_value.is_finite() {
645 return Err(QdrantError::Decode(
646 "Invalid non-finite payload float value".to_string(),
647 ));
648 }
649 set_decoded_payload_value(
650 &mut value,
651 PayloadValue::Float(float_value),
652 "payload value kind",
653 )?;
654 }
655 VALUE_INTEGER => {
656 if wire_type != WIRE_VARINT {
658 return Err(QdrantError::Decode(
659 "Invalid wire type for payload integer value".to_string(),
660 ));
661 }
662 let n = decode_varint(&mut buf)? as i64;
663 set_decoded_payload_value(
664 &mut value,
665 PayloadValue::Integer(n),
666 "payload value kind",
667 )?;
668 }
669 VALUE_STRING => {
670 if wire_type != WIRE_LEN {
672 return Err(QdrantError::Decode(
673 "Invalid wire type for payload string value".to_string(),
674 ));
675 }
676 let s_data = read_submessage(&mut buf)?;
677 let s = std::str::from_utf8(s_data)
678 .map_err(|e| {
679 QdrantError::Decode(format!("Invalid UTF-8 payload string: {}", e))
680 })?
681 .to_string();
682 set_decoded_payload_value(
683 &mut value,
684 PayloadValue::String(s),
685 "payload value kind",
686 )?;
687 }
688 VALUE_BOOL => {
689 if wire_type != WIRE_VARINT {
691 return Err(QdrantError::Decode(
692 "Invalid wire type for payload bool value".to_string(),
693 ));
694 }
695 let v = decode_varint(&mut buf)?;
696 if v > 1 {
697 return Err(QdrantError::Decode(format!(
698 "Invalid payload bool value: {v}"
699 )));
700 }
701 set_decoded_payload_value(
702 &mut value,
703 PayloadValue::Bool(v != 0),
704 "payload value kind",
705 )?;
706 }
707 VALUE_STRUCT => {
708 if wire_type != WIRE_LEN {
710 return Err(QdrantError::Decode(
711 "Invalid wire type for payload object value".to_string(),
712 ));
713 }
714 let struct_data = read_submessage(&mut buf)?;
715 let map = decode_struct_fields_with_depth(struct_data, depth + 1)?;
716 set_decoded_payload_value(
717 &mut value,
718 PayloadValue::Object(map),
719 "payload value kind",
720 )?;
721 }
722 VALUE_LIST => {
723 if wire_type != WIRE_LEN {
725 return Err(QdrantError::Decode(
726 "Invalid wire type for payload list value".to_string(),
727 ));
728 }
729 let list_data = read_submessage(&mut buf)?;
730 let items = decode_list_values_with_depth(list_data, depth + 1)?;
731 set_decoded_payload_value(
732 &mut value,
733 PayloadValue::List(items),
734 "payload value kind",
735 )?;
736 }
737 _ => {
738 skip_field(&mut buf, wire_type)?;
739 }
740 }
741 }
742
743 value.ok_or_else(|| QdrantError::Decode("Missing payload value kind".to_string()))
744}
745
746fn decode_struct_fields_with_depth(
748 data: &[u8],
749 depth: usize,
750) -> QdrantResult<std::collections::HashMap<String, PayloadValue>> {
751 let mut map = std::collections::HashMap::new();
752 if depth > MAX_DECODE_DEPTH {
753 return Err(QdrantError::Decode(
754 "Payload object nesting exceeds maximum depth".to_string(),
755 ));
756 }
757 let mut buf = data;
758
759 while !buf.is_empty() {
760 let (field_number, wire_type) = decode_tag(&mut buf)?;
761 match field_number {
762 1 => {
763 if wire_type != WIRE_LEN {
765 return Err(QdrantError::Decode(
766 "Invalid wire type for payload object field".to_string(),
767 ));
768 }
769 let entry_data = read_submessage(&mut buf)?;
770 let (key, value) = decode_map_entry(entry_data, depth)?;
771 insert_payload_entry(&mut map, key, value, "payload object")?;
772 }
773 _ => {
774 skip_field(&mut buf, wire_type)?;
775 }
776 }
777 }
778
779 Ok(map)
780}
781
782fn decode_list_values_with_depth(data: &[u8], depth: usize) -> QdrantResult<Vec<PayloadValue>> {
784 let mut items = Vec::new();
785 if depth > MAX_DECODE_DEPTH {
786 return Err(QdrantError::Decode(
787 "Payload list nesting exceeds maximum depth".to_string(),
788 ));
789 }
790 let mut buf = data;
791
792 while !buf.is_empty() {
793 let (field_number, wire_type) = decode_tag(&mut buf)?;
794 match field_number {
795 1 => {
796 if wire_type != WIRE_LEN {
798 return Err(QdrantError::Decode(
799 "Invalid wire type for payload list item".to_string(),
800 ));
801 }
802 let v_data = read_submessage(&mut buf)?;
803 let value = decode_value_with_depth(v_data, depth)?;
804 items.push(value);
805 }
806 _ => {
807 skip_field(&mut buf, wire_type)?;
808 }
809 }
810 }
811
812 Ok(items)
813}
814
815fn decode_vectors(data: &[u8]) -> QdrantResult<Option<Vec<f32>>> {
834 let mut vector = None;
835 let mut buf = data;
836
837 while !buf.is_empty() {
838 let (field_number, wire_type) = decode_tag(&mut buf)?;
839 match field_number {
840 VECTORS_OUTPUT_VECTOR => {
841 if wire_type != WIRE_LEN {
842 skip_field(&mut buf, wire_type)?;
843 continue;
844 }
845 let vec_data = read_submessage(&mut buf)?;
846 if let Some(next) = decode_vector_output(vec_data)? {
847 set_decoded_vector(&mut vector, next)?;
848 }
849 }
850 VECTORS_OUTPUT_NAMED => {
851 if wire_type != WIRE_LEN {
852 skip_field(&mut buf, wire_type)?;
853 continue;
854 }
855 let vectors_data = read_submessage(&mut buf)?;
856 if let Some(next) = decode_named_vectors_output(vectors_data)? {
857 set_decoded_vector(&mut vector, next)?;
858 }
859 }
860 _ => {
861 skip_field(&mut buf, wire_type)?;
862 }
863 }
864 }
865
866 Ok(vector)
867}
868
869fn set_decoded_vector(slot: &mut Option<Vec<f32>>, next: Vec<f32>) -> QdrantResult<()> {
870 if let Some(existing) = slot
871 && existing != &next
872 {
873 return Err(QdrantError::Decode(
874 "Conflicting vector outputs in Qdrant response".to_string(),
875 ));
876 }
877 *slot = Some(next);
878 Ok(())
879}
880
881fn append_decoded_vector(slot: &mut Option<Vec<f32>>, mut next: Vec<f32>) {
882 slot.get_or_insert_with(Vec::new).append(&mut next);
883}
884
885fn append_decoded_vector_value(slot: &mut Option<Vec<f32>>, next: f32) {
886 slot.get_or_insert_with(Vec::new).push(next);
887}
888
889fn decode_vector_output(data: &[u8]) -> QdrantResult<Option<Vec<f32>>> {
891 let mut deprecated_vector = None;
892 let mut dense_vector = None;
893 let mut buf = data;
894
895 while !buf.is_empty() {
896 let (field_number, wire_type) = decode_tag(&mut buf)?;
897 match field_number {
898 VECTOR_OUTPUT_DEPRECATED_DATA => match wire_type {
899 WIRE_LEN => {
900 let float_data = read_submessage(&mut buf)?;
901 append_decoded_vector(
902 &mut deprecated_vector,
903 decode_packed_f32_vector(float_data)?,
904 );
905 }
906 WIRE_FIXED32 => {
907 let value = read_fixed32_f32(&mut buf, "vector value")?;
908 append_decoded_vector_value(&mut deprecated_vector, value);
909 }
910 _ => {
911 skip_field(&mut buf, wire_type)?;
912 }
913 },
914 VECTOR_OUTPUT_DENSE => {
915 if wire_type != WIRE_LEN {
916 skip_field(&mut buf, wire_type)?;
917 continue;
918 }
919 let dense_data = read_submessage(&mut buf)?;
920 if let Some(next) = decode_dense_vector(dense_data)? {
921 set_decoded_vector(&mut dense_vector, next)?;
922 }
923 }
924 _ => {
925 skip_field(&mut buf, wire_type)?;
926 }
927 }
928 }
929
930 let mut vector = None;
931 if let Some(next) = deprecated_vector {
932 set_decoded_vector(&mut vector, next)?;
933 }
934 if let Some(next) = dense_vector {
935 set_decoded_vector(&mut vector, next)?;
936 }
937 Ok(vector)
938}
939
940fn decode_dense_vector(data: &[u8]) -> QdrantResult<Option<Vec<f32>>> {
942 let mut vector = None;
943 let mut buf = data;
944
945 while !buf.is_empty() {
946 let (field_number, wire_type) = decode_tag(&mut buf)?;
947 match field_number {
948 DENSE_VECTOR_DATA => match wire_type {
949 WIRE_LEN => {
950 let float_data = read_submessage(&mut buf)?;
951 append_decoded_vector(&mut vector, decode_packed_f32_vector(float_data)?);
952 }
953 WIRE_FIXED32 => {
954 let value = read_fixed32_f32(&mut buf, "vector value")?;
955 append_decoded_vector_value(&mut vector, value);
956 }
957 _ => {
958 skip_field(&mut buf, wire_type)?;
959 }
960 },
961 _ => {
962 skip_field(&mut buf, wire_type)?;
963 }
964 }
965 }
966
967 Ok(vector)
968}
969
970fn decode_named_vectors_output(data: &[u8]) -> QdrantResult<Option<Vec<f32>>> {
971 let mut vector = None;
972 let mut buf = data;
973
974 while !buf.is_empty() {
975 let (field_number, wire_type) = decode_tag(&mut buf)?;
976 match field_number {
977 NAMED_VECTORS_OUTPUT_ENTRY => {
978 if wire_type != WIRE_LEN {
979 skip_field(&mut buf, wire_type)?;
980 continue;
981 }
982 let entry_data = read_submessage(&mut buf)?;
983 if let Some(next) = decode_named_vector_output_entry(entry_data)? {
984 if vector.is_some() {
985 return Err(QdrantError::Decode(
986 "Multiple named vectors cannot be represented as a single dense vector"
987 .to_string(),
988 ));
989 }
990 vector = Some(next);
991 }
992 }
993 _ => {
994 skip_field(&mut buf, wire_type)?;
995 }
996 }
997 }
998
999 Ok(vector)
1000}
1001
1002fn decode_named_vector_output_entry(data: &[u8]) -> QdrantResult<Option<Vec<f32>>> {
1003 let mut key = None;
1004 let mut vector = None;
1005 let mut buf = data;
1006
1007 while !buf.is_empty() {
1008 let (field_number, wire_type) = decode_tag(&mut buf)?;
1009 match field_number {
1010 NAMED_VECTOR_ENTRY_KEY => {
1011 if wire_type != WIRE_LEN {
1012 return Err(QdrantError::Decode(
1013 "Invalid wire type for named vector key".to_string(),
1014 ));
1015 }
1016 let key_data = read_submessage(&mut buf)?;
1017 let decoded_key = std::str::from_utf8(key_data).map_err(|e| {
1018 QdrantError::Decode(format!("Invalid UTF-8 named vector key: {e}"))
1019 })?;
1020 ensure_non_empty_decoded_name(decoded_key, "Named vector key")?;
1021 set_decoded_string(&mut key, decoded_key.to_string(), "named vector key")?;
1022 }
1023 NAMED_VECTOR_ENTRY_VALUE => {
1024 if wire_type != WIRE_LEN {
1025 return Err(QdrantError::Decode(
1026 "Invalid wire type for named vector value".to_string(),
1027 ));
1028 }
1029 let value_data = read_submessage(&mut buf)?;
1030 if let Some(next) = decode_vector_output(value_data)? {
1031 set_decoded_vector(&mut vector, next)?;
1032 }
1033 }
1034 _ => {
1035 skip_field(&mut buf, wire_type)?;
1036 }
1037 }
1038 }
1039
1040 if vector.is_some() && key.is_none() {
1041 return Err(QdrantError::Decode("Missing named vector key".to_string()));
1042 }
1043
1044 Ok(vector)
1045}
1046
1047fn decode_packed_f32_vector(float_data: &[u8]) -> QdrantResult<Vec<f32>> {
1048 if float_data.is_empty() {
1049 return Err(QdrantError::Decode("Empty vector data".to_string()));
1050 }
1051 if !float_data.len().is_multiple_of(4) {
1052 return Err(QdrantError::Decode(
1053 "Invalid vector data length".to_string(),
1054 ));
1055 }
1056 let count = float_data.len() / 4;
1057 let mut result = Vec::with_capacity(count);
1058 for i in 0..count {
1059 let offset = i * 4;
1060 let bytes: [u8; 4] = float_data[offset..offset + 4]
1061 .try_into()
1062 .map_err(|_| QdrantError::Decode("Invalid vector data length".to_string()))?;
1063 let value = f32::from_le_bytes(bytes);
1064 if !value.is_finite() {
1065 return Err(QdrantError::Decode(
1066 "Invalid non-finite vector value".to_string(),
1067 ));
1068 }
1069 result.push(value);
1070 }
1071 Ok(result)
1072}
1073
1074fn decode_point_id(data: &[u8]) -> QdrantResult<PointId> {
1080 let mut id = None;
1081 let mut buf = data;
1082
1083 while !buf.is_empty() {
1084 let (field_number, wire_type) = decode_tag(&mut buf)?;
1085
1086 match field_number {
1087 POINT_ID_NUM => {
1088 if wire_type != WIRE_VARINT {
1089 skip_field(&mut buf, wire_type)?;
1090 continue;
1091 }
1092 let num = decode_varint(&mut buf)?;
1093 set_decoded_point_id(&mut id, PointId::Num(num), "point id")?;
1094 }
1095 POINT_ID_UUID => {
1096 if wire_type != WIRE_LEN {
1097 skip_field(&mut buf, wire_type)?;
1098 continue;
1099 }
1100 let uuid_data = read_submessage(&mut buf)?;
1101 let uuid_str = std::str::from_utf8(uuid_data)
1102 .map_err(|e| QdrantError::Decode(format!("Invalid UTF-8: {}", e)))?;
1103 ensure_non_empty_decoded_name(uuid_str, "Point UUID")?;
1104 set_decoded_point_id(&mut id, PointId::Uuid(uuid_str.to_string()), "point id")?;
1105 }
1106 _ => {
1107 skip_field(&mut buf, wire_type)?;
1108 }
1109 }
1110 }
1111
1112 id.ok_or_else(|| QdrantError::Decode("Missing point id".to_string()))
1113}
1114
1115#[cfg(test)]
1120mod tests {
1121 use super::*;
1122
1123 #[test]
1124 fn test_decode_varint() {
1125 let mut buf: &[u8] = &[0x01];
1126 assert_eq!(decode_varint(&mut buf).unwrap(), 1);
1127 assert!(buf.is_empty());
1128
1129 let mut buf: &[u8] = &[0xAC, 0x02];
1130 assert_eq!(decode_varint(&mut buf).unwrap(), 300);
1131 assert!(buf.is_empty());
1132 }
1133
1134 #[test]
1135 fn test_decode_varint_rejects_u64_overflow() {
1136 let mut data = [0xFF; 10];
1137 data[9] = 0x7F;
1138 let mut buf: &[u8] = &data;
1139
1140 let err = decode_varint(&mut buf).unwrap_err();
1141 assert!(err.to_string().contains("overflows u64"));
1142 }
1143
1144 #[test]
1145 fn test_decode_varint_rejects_unterminated_tenth_byte() {
1146 let data = [0x80; 10];
1147 let mut buf: &[u8] = &data;
1148
1149 let err = decode_varint(&mut buf).unwrap_err();
1150 assert!(err.to_string().contains("Varint too long"));
1151 }
1152
1153 #[test]
1154 fn test_decode_tag() {
1155 let mut buf: &[u8] = &[0x0A];
1156 let (field, wire) = decode_tag(&mut buf).unwrap();
1157 assert_eq!(field, 1);
1158 assert_eq!(wire, WIRE_LEN);
1159
1160 let mut buf: &[u8] = &[0x1D];
1161 let (field, wire) = decode_tag(&mut buf).unwrap();
1162 assert_eq!(field, 3);
1163 assert_eq!(wire, WIRE_FIXED32);
1164 }
1165
1166 #[test]
1167 fn test_decode_tag_rejects_zero_field_number() {
1168 let mut buf: &[u8] = &[0x00];
1169
1170 let err = decode_tag(&mut buf).unwrap_err();
1171 assert!(err.to_string().contains("Invalid protobuf field number"));
1172 }
1173
1174 #[test]
1175 fn test_decode_tag_rejects_oversized_field_number() {
1176 let mut value = ((MAX_PROTO_FIELD_NUMBER + 1) << 3) | u64::from(WIRE_LEN);
1177 let mut encoded = Vec::new();
1178 while value >= 0x80 {
1179 encoded.push(((value as u8) & 0x7F) | 0x80);
1180 value >>= 7;
1181 }
1182 encoded.push(value as u8);
1183
1184 let mut buf: &[u8] = &encoded;
1185 let err = decode_tag(&mut buf).unwrap_err();
1186 assert!(err.to_string().contains("Invalid protobuf field number"));
1187 }
1188
1189 #[test]
1190 fn test_decode_point_id_num() {
1191 let data = &[0x08, 0x2A];
1192 let id = decode_point_id(data).unwrap();
1193 assert_eq!(id, PointId::Num(42));
1194 }
1195
1196 #[test]
1197 fn test_decode_point_id_explicit_zero() {
1198 let data = &[0x08, 0x00];
1199 let id = decode_point_id(data).unwrap();
1200 assert_eq!(id, PointId::Num(0));
1201 }
1202
1203 #[test]
1204 fn test_decode_point_id_rejects_empty_message() {
1205 let err = decode_point_id(&[]).unwrap_err();
1206 assert!(err.to_string().contains("Missing point id"));
1207 }
1208
1209 #[test]
1210 fn test_decode_point_id_uuid() {
1211 let data = &[0x12, 0x03, b'a', b'b', b'c'];
1212 let id = decode_point_id(data).unwrap();
1213 assert_eq!(id, PointId::Uuid("abc".to_string()));
1214 }
1215
1216 #[test]
1217 fn test_decode_point_id_rejects_duplicate_fields() {
1218 let duplicate_num = &[0x08, 0x01, 0x08, 0x02];
1219 let err = decode_point_id(duplicate_num).unwrap_err();
1220 assert!(err.to_string().contains("Duplicate point id"));
1221
1222 let conflicting_oneof = &[0x08, 0x01, 0x12, 0x03, b'a', b'b', b'c'];
1223 let err = decode_point_id(conflicting_oneof).unwrap_err();
1224 assert!(err.to_string().contains("Duplicate point id"));
1225 }
1226
1227 #[test]
1228 fn test_decode_point_id_rejects_empty_uuid() {
1229 let empty = &[0x12, 0x00];
1230 let err = decode_point_id(empty).unwrap_err();
1231 assert!(err.to_string().contains("Point UUID"));
1232
1233 let blank = &[0x12, 0x01, b' '];
1234 let err = decode_point_id(blank).unwrap_err();
1235 assert!(err.to_string().contains("Point UUID"));
1236 }
1237
1238 #[test]
1239 fn test_decode_scored_point() {
1240 let score_bytes = 0.5f32.to_le_bytes();
1241 let data = &[
1242 0x0A,
1243 0x02,
1244 0x08,
1245 0x01, 0x1D,
1247 score_bytes[0],
1248 score_bytes[1],
1249 score_bytes[2],
1250 score_bytes[3],
1251 ];
1252
1253 let point = decode_scored_point(data).unwrap();
1254 assert_eq!(point.id, PointId::Num(1));
1255 assert!((point.score - 0.5).abs() < 0.0001);
1256 }
1257
1258 fn push_len_field(out: &mut Vec<u8>, tag: u8, body: &[u8]) {
1259 assert!(body.len() < 128, "test helper only handles short bodies");
1260 out.push(tag);
1261 out.push(body.len() as u8);
1262 out.extend_from_slice(body);
1263 }
1264
1265 fn packed_f32(values: &[f32]) -> Vec<u8> {
1266 let mut bytes = Vec::with_capacity(values.len() * 4);
1267 for value in values {
1268 bytes.extend_from_slice(&value.to_le_bytes());
1269 }
1270 bytes
1271 }
1272
1273 fn current_dense_vectors_output(values: &[f32]) -> Vec<u8> {
1274 let floats = packed_f32(values);
1275
1276 let mut dense = Vec::new();
1277 push_len_field(&mut dense, 0x0A, &floats);
1278
1279 let mut vector_output = Vec::new();
1280 vector_output.extend_from_slice(&[0xAA, 0x06]);
1281 vector_output.push(dense.len() as u8);
1282 vector_output.extend_from_slice(&dense);
1283
1284 let mut vectors_output = Vec::new();
1285 push_len_field(&mut vectors_output, 0x0A, &vector_output);
1286 vectors_output
1287 }
1288
1289 fn deprecated_dense_vectors_output(values: &[f32]) -> Vec<u8> {
1290 let floats = packed_f32(values);
1291
1292 let mut vector_output = Vec::new();
1293 push_len_field(&mut vector_output, 0x0A, &floats);
1294
1295 let mut vectors_output = Vec::new();
1296 push_len_field(&mut vectors_output, 0x0A, &vector_output);
1297 vectors_output
1298 }
1299
1300 fn current_dense_vectors_output_unpacked(values: &[f32]) -> Vec<u8> {
1301 let mut dense = Vec::new();
1302 for value in values {
1303 dense.push(0x0D);
1304 dense.extend_from_slice(&value.to_le_bytes());
1305 }
1306
1307 let mut vector_output = Vec::new();
1308 vector_output.extend_from_slice(&[0xAA, 0x06]);
1309 vector_output.push(dense.len() as u8);
1310 vector_output.extend_from_slice(&dense);
1311
1312 let mut vectors_output = Vec::new();
1313 push_len_field(&mut vectors_output, 0x0A, &vector_output);
1314 vectors_output
1315 }
1316
1317 fn deprecated_dense_vectors_output_unpacked(values: &[f32]) -> Vec<u8> {
1318 let mut vector_output = Vec::new();
1319 for value in values {
1320 vector_output.push(0x0D);
1321 vector_output.extend_from_slice(&value.to_le_bytes());
1322 }
1323
1324 let mut vectors_output = Vec::new();
1325 push_len_field(&mut vectors_output, 0x0A, &vector_output);
1326 vectors_output
1327 }
1328
1329 fn named_dense_vectors_output(name: &str, values: &[f32]) -> Vec<u8> {
1330 let vectors_output = current_dense_vectors_output(values);
1331 let vector_output = &vectors_output[2..];
1332
1333 let mut entry = Vec::new();
1334 push_len_field(&mut entry, 0x0A, name.as_bytes());
1335 push_len_field(&mut entry, 0x12, vector_output);
1336
1337 let mut named = Vec::new();
1338 push_len_field(&mut named, 0x0A, &entry);
1339
1340 let mut output = Vec::new();
1341 push_len_field(&mut output, 0x12, &named);
1342 output
1343 }
1344
1345 fn scored_point_with_vectors(vectors_output: &[u8]) -> Vec<u8> {
1346 let score_bytes = 0.5f32.to_le_bytes();
1347 let mut data = vec![
1348 0x0A,
1349 0x02,
1350 0x08,
1351 0x01, 0x1D,
1353 score_bytes[0],
1354 score_bytes[1],
1355 score_bytes[2],
1356 score_bytes[3],
1357 ];
1358 push_len_field(&mut data, 0x32, vectors_output);
1359 data
1360 }
1361
1362 fn payload_string_entry(key: &str, value: &str) -> Vec<u8> {
1363 let mut value_message = Vec::new();
1364 push_len_field(&mut value_message, 0x22, value.as_bytes());
1365
1366 let mut entry = Vec::new();
1367 push_len_field(&mut entry, 0x0A, key.as_bytes());
1368 push_len_field(&mut entry, 0x12, &value_message);
1369 entry
1370 }
1371
1372 #[test]
1373 fn test_decode_search_response_accepts_current_dense_vector_output() {
1374 let scored_point = scored_point_with_vectors(¤t_dense_vectors_output(&[0.25, 0.75]));
1375 let mut data = Vec::new();
1376 push_len_field(&mut data, 0x0A, &scored_point);
1377
1378 let points = decode_search_response(&data).unwrap();
1379
1380 assert_eq!(points.len(), 1);
1381 assert_eq!(points[0].vector, Some(vec![0.25, 0.75]));
1382 }
1383
1384 #[test]
1385 fn test_decode_search_response_accepts_unpacked_current_dense_vector_output() {
1386 let scored_point =
1387 scored_point_with_vectors(¤t_dense_vectors_output_unpacked(&[0.25, 0.75]));
1388 let mut data = Vec::new();
1389 push_len_field(&mut data, 0x0A, &scored_point);
1390
1391 let points = decode_search_response(&data).unwrap();
1392
1393 assert_eq!(points.len(), 1);
1394 assert_eq!(points[0].vector, Some(vec![0.25, 0.75]));
1395 }
1396
1397 #[test]
1398 fn test_decode_scored_point_accepts_deprecated_dense_vector_output() {
1399 let data = scored_point_with_vectors(&deprecated_dense_vectors_output(&[0.25, 0.75]));
1400
1401 let point = decode_scored_point(&data).unwrap();
1402
1403 assert_eq!(point.vector, Some(vec![0.25, 0.75]));
1404 }
1405
1406 #[test]
1407 fn test_decode_scored_point_accepts_unpacked_deprecated_dense_vector_output() {
1408 let data =
1409 scored_point_with_vectors(&deprecated_dense_vectors_output_unpacked(&[0.25, 0.75]));
1410
1411 let point = decode_scored_point(&data).unwrap();
1412
1413 assert_eq!(point.vector, Some(vec![0.25, 0.75]));
1414 }
1415
1416 #[test]
1417 fn test_decode_scored_point_accepts_split_packed_dense_vector_chunks() {
1418 let mut dense = Vec::new();
1419 push_len_field(&mut dense, 0x0A, &packed_f32(&[0.25]));
1420 push_len_field(&mut dense, 0x0A, &packed_f32(&[0.75]));
1421
1422 let mut vector_output = Vec::new();
1423 vector_output.extend_from_slice(&[0xAA, 0x06]);
1424 vector_output.push(dense.len() as u8);
1425 vector_output.extend_from_slice(&dense);
1426
1427 let mut vectors_output = Vec::new();
1428 push_len_field(&mut vectors_output, 0x0A, &vector_output);
1429 let data = scored_point_with_vectors(&vectors_output);
1430
1431 let point = decode_scored_point(&data).unwrap();
1432
1433 assert_eq!(point.vector, Some(vec![0.25, 0.75]));
1434 }
1435
1436 #[test]
1437 fn test_decode_scored_point_accepts_single_named_dense_vector_output() {
1438 let data = scored_point_with_vectors(&named_dense_vectors_output("image", &[0.25, 0.75]));
1439
1440 let point = decode_scored_point(&data).unwrap();
1441
1442 assert_eq!(point.vector, Some(vec![0.25, 0.75]));
1443 }
1444
1445 #[test]
1446 fn test_decode_scored_point_rejects_multiple_named_vectors() {
1447 let mut first = named_dense_vectors_output("image", &[0.25, 0.75]);
1448 let second = named_dense_vectors_output("text", &[0.5, 0.5]);
1449 let second_named_body = &second[2..];
1450 let mut named_body = first.split_off(2);
1451 named_body.extend_from_slice(second_named_body);
1452 let mut output = Vec::new();
1453 push_len_field(&mut output, 0x12, &named_body);
1454 let data = scored_point_with_vectors(&output);
1455
1456 let err = decode_scored_point(&data).unwrap_err();
1457
1458 assert!(err.to_string().contains("Multiple named vectors"));
1459 }
1460
1461 #[test]
1462 fn test_decode_named_vector_entry_rejects_duplicate_key_fields() {
1463 let vector_output = current_dense_vectors_output(&[0.25, 0.75]);
1464 let vector_output = &vector_output[2..];
1465
1466 let mut entry = Vec::new();
1467 push_len_field(&mut entry, 0x0A, b"image");
1468 push_len_field(&mut entry, 0x0A, b"text");
1469 push_len_field(&mut entry, 0x12, vector_output);
1470
1471 let err = decode_named_vector_output_entry(&entry).unwrap_err();
1472
1473 assert!(err.to_string().contains("Duplicate named vector key"));
1474 }
1475
1476 #[test]
1477 fn test_decode_named_vector_entry_rejects_conflicting_value_fields() {
1478 let first = current_dense_vectors_output(&[0.25]);
1479 let second = current_dense_vectors_output(&[0.75]);
1480
1481 let mut entry = Vec::new();
1482 push_len_field(&mut entry, 0x0A, b"image");
1483 push_len_field(&mut entry, 0x12, &first[2..]);
1484 push_len_field(&mut entry, 0x12, &second[2..]);
1485
1486 let err = decode_named_vector_output_entry(&entry).unwrap_err();
1487
1488 assert!(err.to_string().contains("Conflicting vector outputs"));
1489 }
1490
1491 #[test]
1492 fn test_decode_scored_point_rejects_conflicting_vector_fields() {
1493 let mut data = vec![
1494 0x0A, 0x02, 0x08, 0x01, ];
1496 push_len_field(&mut data, 0x32, ¤t_dense_vectors_output(&[0.25]));
1497 push_len_field(&mut data, 0x32, ¤t_dense_vectors_output(&[0.75]));
1498
1499 let err = decode_scored_point(&data).unwrap_err();
1500
1501 assert!(err.to_string().contains("Conflicting vector outputs"));
1502 }
1503
1504 #[test]
1505 fn test_decode_vector_output_rejects_conflicting_deprecated_and_dense_vectors() {
1506 let deprecated = deprecated_dense_vectors_output(&[0.25]);
1507 let dense = current_dense_vectors_output(&[0.75]);
1508
1509 let mut vector_output = deprecated[2..].to_vec();
1510 vector_output.extend_from_slice(&dense[2..]);
1511
1512 let err = decode_vector_output(&vector_output).unwrap_err();
1513
1514 assert!(err.to_string().contains("Conflicting vector outputs"));
1515 }
1516
1517 #[test]
1518 fn test_decode_scored_point_rejects_duplicate_score_fields() {
1519 let first_score = 0.5f32.to_le_bytes();
1520 let second_score = 0.75f32.to_le_bytes();
1521 let data = &[
1522 0x0A,
1523 0x02,
1524 0x08,
1525 0x01, 0x1D,
1527 first_score[0],
1528 first_score[1],
1529 first_score[2],
1530 first_score[3],
1531 0x1D,
1532 second_score[0],
1533 second_score[1],
1534 second_score[2],
1535 second_score[3],
1536 ];
1537
1538 let err = decode_scored_point(data).unwrap_err();
1539
1540 assert!(err.to_string().contains("Duplicate scored point score"));
1541 }
1542
1543 #[test]
1544 fn test_decode_scored_point_rejects_duplicate_id_fields() {
1545 let data = &[
1546 0x0A, 0x02, 0x08, 0x01, 0x0A, 0x02, 0x08, 0x02, ];
1549
1550 let err = decode_scored_point(data).unwrap_err();
1551
1552 assert!(err.to_string().contains("Duplicate scored point id"));
1553 }
1554
1555 #[test]
1556 fn test_decode_scored_point_rejects_duplicate_payload_keys() {
1557 let mut data = vec![
1558 0x0A, 0x02, 0x08, 0x01, ];
1560 push_len_field(&mut data, 0x12, &payload_string_entry("tenant_id", "first"));
1561 push_len_field(
1562 &mut data,
1563 0x12,
1564 &payload_string_entry("tenant_id", "second"),
1565 );
1566
1567 let err = decode_scored_point(&data).unwrap_err();
1568
1569 assert!(err.to_string().contains("Duplicate payload key"));
1570 }
1571
1572 #[test]
1573 fn test_decode_scored_point_rejects_malformed_vector() {
1574 let data = &[
1575 0x0A, 0x02, 0x08, 0x01, 0x32, 0x07, 0x0A, 0x05, 0x0A, 0x03, 0x00, 0x00, 0x00,
1580 ];
1581
1582 let err = decode_scored_point(data).unwrap_err();
1583 assert!(err.to_string().contains("Invalid vector data length"));
1584 }
1585
1586 #[test]
1587 fn test_decode_scored_point_rejects_non_finite_score() {
1588 let nan = f32::NAN.to_le_bytes();
1589 let data = &[
1590 0x0A, 0x02, 0x08, 0x01, 0x1D, nan[0], nan[1], nan[2], nan[3],
1592 ];
1593
1594 let err = decode_scored_point(data).unwrap_err();
1595 assert!(err.to_string().contains("non-finite score"));
1596 }
1597
1598 #[test]
1599 fn test_decode_scored_point_rejects_non_finite_vector() {
1600 let nan = f32::NAN.to_le_bytes();
1601 let data = &[
1602 0x0A, 0x02, 0x08, 0x01, 0x32, 0x08, 0x0A, 0x06, 0x0A, 0x04, nan[0], nan[1], nan[2], nan[3],
1607 ];
1608
1609 let err = decode_scored_point(data).unwrap_err();
1610 assert!(err.to_string().contains("non-finite vector value"));
1611 }
1612
1613 #[test]
1614 fn test_decode_scored_point_rejects_empty_vector_data() {
1615 let data = &[
1616 0x0A, 0x02, 0x08, 0x01, 0x32, 0x04, 0x0A, 0x02, 0x0A, 0x00, ];
1621
1622 let err = decode_scored_point(data).unwrap_err();
1623 assert!(err.to_string().contains("Empty vector data"));
1624 }
1625
1626 #[test]
1627 fn test_decode_search_response_rejects_point_without_id() {
1628 let score_bytes = 1.0f32.to_le_bytes();
1629 let data = &[
1630 0x0A,
1631 0x05,
1632 0x1D,
1633 score_bytes[0],
1634 score_bytes[1],
1635 score_bytes[2],
1636 score_bytes[3],
1637 ];
1638
1639 let err = decode_search_response(data).unwrap_err();
1640 assert!(err.to_string().contains("Missing point id"));
1641 }
1642
1643 #[test]
1644 fn test_decode_get_response_rejects_point_without_id() {
1645 let data = &[0x0A, 0x00];
1646
1647 let err = decode_get_response(data).unwrap_err();
1648 assert!(err.to_string().contains("Missing point id"));
1649 }
1650
1651 #[test]
1652 fn test_decode_get_response_rejects_duplicate_retrieved_id_fields() {
1653 let retrieved_point = &[
1654 0x0A, 0x02, 0x08, 0x01, 0x0A, 0x02, 0x08, 0x02, ];
1657 let mut data = Vec::new();
1658 push_len_field(&mut data, 0x0A, retrieved_point);
1659
1660 let err = decode_get_response(&data).unwrap_err();
1661
1662 assert!(err.to_string().contains("Duplicate retrieved point id"));
1663 }
1664
1665 #[test]
1666 fn test_decode_get_response_rejects_duplicate_retrieved_payload_keys() {
1667 let mut retrieved_point = vec![
1668 0x0A, 0x02, 0x08, 0x01, ];
1670 push_len_field(
1671 &mut retrieved_point,
1672 0x12,
1673 &payload_string_entry("tenant_id", "first"),
1674 );
1675 push_len_field(
1676 &mut retrieved_point,
1677 0x12,
1678 &payload_string_entry("tenant_id", "second"),
1679 );
1680
1681 let mut data = Vec::new();
1682 push_len_field(&mut data, 0x0A, &retrieved_point);
1683
1684 let err = decode_get_response(&data).unwrap_err();
1685
1686 assert!(err.to_string().contains("Duplicate payload key"));
1687 }
1688
1689 #[test]
1690 fn test_decode_scroll_response_rejects_point_without_id() {
1691 let data = &[0x12, 0x00];
1692
1693 let err = match decode_scroll_response(data) {
1694 Ok(_) => panic!("scroll response without point id must fail"),
1695 Err(err) => err,
1696 };
1697 assert!(err.to_string().contains("Missing point id"));
1698 }
1699
1700 #[test]
1701 fn test_decode_scroll_response_rejects_empty_next_offset() {
1702 let data = &[0x0A, 0x00];
1703
1704 let err = match decode_scroll_response(data) {
1705 Ok(_) => panic!("scroll response with empty next offset must fail"),
1706 Err(err) => err,
1707 };
1708 assert!(err.to_string().contains("Missing point id"));
1709 }
1710
1711 #[test]
1712 fn test_decode_scroll_response_rejects_duplicate_next_offset() {
1713 let data = &[
1714 0x0A, 0x02, 0x08, 0x01, 0x0A, 0x02, 0x08, 0x02, ];
1717
1718 let err = match decode_scroll_response(data) {
1719 Ok(_) => panic!("scroll response with duplicate next offset must fail"),
1720 Err(err) => err,
1721 };
1722
1723 assert!(err.to_string().contains("Duplicate scroll next offset"));
1724 }
1725
1726 #[test]
1727 fn test_decode_search_response_empty() {
1728 let data: &[u8] = &[];
1729 let results = decode_search_response(data).unwrap();
1730 assert!(results.is_empty());
1731 }
1732
1733 #[test]
1734 fn test_decode_value_string() {
1735 let data = &[0x22, 0x05, b'h', b'e', b'l', b'l', b'o'];
1738 let val = decode_value(data).unwrap();
1739 assert_eq!(val, PayloadValue::String("hello".to_string()));
1740 }
1741
1742 #[test]
1743 fn test_decode_value_integer() {
1744 let data = &[0x18, 0x2A];
1747 let val = decode_value(data).unwrap();
1748 assert_eq!(val, PayloadValue::Integer(42));
1749 }
1750
1751 #[test]
1752 fn test_decode_value_bool() {
1753 let data = &[0x28, 0x01];
1756 let val = decode_value(data).unwrap();
1757 assert_eq!(val, PayloadValue::Bool(true));
1758 }
1759
1760 #[test]
1761 fn test_decode_value_rejects_malformed_bool_varint() {
1762 let data = &[0x28, 0x02];
1763
1764 let err = decode_value(data).unwrap_err();
1765 assert!(err.to_string().contains("Invalid payload bool value"));
1766 }
1767
1768 #[test]
1769 fn test_decode_value_double() {
1770 let f_bytes = std::f64::consts::PI.to_le_bytes();
1773 let mut data = vec![0x11];
1774 data.extend_from_slice(&f_bytes);
1775 let val = decode_value(&data).unwrap();
1776 match val {
1777 PayloadValue::Float(f) => assert!((f - std::f64::consts::PI).abs() < 0.001),
1778 _ => panic!("Expected Float"),
1779 }
1780 }
1781
1782 #[test]
1783 fn test_decode_value_null() {
1784 let data = &[0x08, 0x00];
1787 let val = decode_value(data).unwrap();
1788 assert_eq!(val, PayloadValue::Null);
1789 }
1790
1791 #[test]
1792 fn test_decode_value_rejects_malformed_null_enum() {
1793 let data = &[0x08, 0x01];
1794
1795 let err = decode_value(data).unwrap_err();
1796 assert!(err.to_string().contains("Invalid payload null enum value"));
1797 }
1798
1799 #[test]
1800 fn test_decode_value_rejects_duplicate_value_kinds() {
1801 let data = &[
1802 0x18, 0x2A, 0x22, 0x02, b'o', b'k', ];
1805
1806 let err = decode_value(data).unwrap_err();
1807
1808 assert!(err.to_string().contains("Duplicate payload value kind"));
1809 }
1810
1811 #[test]
1812 fn test_decode_value_rejects_duplicate_same_value_kind() {
1813 let data = &[
1814 0x22, 0x05, b'f', b'i', b'r', b's', b't', 0x22, 0x06, b's', b'e', b'c', b'o', b'n', b'd', ];
1817
1818 let err = decode_value(data).unwrap_err();
1819
1820 assert!(err.to_string().contains("Duplicate payload value kind"));
1821 }
1822
1823 #[test]
1824 fn test_decode_map_entry_rejects_duplicate_key_fields() {
1825 let mut entry = Vec::new();
1826 push_len_field(&mut entry, 0x0A, b"first");
1827 push_len_field(&mut entry, 0x0A, b"second");
1828 push_len_field(&mut entry, 0x12, &{
1829 let mut value = Vec::new();
1830 push_len_field(&mut value, 0x22, b"ok");
1831 value
1832 });
1833
1834 let err = decode_map_entry(&entry, 0).unwrap_err();
1835
1836 assert!(err.to_string().contains("Duplicate payload map key"));
1837 }
1838
1839 #[test]
1840 fn test_decode_map_entry_rejects_duplicate_value_fields() {
1841 let mut entry = Vec::new();
1842 push_len_field(&mut entry, 0x0A, b"key");
1843 push_len_field(&mut entry, 0x12, &{
1844 let mut value = Vec::new();
1845 push_len_field(&mut value, 0x22, b"first");
1846 value
1847 });
1848 push_len_field(&mut entry, 0x12, &{
1849 let mut value = Vec::new();
1850 push_len_field(&mut value, 0x22, b"second");
1851 value
1852 });
1853
1854 let err = decode_map_entry(&entry, 0).unwrap_err();
1855
1856 assert!(err.to_string().contains("Duplicate payload map value"));
1857 }
1858
1859 #[test]
1860 fn test_decode_scored_point_rejects_invalid_payload_key_utf8() {
1861 let data = &[
1862 0x0A, 0x02, 0x08, 0x01, 0x12, 0x09, 0x0A, 0x01, 0xFF, 0x12, 0x04, 0x22, 0x02, b'o', b'k', ];
1868
1869 let err = decode_scored_point(data).unwrap_err();
1870 assert!(err.to_string().contains("Invalid UTF-8 payload map key"));
1871 }
1872
1873 #[test]
1874 fn test_decode_scored_point_rejects_empty_payload_key() {
1875 let data = &[
1876 0x0A, 0x02, 0x08, 0x01, 0x12, 0x08, 0x0A, 0x00, 0x12, 0x04, 0x22, 0x02, b'o', b'k', ];
1882
1883 let err = decode_scored_point(data).unwrap_err();
1884 assert!(err.to_string().contains("Payload map key"));
1885 }
1886
1887 #[test]
1888 fn test_decode_scored_point_rejects_payload_entry_without_value() {
1889 let data = &[
1890 0x0A, 0x02, 0x08, 0x01, 0x12, 0x05, 0x0A, 0x03, b'b', b'a', b'd', ];
1894
1895 let err = decode_scored_point(data).unwrap_err();
1896 assert!(err.to_string().contains("Missing payload map value"));
1897 }
1898
1899 #[test]
1900 fn test_decode_value_rejects_non_finite_payload_float() {
1901 let nan = f64::NAN.to_le_bytes();
1902 let mut data = vec![0x11];
1903 data.extend_from_slice(&nan);
1904
1905 let err = decode_value(&data).unwrap_err();
1906 assert!(err.to_string().contains("non-finite payload float"));
1907 }
1908
1909 #[test]
1910 fn test_decode_value_rejects_malformed_nested_object_entry() {
1911 let data = &[
1912 0x32, 0x07, 0x0A, 0x05, 0x0A, 0x03, b'b', b'a', b'd', ];
1916
1917 let err = decode_value(data).unwrap_err();
1918 assert!(err.to_string().contains("Missing payload map value"));
1919 }
1920
1921 #[test]
1922 fn test_decode_value_rejects_empty_nested_object_key() {
1923 let data = &[
1924 0x32, 0x0A, 0x0A, 0x08, 0x0A, 0x00, 0x12, 0x04, 0x22, 0x02, b'o', b'k', ];
1930
1931 let err = decode_value(data).unwrap_err();
1932 assert!(err.to_string().contains("Payload map key"));
1933 }
1934
1935 #[test]
1936 fn test_decode_value_rejects_duplicate_nested_object_key() {
1937 let first = payload_string_entry("tenant_id", "first");
1938 let second = payload_string_entry("tenant_id", "second");
1939
1940 let mut struct_value = Vec::new();
1941 push_len_field(&mut struct_value, 0x0A, &first);
1942 push_len_field(&mut struct_value, 0x0A, &second);
1943
1944 let mut data = Vec::new();
1945 push_len_field(&mut data, 0x32, &struct_value);
1946
1947 let err = decode_value(&data).unwrap_err();
1948
1949 assert!(err.to_string().contains("Duplicate payload key"));
1950 }
1951
1952 #[test]
1953 fn test_decode_value_rejects_malformed_nested_list_item() {
1954 let data = &[
1955 0x3A, 0x02, 0x0A, 0x00, ];
1958
1959 let err = decode_value(data).unwrap_err();
1960 assert!(err.to_string().contains("Missing payload value kind"));
1961 }
1962
1963 #[test]
1964 fn test_decode_scroll_result_empty() {
1965 let data: &[u8] = &[];
1966 let result = decode_scroll_response(data).unwrap();
1967 assert!(result.points.is_empty());
1968 assert!(result.next_offset.is_none());
1969 }
1970}