1use std::cmp;
2use std::collections::BinaryHeap;
3use std::num::FpCategory;
4use std::vec;
5
6#[derive(Clone, Debug, Default)]
8pub struct SearchResults<T>(Vec<Scored<T>>);
9
10impl<T> SearchResults<T> {
11 pub fn new() -> SearchResults<T> {
13 SearchResults(vec![])
14 }
15
16 pub fn from_min_heap(
18 queue: &mut BinaryHeap<cmp::Reverse<Scored<T>>>,
19 ) -> SearchResults<T> {
20 let mut results = vec![];
21 while let Some(x) = queue.pop() {
22 results.push(x.0);
23 }
24 results.reverse();
25 SearchResults(results)
26 }
27
28 pub fn push(&mut self, scored: Scored<T>) {
33 assert!(self.0.last().map_or(true, |smallest| &scored <= smallest));
34 self.0.push(scored);
35 }
36
37 pub fn normalize(&mut self) {
43 if let Some(top_score) = self.0.get(0).map(|s| s.score()) {
44 if top_score.classify() == FpCategory::Zero {
48 return;
49 }
50 for result in &mut self.0 {
51 let score = result.score();
52 result.set_score(score / top_score);
53 }
54 }
55 }
56
57 pub fn rescore<F: FnMut(&T) -> f64>(&mut self, mut rescore: F) {
61 for result in &mut self.0 {
62 let score = rescore(result.value());
63 result.set_score(score);
64 }
65 self.0.sort_by(|s1, s2| s1.cmp(&s2).reverse());
66 }
67
68 pub fn trim(&mut self, size: usize) {
71 if self.0.len() > size {
72 self.0.drain(size..);
73 }
74 }
75
76 pub fn len(&self) -> usize {
78 self.0.len()
79 }
80
81 pub fn is_empty(&self) -> bool {
83 self.0.is_empty()
84 }
85
86 pub fn as_slice(&self) -> &[Scored<T>] {
88 &self.0
89 }
90
91 pub fn into_vec(self) -> Vec<Scored<T>> {
94 self.0
95 }
96}
97
98impl<T> IntoIterator for SearchResults<T> {
99 type IntoIter = vec::IntoIter<Scored<T>>;
100 type Item = Scored<T>;
101
102 fn into_iter(self) -> vec::IntoIter<Scored<T>> {
103 self.into_vec().into_iter()
104 }
105}
106
107#[derive(Clone, Copy, Debug)]
113pub struct Scored<T> {
114 score: f64,
115 value: T,
116}
117
118impl<T> Scored<T> {
119 pub fn new(value: T) -> Scored<T> {
121 Scored { score: 1.0, value }
122 }
123
124 pub fn score(&self) -> f64 {
131 self.score
132 }
133
134 pub fn set_score(&mut self, score: f64) {
138 assert!(score.is_finite());
139 self.score = score;
140 }
141
142 pub fn with_score(mut self, score: f64) -> Scored<T> {
147 self.set_score(score);
148 self
149 }
150
151 pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Scored<U> {
155 Scored { score: self.score, value: f(self.value) }
156 }
157
158 pub fn map_score<F: FnOnce(f64) -> f64>(self, f: F) -> Scored<T> {
163 let score = f(self.score);
164 self.with_score(score)
165 }
166
167 pub fn value(&self) -> &T {
169 &self.value
170 }
171
172 pub fn into_value(self) -> T {
175 self.value
176 }
177
178 pub fn into_pair(self) -> (f64, T) {
181 (self.score, self.value)
182 }
183}
184
185impl<T: Default> Default for Scored<T> {
186 fn default() -> Scored<T> {
187 Scored::new(T::default())
188 }
189}
190
191impl<T> Eq for Scored<T> {}
192
193impl<T> PartialEq for Scored<T> {
194 fn eq(&self, other: &Scored<T>) -> bool {
195 let (s1, s2) = (self.score, other.score);
196 s1 == s2
197 }
198}
199
200impl<T> Ord for Scored<T> {
201 fn cmp(&self, other: &Scored<T>) -> cmp::Ordering {
202 self.score.partial_cmp(&other.score).unwrap()
203 }
204}
205
206impl<T> PartialOrd for Scored<T> {
207 fn partial_cmp(&self, other: &Scored<T>) -> Option<cmp::Ordering> {
208 Some(self.cmp(other))
209 }
210}
211
212#[cfg(test)]
213mod tests {
214 use super::Scored;
215 use std::f64::NAN;
216
217 #[test]
218 #[should_panic]
219 fn never_nan_1() {
220 Scored::new(()).set_score(NAN);
221 }
222
223 #[test]
224 #[should_panic]
225 fn never_nan_2() {
226 Scored::new(()).with_score(NAN);
227 }
228
229 #[test]
230 #[should_panic]
231 fn never_nan_3() {
232 Scored::new(()).map_score(|_| NAN);
233 }
234}