Skip to main content

diskann_utils/
lazystring.rs

1/*
2 * Copyright (c) Microsoft Corporation.
3 * Licensed under the MIT license.
4 */
5
6use std::fmt::{Display, Error, Formatter};
7
8/// A struct used to lazily defer creation of custom async logging messages until we know
9/// that the message is actually needed.
10///
11/// # Context
12///
13/// Logging in the async context explicitly requires passing of a context pointer to enable
14/// CDB to determine the source of error message. To that end, a custom logging function is
15/// used.
16///
17/// The `LazyString` captures a lambda that constructs the logging message and implements
18/// `std::fmt::Display`, allowing string formatting to only be performed once we know a
19/// message needs to be logged.
20pub struct LazyString<F>(F)
21where
22    F: Fn(&mut Formatter<'_>) -> Result<(), Error>;
23
24impl<F> LazyString<F>
25where
26    F: Fn(&mut Formatter<'_>) -> Result<(), Error>,
27{
28    /// Construct a new `LazyString` around the provided lambda.
29    pub fn new(f: F) -> Self {
30        Self(f)
31    }
32}
33
34impl<F> Display for LazyString<F>
35where
36    F: Fn(&mut Formatter<'_>) -> Result<(), Error>,
37{
38    #[inline]
39    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
40        (self.0)(f)
41    }
42}
43
44/// A macro that behaves like `format!` but constructs a `diskann::utils::LazyString`
45/// to enable deferred evaluation of the error message.
46///
47/// Invoking this macro has the following equivalence:
48/// ```ignore
49/// let a: f32 = 10.5;
50/// let b: usize = 20;
51/// // Macro form
52/// let lazy_from_macro = lazy_format("This is a test. A = {}, B = {}", a, b);
53///
54/// // Direct form
55/// let lazy_direct = crate::utils::LazyString::new(|f: &mut std::fmt::Formatter<'_>| {
56///     write!(f, "ihis is a test. A = {}, B = {}", a, b)
57/// });
58/// ```
59#[macro_export]
60macro_rules! lazy_format {
61    ($($arg:tt)*) => {
62        // Must be a full path and only available inside `DiskANN`.
63        $crate::LazyString::new(|f: &mut std::fmt::Formatter<'_>| {
64            write!(f, $($arg)*)
65        })
66    }
67}
68
69#[cfg(test)]
70mod test {
71    use super::*;
72
73    #[test]
74    fn test_lazy_string() {
75        let x: f32 = 10.5;
76        let y: usize = 20;
77
78        let lazy = LazyString::new(|f: &mut std::fmt::Formatter| {
79            write!(f, "Lazy Message: x = {x}, y = {y}")
80        });
81        assert_eq!(lazy.to_string(), "Lazy Message: x = 10.5, y = 20");
82
83        let lazy = lazy_format!("Lazy Message: x = {x}, y = {y}");
84        assert_eq!(lazy.to_string(), "Lazy Message: x = 10.5, y = 20");
85    }
86}