diskann_benchmark_runner/dispatcher/
api.rs1use std::fmt::{self, Display, Formatter};
7
8#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
12pub struct MatchScore(pub u32);
13
14impl Display for MatchScore {
15 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
16 write!(f, "success ({})", self.0)
17 }
18}
19
20#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
25pub struct FailureScore(pub u32);
26
27impl Display for FailureScore {
28 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
29 write!(f, "fail ({})", self.0)
30 }
31}
32
33pub struct TaggedFailureScore<'a> {
36 pub(crate) score: u32,
37 pub(crate) why: Box<dyn std::fmt::Display + 'a>,
38}
39
40impl TaggedFailureScore<'_> {
41 pub fn score(&self) -> FailureScore {
43 FailureScore(self.score)
44 }
45}
46
47impl fmt::Debug for TaggedFailureScore<'_> {
48 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
49 f.debug_struct("TaggedFailureScore")
50 .field("score", &self.score)
51 .field("why", &self.why.to_string())
52 .finish()
53 }
54}
55
56impl Display for TaggedFailureScore<'_> {
57 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
58 write!(f, "{}", self.why)
59 }
60}
61
62pub trait DispatchRule<From>: Sized {
64 type Error: std::fmt::Debug + std::fmt::Display + 'static;
66
67 fn try_match(from: &From) -> Result<MatchScore, FailureScore>;
74
75 fn convert(from: From) -> Result<Self, Self::Error>;
84
85 fn description(f: &mut Formatter<'_>, _from: Option<&From>) -> fmt::Result {
96 write!(f, "<no description>")
97 }
98
99 fn try_match_verbose<'a>(from: &'a From) -> Result<MatchScore, TaggedFailureScore<'a>>
105 where
106 Self: 'a,
107 {
108 match Self::try_match(from) {
109 Ok(score) => Ok(score),
110 Err(score) => Err(TaggedFailureScore {
111 score: score.0,
112 why: Box::new(Why::<From, Self>::new(from)),
113 }),
114 }
115 }
116}
117
118#[derive(Debug, Clone, Copy)]
120pub struct Why<'a, From, To> {
121 from: &'a From,
122 _to: std::marker::PhantomData<To>,
123}
124
125impl<'a, From, To> Why<'a, From, To> {
126 pub fn new(from: &'a From) -> Self {
127 Self {
128 from,
129 _to: std::marker::PhantomData,
130 }
131 }
132}
133
134impl<From, To> std::fmt::Display for Why<'_, From, To>
135where
136 To: DispatchRule<From>,
137{
138 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
139 To::description(f, Some(self.from))
140 }
141}
142
143#[derive(Debug, Clone, Copy)]
145pub struct Description<From, To> {
146 _from: std::marker::PhantomData<From>,
147 _to: std::marker::PhantomData<To>,
148}
149
150impl<From, To> Description<From, To> {
151 pub fn new() -> Self {
152 Self {
153 _from: std::marker::PhantomData,
154 _to: std::marker::PhantomData,
155 }
156 }
157}
158
159impl<From, To> Default for Description<From, To> {
160 fn default() -> Self {
161 Self::new()
162 }
163}
164
165impl<From, To> std::fmt::Display for Description<From, To>
166where
167 To: DispatchRule<From>,
168{
169 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
170 To::description(f, None)
171 }
172}
173
174pub const IMPLICIT_MATCH_SCORE: MatchScore = MatchScore(100000);
181
182impl<T: Sized> DispatchRule<T> for T {
183 type Error = std::convert::Infallible;
184
185 fn try_match(_from: &T) -> Result<MatchScore, FailureScore> {
186 Ok(IMPLICIT_MATCH_SCORE)
187 }
188
189 fn convert(from: T) -> Result<T, Self::Error> {
190 Ok(from)
191 }
192
193 fn description(f: &mut Formatter<'_>, from: Option<&T>) -> fmt::Result {
194 match from {
195 None => write!(f, "{}", std::any::type_name::<T>()),
196 Some(_) => write!(f, "identity match"),
197 }
198 }
199}
200
201impl<'a, T: Sized> DispatchRule<&'a mut T> for &'a T {
203 type Error = std::convert::Infallible;
204
205 fn try_match(_from: &&'a mut T) -> Result<MatchScore, FailureScore> {
206 Ok(IMPLICIT_MATCH_SCORE)
207 }
208
209 fn convert(from: &'a mut T) -> Result<&'a T, Self::Error> {
210 Ok(from)
211 }
212
213 fn description(f: &mut Formatter<'_>, from: Option<&&'a mut T>) -> fmt::Result {
214 match from {
215 None => write!(f, "&{}", std::any::type_name::<T>()),
216 Some(_) => write!(f, "identity match"),
217 }
218 }
219}
220
221pub trait Map: 'static {
266 type Type<'a>;
268}
269
270pub struct Ref<T: ?Sized + 'static>(std::marker::PhantomData<T>);
282
283impl<T: ?Sized> Map for Ref<T> {
284 type Type<'a> = &'a T;
285}
286
287pub struct MutRef<T: ?Sized + 'static>(std::marker::PhantomData<T>);
300impl<T: ?Sized> Map for MutRef<T> {
301 type Type<'a> = &'a mut T;
302}
303
304pub struct Type<T: 'static>(std::marker::PhantomData<T>);
305impl<T> Map for Type<T> {
306 type Type<'a> = T;
307}
308
309#[macro_export]
310macro_rules! self_map {
311 ($($type:tt)*) => {
312 impl $crate::dispatcher::Map for $($type)* {
313 type Type<'a> = $($type)*;
314 }
315 }
316}
317
318self_map!(bool);
319self_map!(usize);
320self_map!(u8);
321self_map!(u16);
322self_map!(u32);
323self_map!(u64);
324self_map!(u128);
325self_map!(i8);
326self_map!(i16);
327self_map!(i32);
328self_map!(i64);
329self_map!(i128);
330self_map!(String);
331self_map!(f32);
332self_map!(f64);
333
334pub struct ArgumentMismatch<'a, const N: usize> {
339 pub(crate) method: &'a str,
340 pub(crate) mismatches: [Option<Box<dyn std::fmt::Display + 'a>>; N],
341}
342
343impl<'a, const N: usize> ArgumentMismatch<'a, N> {
344 pub fn method(&self) -> &str {
346 self.method
347 }
348
349 pub fn mismatches(&self) -> &[Option<Box<dyn std::fmt::Display + 'a>>; N] {
357 &self.mismatches
358 }
359}
360
361pub struct Signature(pub(crate) fn(&mut Formatter<'_>) -> std::fmt::Result);
363
364impl std::fmt::Display for Signature {
365 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
366 (self.0)(f)
367 }
368}
369
370#[cfg(test)]
375mod tests {
376 use super::*;
377
378 #[test]
379 fn test_match_score() {
380 let x = MatchScore(10);
381 let y = MatchScore(20);
382 assert!(x < y);
383 assert!(x <= y);
384 assert!(x <= x);
385 assert!(x == x);
386 assert!(x != y);
387
388 assert!(y == y);
389 assert!(y != x);
390 assert!(y > x);
391 assert!(y >= x);
392
393 assert_eq!(x.to_string(), "success (10)");
394 }
395
396 #[test]
397 fn test_fail_score() {
398 let x = FailureScore(10);
399 let y = FailureScore(20);
400 assert!(x < y);
401 assert!(x <= y);
402 assert!(x <= x);
403 assert!(x == x);
404 assert!(x != y);
405
406 assert!(y == y);
407 assert!(y != x);
408 assert!(y > x);
409 assert!(y >= x);
410
411 assert_eq!(x.to_string(), "fail (10)");
412 }
413
414 #[test]
415 fn test_tagged_failure() {
416 let tagged = TaggedFailureScore {
417 score: 10,
418 why: Box::new(20),
419 };
420
421 assert_eq!(tagged.score(), FailureScore(10));
422
423 assert_eq!(tagged.to_string(), "20");
425
426 assert_eq!(
427 format!("{:?}", tagged),
428 "TaggedFailureScore { score: 10, why: \"20\" }"
429 );
430 }
431
432 enum TestEnum {
433 A,
434 B,
435 }
436
437 struct TestType;
438
439 impl DispatchRule<TestEnum> for TestType {
440 type Error = std::convert::Infallible;
441 fn try_match(x: &TestEnum) -> Result<MatchScore, FailureScore> {
442 match x {
443 TestEnum::A => Ok(MatchScore(10)),
444 TestEnum::B => Err(FailureScore(20)),
445 }
446 }
447
448 fn convert(x: TestEnum) -> Result<Self, Self::Error> {
449 assert!(matches!(x, TestEnum::A));
450 Ok(TestType)
451 }
452
453 fn description(f: &mut Formatter<'_>, from: Option<&TestEnum>) -> fmt::Result {
454 match from {
455 None => write!(f, "TestEnum::A"),
456 Some(value) => match value {
457 TestEnum::A => write!(f, "success"),
458 TestEnum::B => write!(f, "expected TestEnum::B"),
459 },
460 }
461 }
462 }
463
464 #[test]
465 fn test_dispatch_helpers() {
466 let desc = Description::<TestEnum, TestType>::default().to_string();
467 assert_eq!(desc, "TestEnum::A");
468
469 let a = TestEnum::A;
470 let why = Why::<_, TestType>::new(&a).to_string();
471 assert_eq!(why, "success");
472
473 let b = TestEnum::B;
474 let why = Why::<_, TestType>::new(&b).to_string();
475 assert_eq!(why, "expected TestEnum::B");
476
477 let result = TestType::try_match_verbose(&a).unwrap();
478 assert_eq!(result, MatchScore(10));
479
480 let result = TestType::try_match_verbose(&b).unwrap_err();
481 assert_eq!(result.score(), FailureScore(20));
482 assert_eq!(result.to_string(), "expected TestEnum::B");
483
484 TestType::convert(TestEnum::A).unwrap();
485 }
486
487 #[test]
488 fn test_implicit_conversions() {
489 let x = f32::try_match(&0.0f32).unwrap();
491 assert_eq!(x, IMPLICIT_MATCH_SCORE);
492
493 let x = f32::convert(0.0f32).unwrap();
494 assert_eq!(x, 0.0f32);
495
496 let x = <&f32>::try_match(&&mut 0.0f32).unwrap();
497 assert_eq!(x, IMPLICIT_MATCH_SCORE);
498
499 let mut x: f32 = 10.0;
500 let x = <&f32>::convert(&mut x).unwrap();
501 assert_eq!(*x, 10.0);
502
503 assert_eq!(Description::<f32, f32>::new().to_string(), "f32");
504 assert_eq!(Why::<f32, f32>::new(&0.0f32).to_string(), "identity match");
505
506 assert_eq!(Description::<&mut f32, &f32>::new().to_string(), "&f32");
507 assert_eq!(
508 Why::<&mut f32, &f32>::new(&&mut 0.0f32).to_string(),
509 "identity match"
510 );
511 }
512
513 #[test]
514 #[should_panic]
515 fn convert_panics() {
516 let _ = TestType::convert(TestEnum::B);
517 }
518}