1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
//! Compile-time and runtime assertions for the `SearchBackend` trait and
//! `SearchResult` type.
//!
//! Tests here verify:
//! - `SearchResult` is `Send + Sync + Clone`
//! - The trait is dyn-compatible (object-safe)
//! - `SearchResult` ordering is descending by score
//! - NaN scores degrade gracefully via `unwrap_or(Equal)`
extern crate alloc;
use alloc::sync::Arc;
use tinyquant_core::backend::{SearchBackend, SearchResult};
// ---------------------------------------------------------------------------
// Compile-time type-system assertions (function-based)
// ---------------------------------------------------------------------------
/// If `SearchBackend` is not dyn-compatible this function will fail to compile.
fn _assert_dyn_safe(_: &dyn SearchBackend) {}
/// Generic bounds check — compiles only if `T: Send + Sync`.
fn _assert_send_sync<T: Send + Sync>() {}
/// Generic bounds check — compiles only if `T: Clone`.
fn _assert_clone<T: Clone>() {}
// ---------------------------------------------------------------------------
// Runtime tests
// ---------------------------------------------------------------------------
#[test]
fn search_result_is_send_sync_clone() {
_assert_send_sync::<SearchResult>();
_assert_clone::<SearchResult>();
}
#[test]
fn search_result_ordering_descending() {
let mut v = [
SearchResult {
vector_id: Arc::from("a"),
score: 0.5,
},
SearchResult {
vector_id: Arc::from("b"),
score: 0.9,
},
SearchResult {
vector_id: Arc::from("c"),
score: 0.1,
},
];
v.sort();
assert_eq!(v[0].vector_id.as_ref(), "b");
assert_eq!(v[1].vector_id.as_ref(), "a");
assert_eq!(v[2].vector_id.as_ref(), "c");
}
#[test]
fn search_result_nan_collapses_to_equal() {
// The Ord impl uses `other.score.partial_cmp(&self.score).unwrap_or(Equal)`.
// NaN comparisons return None from partial_cmp, which collapses to Equal.
// The vector_id tiebreaker (ascending) then determines order:
// "nan" < "one" lexicographically, so "nan" sorts first.
use std::sync::Arc;
let mut v = [
SearchResult {
vector_id: Arc::from("one"),
score: 1.0,
},
SearchResult {
vector_id: Arc::from("nan"),
score: f32::NAN,
},
];
v.sort(); // NaN collapses to Equal; tiebreaker: "nan" < "one" → "nan" sorts first
assert_eq!(v[0].vector_id.as_ref(), "nan");
}
#[test]
fn search_result_tie_breaks_preserve_insertion_order() {
let mut v = [
SearchResult {
vector_id: Arc::from("first"),
score: 0.5,
},
SearchResult {
vector_id: Arc::from("second"),
score: 0.5,
},
SearchResult {
vector_id: Arc::from("third"),
score: 0.5,
},
];
// tiebreaker is vector_id ascending: "first" < "second" < "third"
v.sort();
assert_eq!(v[0].vector_id.as_ref(), "first");
assert_eq!(v[1].vector_id.as_ref(), "second");
assert_eq!(v[2].vector_id.as_ref(), "third");
}