From d8eb67d2d8d2918d4950c688bd0045731fb44b95 Mon Sep 17 00:00:00 2001 From: Mark Hildebrand Date: Fri, 24 Jul 2026 16:50:20 -0700 Subject: [PATCH 1/7] Cleanup lazystring. --- diskann-utils/src/lazystring.rs | 90 ++++++++++++++++++++------------- 1 file changed, 56 insertions(+), 34 deletions(-) diff --git a/diskann-utils/src/lazystring.rs b/diskann-utils/src/lazystring.rs index 72ec2c6d1..ec5d784b2 100644 --- a/diskann-utils/src/lazystring.rs +++ b/diskann-utils/src/lazystring.rs @@ -5,18 +5,65 @@ use std::fmt::{Display, Error, Formatter}; -/// A struct used to lazily defer creation of custom async logging messages until we know -/// that the message is actually needed. +/// A macro that behaves like `format!` but constructs a [`LazyString`] to defer string +/// formatting if [`Display`] is unused. /// -/// # Context +/// ```rust +/// use diskann_utils::lazy_format; /// -/// Logging in the async context explicitly requires passing of a context pointer to enable -/// CDB to determine the source of error message. To that end, a custom logging function is -/// used. +/// let a: f32 = 10.5; +/// let b: usize = 20; +/// +/// let lazy_string = lazy_format!("This is a test. A = {}, B = {}", a, b); +/// assert_eq!(lazy_string.to_string(), "This is a test. A = 10.5, B = 20"); +/// +/// // Formatting of captured members is deferred until the created `LazyString` is formatted. +/// #[derive(Default)] +/// struct Formatted(std::cell::Cell); +/// +/// impl Formatted { +/// fn was_formatted(&self) -> bool { +/// self.0.get() +/// } +/// +/// fn mark_as_formatted(&self) { +/// self.0.set(true) +/// } +/// } +/// +/// impl std::fmt::Display for Formatted { +/// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +/// if self.was_formatted() { +/// f.write_str("yes") +/// } else { +/// self.mark_as_formatted(); +/// f.write_str("not yet") +/// } +/// } +/// } +/// +/// let f = Formatted::default(); +/// let lazy = lazy_format!("Was this formatted: {}", f); +/// +/// assert!(!f.was_formatted(), "string formatting should be deferred"); +/// assert_eq!(lazy.to_string(), "Was this formatted: not yet"); +/// +/// assert!(f.was_formatted()); +/// assert_eq!(lazy.to_string(), "Was this formatted: yes"); +/// ``` +#[macro_export] +macro_rules! lazy_format { + ($($arg:tt)*) => { + $crate::LazyString::new(|f: &mut std::fmt::Formatter<'_>| { + write!(f, $($arg)*) + }) + } +} + +/// A struct used to lazily defer string formatting until needed. This is used to implement +/// [`lazy_format`]: a lazy version of the standard `format!` macro. /// -/// The `LazyString` captures a lambda that constructs the logging message and implements -/// `std::fmt::Display`, allowing string formatting to only be performed once we know a -/// message needs to be logged. +/// See [`lazy_format`] for usage. pub struct LazyString(F) where F: Fn(&mut Formatter<'_>) -> Result<(), Error>; @@ -41,31 +88,6 @@ where } } -/// A macro that behaves like `format!` but constructs a `diskann::utils::LazyString` -/// to enable deferred evaluation of the error message. -/// -/// Invoking this macro has the following equivalence: -/// ```ignore -/// let a: f32 = 10.5; -/// let b: usize = 20; -/// // Macro form -/// let lazy_from_macro = lazy_format("This is a test. A = {}, B = {}", a, b); -/// -/// // Direct form -/// let lazy_direct = crate::utils::LazyString::new(|f: &mut std::fmt::Formatter<'_>| { -/// write!(f, "ihis is a test. A = {}, B = {}", a, b) -/// }); -/// ``` -#[macro_export] -macro_rules! lazy_format { - ($($arg:tt)*) => { - // Must be a full path and only available inside `DiskANN`. - $crate::LazyString::new(|f: &mut std::fmt::Formatter<'_>| { - write!(f, $($arg)*) - }) - } -} - #[cfg(test)] mod test { use super::*; From 016fe50a9f1d7267d9d5026af4d8c4f4a33ad6d1 Mon Sep 17 00:00:00 2001 From: Mark Hildebrand Date: Fri, 24 Jul 2026 16:56:16 -0700 Subject: [PATCH 2/7] Cleanup `LazyString`. --- diskann-utils/src/lazystring.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/diskann-utils/src/lazystring.rs b/diskann-utils/src/lazystring.rs index ec5d784b2..afffdc459 100644 --- a/diskann-utils/src/lazystring.rs +++ b/diskann-utils/src/lazystring.rs @@ -3,10 +3,11 @@ * Licensed under the MIT license. */ -use std::fmt::{Display, Error, Formatter}; +use std::fmt::{Display, Result, Formatter}; /// A macro that behaves like `format!` but constructs a [`LazyString`] to defer string -/// formatting if [`Display`] is unused. +/// formatting until the result is actually displayed. If the [`LazyString`] is never +/// displayed, this construct has minimal overhead. /// /// ```rust /// use diskann_utils::lazy_format; @@ -43,7 +44,7 @@ use std::fmt::{Display, Error, Formatter}; /// } /// /// let f = Formatted::default(); -/// let lazy = lazy_format!("Was this formatted: {}", f); +/// let lazy = lazy_format!("Was this formatted: {f}"); /// /// assert!(!f.was_formatted(), "string formatting should be deferred"); /// assert_eq!(lazy.to_string(), "Was this formatted: not yet"); @@ -66,11 +67,11 @@ macro_rules! lazy_format { /// See [`lazy_format`] for usage. pub struct LazyString(F) where - F: Fn(&mut Formatter<'_>) -> Result<(), Error>; + F: Fn(&mut Formatter<'_>) -> Result; impl LazyString where - F: Fn(&mut Formatter<'_>) -> Result<(), Error>, + F: Fn(&mut Formatter<'_>) -> Result, { /// Construct a new `LazyString` around the provided lambda. pub fn new(f: F) -> Self { @@ -80,14 +81,18 @@ where impl Display for LazyString where - F: Fn(&mut Formatter<'_>) -> Result<(), Error>, + F: Fn(&mut Formatter<'_>) -> Result, { #[inline] - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { (self.0)(f) } } +/////////// +// Tests // +/////////// + #[cfg(test)] mod test { use super::*; From db768a0dca4d4a5e64add461d0ef791ac70e2c83 Mon Sep 17 00:00:00 2001 From: Mark Hildebrand Date: Fri, 24 Jul 2026 17:07:34 -0700 Subject: [PATCH 3/7] Run formatter and fix cross-references. --- diskann-utils/src/lazystring.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/diskann-utils/src/lazystring.rs b/diskann-utils/src/lazystring.rs index afffdc459..7fc0e7830 100644 --- a/diskann-utils/src/lazystring.rs +++ b/diskann-utils/src/lazystring.rs @@ -3,7 +3,7 @@ * Licensed under the MIT license. */ -use std::fmt::{Display, Result, Formatter}; +use std::fmt::{Display, Formatter, Result}; /// A macro that behaves like `format!` but constructs a [`LazyString`] to defer string /// formatting until the result is actually displayed. If the [`LazyString`] is never @@ -62,9 +62,9 @@ macro_rules! lazy_format { } /// A struct used to lazily defer string formatting until needed. This is used to implement -/// [`lazy_format`]: a lazy version of the standard `format!` macro. +/// [`lazy_format!`]: a lazy version of the standard `format!` macro. /// -/// See [`lazy_format`] for usage. +/// See [`lazy_format!`] for usage. pub struct LazyString(F) where F: Fn(&mut Formatter<'_>) -> Result; @@ -74,6 +74,7 @@ where F: Fn(&mut Formatter<'_>) -> Result, { /// Construct a new `LazyString` around the provided lambda. + #[doc(hidden)] pub fn new(f: F) -> Self { Self(f) } From 128510daed359857be125b0ae051742d86ea703a Mon Sep 17 00:00:00 2001 From: Mark Hildebrand Date: Fri, 24 Jul 2026 17:41:30 -0700 Subject: [PATCH 4/7] New features! --- diskann-utils/src/lazystring.rs | 61 +++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/diskann-utils/src/lazystring.rs b/diskann-utils/src/lazystring.rs index 7fc0e7830..adb76ddcb 100644 --- a/diskann-utils/src/lazystring.rs +++ b/diskann-utils/src/lazystring.rs @@ -3,7 +3,7 @@ * Licensed under the MIT license. */ -use std::fmt::{Display, Formatter, Result}; +use std::fmt::{Debug, Display, Formatter, Result}; /// A macro that behaves like `format!` but constructs a [`LazyString`] to defer string /// formatting until the result is actually displayed. If the [`LazyString`] is never @@ -52,13 +52,38 @@ use std::fmt::{Display, Formatter, Result}; /// assert!(f.was_formatted()); /// assert_eq!(lazy.to_string(), "Was this formatted: yes"); /// ``` +/// +/// # Creating lazily formatted `'static` error messages +/// +/// The default [`LazyString`] created by this macro borrows from its formatted arguments +/// and thus has a lifetime constrained to its arguments. +/// +/// If a lazily formatted `'static` compliant variation is needed, the "move" variant +/// can be used: +/// +/// ```rust +/// use diskann_utils::lazy_format; +/// +/// fn assert_static(_: &T) {} +/// +/// let x = 10; +/// +/// let lazy = lazy_format!(move, "x = {x}"); +/// assert_static(&lazy); +/// assert_eq!(lazy.to_string(), "x = 10"); +/// ``` #[macro_export] macro_rules! lazy_format { + (move, $($arg:tt)*) => { + $crate::LazyString::new(move |f: &mut std::fmt::Formatter<'_>| { + write!(f, $($arg)*) + }) + }; ($($arg:tt)*) => { $crate::LazyString::new(|f: &mut std::fmt::Formatter<'_>| { write!(f, $($arg)*) }) - } + }; } /// A struct used to lazily defer string formatting until needed. This is used to implement @@ -90,6 +115,29 @@ where } } +impl Debug for LazyString +where + F: Fn(&mut Formatter<'_>) -> Result, +{ + #[inline] + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + struct AsDisplay<'a, T>(&'a T); + + impl Debug for AsDisplay<'_, T> + where + T: Display, + { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + write!(f, "{}", self.0) + } + } + + f.debug_tuple("LazyString") + .field(&AsDisplay(&self)) + .finish() + } +} + /////////// // Tests // /////////// @@ -98,6 +146,8 @@ where mod test { use super::*; + fn assert_static(_: &T) {} + #[test] fn test_lazy_string() { let x: f32 = 10.5; @@ -110,5 +160,12 @@ mod test { let lazy = lazy_format!("Lazy Message: x = {x}, y = {y}"); assert_eq!(lazy.to_string(), "Lazy Message: x = 10.5, y = 20"); + + let lazy = lazy_format!(move, "Lazy Message: x = {}, y = {y}", x); + assert_static(&lazy); + assert_eq!(lazy.to_string(), "Lazy Message: x = 10.5, y = 20"); + + // Verify that `Debug` at least runs. + let _ = format!("{:?}", lazy); } } From 779fb61d3f4e79d515b0180d4316b989224d7c91 Mon Sep 17 00:00:00 2001 From: Mark Hildebrand Date: Fri, 24 Jul 2026 17:47:33 -0700 Subject: [PATCH 5/7] Fully qualify `write!`. --- diskann-utils/src/lazystring.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/diskann-utils/src/lazystring.rs b/diskann-utils/src/lazystring.rs index adb76ddcb..763e64adf 100644 --- a/diskann-utils/src/lazystring.rs +++ b/diskann-utils/src/lazystring.rs @@ -76,12 +76,12 @@ use std::fmt::{Debug, Display, Formatter, Result}; macro_rules! lazy_format { (move, $($arg:tt)*) => { $crate::LazyString::new(move |f: &mut std::fmt::Formatter<'_>| { - write!(f, $($arg)*) + ::core::write!(f, $($arg)*) }) }; ($($arg:tt)*) => { $crate::LazyString::new(|f: &mut std::fmt::Formatter<'_>| { - write!(f, $($arg)*) + ::core::write!(f, $($arg)*) }) }; } From 60cedaa76891023beb49362356b1e52c2afd9456 Mon Sep 17 00:00:00 2001 From: Mark Hildebrand Date: Fri, 24 Jul 2026 17:52:20 -0700 Subject: [PATCH 6/7] Simplify `Debug` implementation. --- diskann-utils/src/lazystring.rs | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/diskann-utils/src/lazystring.rs b/diskann-utils/src/lazystring.rs index 763e64adf..1b17ab728 100644 --- a/diskann-utils/src/lazystring.rs +++ b/diskann-utils/src/lazystring.rs @@ -121,19 +121,8 @@ where { #[inline] fn fmt(&self, f: &mut Formatter<'_>) -> Result { - struct AsDisplay<'a, T>(&'a T); - - impl Debug for AsDisplay<'_, T> - where - T: Display, - { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - write!(f, "{}", self.0) - } - } - f.debug_tuple("LazyString") - .field(&AsDisplay(&self)) + .field(&format_args!("{self}")) .finish() } } @@ -166,6 +155,9 @@ mod test { assert_eq!(lazy.to_string(), "Lazy Message: x = 10.5, y = 20"); // Verify that `Debug` at least runs. - let _ = format!("{:?}", lazy); + assert_eq!( + format!("{:?}", lazy), + "LazyString(Lazy Message: x = 10.5, y = 20)", + ); } } From 451d2dfbb5b5e03d5522c9f43bccb9fe45c013ac Mon Sep 17 00:00:00 2001 From: Mark Hildebrand Date: Fri, 24 Jul 2026 17:55:08 -0700 Subject: [PATCH 7/7] Verify capture. --- diskann-utils/src/lazystring.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/diskann-utils/src/lazystring.rs b/diskann-utils/src/lazystring.rs index 1b17ab728..999c3307e 100644 --- a/diskann-utils/src/lazystring.rs +++ b/diskann-utils/src/lazystring.rs @@ -59,7 +59,7 @@ use std::fmt::{Debug, Display, Formatter, Result}; /// and thus has a lifetime constrained to its arguments. /// /// If a lazily formatted `'static` compliant variation is needed, the "move" variant -/// can be used: +/// can be used (assuming all captured arguments are `'static`): /// /// ```rust /// use diskann_utils::lazy_format;