1. 1
  1.  

  2. 2

    Yeah, that’s an important tool to have in one’s toolbox! I ended up just writing this snippet of code

    #[must_use]
    pub fn timeit(label: impl Into<String>) -> impl Drop {
        let label = label.into();
        let now = std::time::Instant::now();
        defer(move || eprintln!("{}: {:.2?}", label, now.elapsed()))
    }
    
    #[must_use]
    pub fn defer<F: FnOnce()>(f: F) -> impl Drop {
        struct D<F: FnOnce()>(Option<F>);
        impl<F: FnOnce()> Drop for D<F> {
            fn drop(&mut self) {
                if let Some(f) = self.0.take() {
                    f()
                }
            }
        }
        D(Some(f))
    }
    

    https://github.com/matklad/config/blob/578d46cb024014369c82f05b673f81880e30283f/templates/snippets/src/lib.rs#L44-L62

    which I just copy-paste verbatim every time I need this functionality in a random projects.

    Note: do use {:.2?} formatting in such cases, excessive precision is rather distracting when working on perf optimizations.

    1. 1

      Do you have an example of how you would call this? How do you inject the code to be measured?

      1. 2

        Here’s the edit I’d do to check which fraction of total auto-import functionality in rust-analyzer is due to searching for possible imports:

        https://github.com/matklad/rust-analyzer/commit/5c94a84968176f1c88379adaddbb3a0bc7ac47dc

        Though, in case of rust-analyzer specifically, we actually have a dedicated module where we dump missing batteries, so I’d just use that:

        https://github.com/rust-lang/rust-analyzer/blob/994f3cf74dea8730e473c4ad483bea0baff491c9/crates/stdx/src/lib.rs#L19

        1. 1

          And then there was enlightenment!

          It was staring at me in the face, I over fixated on the Drop stuff to not realize that drop is used to signal the end of the block and emit the timing information. The docstring would be something like, “prints elapsed time to stderr when current scope drops”.

          Thank you, off to read stdx

      2. 1

        Why Option<F> instead of just F?

        1. 1

          For Drop. MaybeUninit<F> would’ve worked as well, but that needs unsafe.

          1. 1

            Ah, I didn’t realize you needed to own the function to call it.

            I incorrectly thought changing Option<F> to F would allow writing self.0().

      3. 1

        The didactic structure of the article is interesting in that takes one through the failure process in writing a seemingly simple Rust macro.