Skip to main content

diskann_benchmark_runner/
input.rs

1/*
2 * Copyright (c) Microsoft Corporation.
3 * Licensed under the MIT license.
4 */
5
6use crate::{internal::visibility::Visibility, Checker};
7
8/// Inputs to [`Benchmarks`](crate::Benchmark).
9///
10/// These begin as [`raw`](Self::Raw) data transfer objects before final construction via
11/// [`from_raw`](Self::from_raw).
12pub trait Input: Sized + std::fmt::Debug + 'static {
13    /// The raw form of this input that is deserialized from input files and serialized as
14    /// [`examples`](Self::example). The raw nature of this type reflects that no input
15    /// validation has been performed beyond the checks performed by its
16    /// [`Deserialize`](serde::Deserialize) implementation.
17    ///
18    /// Final object validation is performed via [`from_raw`](Self::from_raw).
19    type Raw: serde::de::DeserializeOwned + serde::Serialize;
20
21    /// Return the discriminant associated with this type.
22    ///
23    /// This is used to map inputs types to their respective parsers.
24    ///
25    /// Well formed implementations should always return the same result.
26    fn tag() -> &'static str;
27
28    /// Construct `Self` from the raw deserialized representation, performing any necessary
29    /// validation checks (e.g., resolving file paths via the [`Checker`]).
30    fn from_raw(raw: Self::Raw, checker: &mut Checker) -> anyhow::Result<Self>;
31
32    /// Serialize `self` to a [`serde_json::Value`].
33    fn serialize(&self) -> anyhow::Result<serde_json::Value>;
34
35    /// Return an example of a raw input for this [`Input`].
36    ///
37    /// This is used to supply sample JSON layouts in the benchmark CLI.
38    fn example() -> Self::Raw;
39}
40
41/// A registered input. See [`crate::Registry::input`].
42#[derive(Clone, Copy)]
43pub struct Registered<'a>(pub(crate) &'a dyn internal::DynInput);
44
45impl Registered<'_> {
46    /// Return the input tag of the registered input.
47    ///
48    /// See: [`Input::tag`].
49    pub fn tag(&self) -> &'static str {
50        self.0.tag()
51    }
52
53    /// Try to deserialize raw JSON into the dynamic type of the input.
54    ///
55    /// See: [`Input::from_raw`].
56    pub(crate) fn try_deserialize(
57        &self,
58        serialized: &serde_json::Value,
59        checker: &mut Checker,
60    ) -> anyhow::Result<internal::Any> {
61        self.0.try_deserialize(serialized, checker)
62    }
63
64    /// Return an example JSON for the dynamic type of the input.
65    ///
66    /// See: [`Input::example`].
67    pub fn example(&self) -> anyhow::Result<serde_json::Value> {
68        self.0.example()
69    }
70
71    /// Return the visibility of the attached input.
72    pub(crate) fn visibility(&self) -> Visibility<'_> {
73        self.0.visibility()
74    }
75
76    /// Return a `std::fmt::Display` implementation that pretty-prints the input tag as well
77    /// as any visibility modifiers.
78    pub(crate) fn display(&self) -> Display<'_> {
79        Display(self.0)
80    }
81}
82
83impl std::fmt::Debug for Registered<'_> {
84    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85        f.debug_struct("input::Registered")
86            .field("tag", &self.tag())
87            .finish()
88    }
89}
90
91/// Return item from [`Registered::display`].
92pub(crate) struct Display<'a>(&'a dyn internal::DynInput);
93
94impl std::fmt::Debug for Display<'_> {
95    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
96        f.debug_struct("input::Display")
97            .field("tag", &self.0.tag())
98            .finish()
99    }
100}
101
102impl std::fmt::Display for Display<'_> {
103    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104        write!(f, "{}", self.0.tag())?;
105        match self.0.visibility() {
106            Visibility::Available => {}
107            Visibility::Gated { features } => {
108                write!(f, " (requires the {})", features)?;
109            }
110        }
111        Ok(())
112    }
113}
114
115/// Orders [`Registered`] inputs in the following order:
116///
117/// 1. Available items in alphabetical order.
118/// 2. Unavailable (gated) items in alphabetical order.
119pub(crate) fn order_inputs(a: &Registered<'_>, b: &Registered<'_>) -> std::cmp::Ordering {
120    a.visibility()
121        .cmp(&b.visibility())
122        .then_with(|| a.tag().cmp(b.tag()))
123}
124
125pub(crate) mod internal {
126    use super::*;
127
128    use crate::Features;
129
130    /// Runtime representation of a deserialized [`Input`].
131    #[derive(Debug)]
132    pub(crate) struct Any {
133        any: Box<dyn RuntimeAny>,
134    }
135
136    impl Any {
137        pub(crate) fn new<T>(input: T) -> Self
138        where
139            T: Input,
140        {
141            Self {
142                any: Box::new(input),
143            }
144        }
145
146        #[must_use = "this function has no side effects"]
147        pub(crate) fn tag(&self) -> &'static str {
148            self.any.tag()
149        }
150
151        #[must_use = "this function has no side effects"]
152        pub(crate) fn downcast_ref<T>(&self) -> Option<&T>
153        where
154            T: std::any::Any,
155        {
156            self.any.as_any().downcast_ref::<T>()
157        }
158
159        #[must_use = "this function has no side effects"]
160        pub(crate) fn is<T>(&self) -> bool
161        where
162            T: std::any::Any,
163        {
164            self.any.as_any().is::<T>()
165        }
166
167        #[must_use = "this function has no side effects"]
168        pub(crate) fn serialize(&self) -> anyhow::Result<serde_json::Value> {
169            self.any.serialize()
170        }
171    }
172
173    trait RuntimeAny: std::fmt::Debug {
174        fn tag(&self) -> &'static str;
175        fn as_any(&self) -> &dyn std::any::Any;
176        fn serialize(&self) -> anyhow::Result<serde_json::Value>;
177    }
178
179    impl<T> RuntimeAny for T
180    where
181        T: Input,
182    {
183        fn tag(&self) -> &'static str {
184            <Self as Input>::tag()
185        }
186
187        fn as_any(&self) -> &dyn std::any::Any {
188            self
189        }
190
191        fn serialize(&self) -> anyhow::Result<serde_json::Value> {
192            <Self as Input>::serialize(self)
193        }
194    }
195
196    // Wrapper for user-supplied inputs.
197
198    #[derive(Debug)]
199    pub(crate) struct Wrapper<T>(std::marker::PhantomData<T>);
200
201    impl<T> Wrapper<T> {
202        pub(crate) const INSTANCE: Self = Self::new();
203
204        pub(crate) const fn new() -> Self {
205            Self(std::marker::PhantomData)
206        }
207    }
208
209    impl<T> Clone for Wrapper<T> {
210        fn clone(&self) -> Self {
211            *self
212        }
213    }
214
215    impl<T> Copy for Wrapper<T> {}
216
217    pub(crate) trait DynInput {
218        fn tag(&self) -> &'static str;
219        fn try_deserialize(
220            &self,
221            serialized: &serde_json::Value,
222            checker: &mut Checker,
223        ) -> anyhow::Result<Any>;
224        fn example(&self) -> anyhow::Result<serde_json::Value>;
225
226        // visibility
227        fn visibility(&self) -> Visibility<'_>;
228
229        // reflection
230        fn as_any(&self) -> &dyn std::any::Any;
231        fn type_name(&self) -> &'static str;
232    }
233
234    impl<T> DynInput for Wrapper<T>
235    where
236        T: Input,
237    {
238        fn tag(&self) -> &'static str {
239            T::tag()
240        }
241        fn try_deserialize(
242            &self,
243            serialized: &serde_json::Value,
244            checker: &mut Checker,
245        ) -> anyhow::Result<Any> {
246            let raw = <T::Raw as serde::Deserialize<'_>>::deserialize(serialized)?;
247            Ok(Any::new(T::from_raw(raw, checker)?))
248        }
249        fn example(&self) -> anyhow::Result<serde_json::Value> {
250            Ok(serde_json::to_value(T::example())?)
251        }
252        fn visibility(&self) -> Visibility<'_> {
253            Visibility::Available
254        }
255        fn as_any(&self) -> &dyn std::any::Any {
256            self
257        }
258        fn type_name(&self) -> &'static str {
259            std::any::type_name::<T>()
260        }
261    }
262
263    /// An input that isn't compiled into a version of a binary, but exists behind a feature
264    /// flag. Including it internally allows us to provide better error messages if we
265    /// discover this `tag` in the wild so we can point users towards its associated `features`.
266    #[derive(Debug)]
267    pub(crate) struct Gated {
268        tag: &'static str,
269        features: Features,
270    }
271
272    impl Gated {
273        pub(crate) fn new(tag: &'static str, features: Features) -> Self {
274            Self { tag, features }
275        }
276
277        pub(crate) fn tag(&self) -> &'static str {
278            self.tag
279        }
280
281        pub(crate) fn features(&self) -> &Features {
282            &self.features
283        }
284    }
285
286    impl DynInput for Gated {
287        fn tag(&self) -> &'static str {
288            self.tag
289        }
290        fn try_deserialize(
291            &self,
292            _serialized: &serde_json::Value,
293            _checker: &mut Checker,
294        ) -> anyhow::Result<Any> {
295            anyhow::bail!(
296                "use of the \"{}\" input is gated behind the {}",
297                self.tag,
298                self.features
299            );
300        }
301        fn example(&self) -> anyhow::Result<serde_json::Value> {
302            anyhow::bail!(
303                "use of the \"{}\" input is gated behind the {}",
304                self.tag,
305                self.features,
306            );
307        }
308        fn visibility(&self) -> Visibility<'_> {
309            Visibility::Gated {
310                features: &self.features,
311            }
312        }
313        fn as_any(&self) -> &dyn std::any::Any {
314            self
315        }
316        fn type_name(&self) -> &'static str {
317            std::any::type_name::<Self>()
318        }
319    }
320}