Skip to main content

score_set/
traits.rs

1use alloc::boxed::Box;
2
3use witnessed::Witnessed;
4
5/// Witness attached to values known to be valid for the normalized `[0, 1]`
6/// scoring boundary.
7pub struct V01;
8
9/// Error returned when a value cannot be proven to be in the normalized
10/// `[0, 1]` range.
11#[derive(Clone, Copy, Debug, Eq, PartialEq)]
12pub struct V01Error;
13
14/// Proves that an `f32` value is in the normalized `[0, 1]` range.
15///
16/// This function is suitable for use with [`witnessed::Witnessing::by`]:
17///
18/// ```
19/// use score_set::traits::{prove_v01_f32, V01};
20/// use witnessed::{WitnessExt, Witnessed};
21///
22/// let score: Witnessed<f32, V01> = 0.75_f32.witness().by(prove_v01_f32).unwrap();
23/// assert_eq!(*score, 0.75);
24/// ```
25///
26/// Values such as `NaN` are rejected because neither range comparison
27/// succeeds for them.
28pub fn prove_v01_f32(value: &f32) -> Result<V01, V01Error> {
29    (0.0..=1.0).contains(value).then_some(V01).ok_or(V01Error)
30}
31
32/// Proves that an `f64` value is in the normalized `[0, 1]` range.
33///
34/// Values such as `NaN` are rejected because neither range comparison
35/// succeeds for them.
36pub fn prove_v01_f64(value: &f64) -> Result<V01, V01Error> {
37    (0.0..=1.0).contains(value).then_some(V01).ok_or(V01Error)
38}
39
40/// Measures a context and returns a value chosen by the implementation.
41///
42/// `Output` is the value consumed by a corresponding `Map01F32` or `Map01F64`
43/// implementation.
44pub trait Measure<Ctx: ?Sized>: Send + Sync {
45    /// The value produced by [`Measure::measure`].
46    type Output;
47
48    /// Extracts a measurable value from `ctx`.
49    fn measure(&self, ctx: &Ctx) -> Self::Output;
50}
51
52/// Maps a measurement into the `[0, 1]` range.
53///
54/// `Input` is associated with the mapper rather than fixed in the trait, so a
55/// mapper can consume any measurement type. The normalized result carries the
56/// [`V01`] witness.
57pub trait Map01F32: Send + Sync {
58    /// The value accepted by [`Map01F32::map`].
59    type Input;
60
61    /// Converts `value` into a normalized score.
62    fn map(&self, value: Self::Input) -> Witnessed<f32, V01>;
63}
64
65/// Maps a measurement into the `[0, 1]` range.
66///
67/// `Input` is associated with the mapper rather than fixed in the trait, so a
68/// mapper can consume any measurement type. The normalized result carries the
69/// [`V01`] witness.
70pub trait Map01F64: Send + Sync {
71    /// The value accepted by [`Map01F64::map`].
72    type Input;
73
74    /// Converts `value` into a normalized score.
75    fn map(&self, value: Self::Input) -> Witnessed<f64, V01>;
76}
77
78/// Evaluates a context into an `f64` score.
79pub trait EvalF64<Ctx: ?Sized>: Send + Sync {
80    /// Computes a score from `ctx`.
81    fn eval(&self, ctx: &Ctx) -> f64;
82}
83
84impl<Ctx, E> EvalF64<Ctx> for Box<E>
85where
86    Ctx: ?Sized,
87    E: EvalF64<Ctx> + ?Sized,
88{
89    #[inline]
90    fn eval(&self, ctx: &Ctx) -> f64 {
91        self.as_ref().eval(ctx)
92    }
93}
94
95/// Evaluates a context into an `f32` score.
96pub trait EvalF32<Ctx: ?Sized>: Send + Sync {
97    /// Computes a score from `ctx`.
98    fn eval(&self, ctx: &Ctx) -> f32;
99}
100
101impl<Ctx, E> EvalF32<Ctx> for Box<E>
102where
103    Ctx: ?Sized,
104    E: EvalF32<Ctx> + ?Sized,
105{
106    #[inline]
107    fn eval(&self, ctx: &Ctx) -> f32 {
108        self.as_ref().eval(ctx)
109    }
110}