PureW
PureW

Reputation: 5075

Equivalent of __func__ or __FUNCTION__ in Rust?

In C and C++ you can get the name of the currently executing function through the __func__ macro with C99 & C++11 and ___FUNCTION___ for MSVC.

Is there an equivalent of this in Rust?

Example of __func__ in C:

#include "stdio.h"

void funny_hello() {
    printf ("Hello from %s\n", __func__);
}

int main() {
    funny_hello();
}

Outputs Hello from funny_hello.

Upvotes: 53

Views: 19576

Answers (6)

Veedrac
Veedrac

Reputation: 60137

You can hack one together with std::any::type_name.

macro_rules! function {
    () => {{
        fn f() {}
        fn type_name_of<T>(_: T) -> &'static str {
            std::any::type_name::<T>()
        }
        let name = type_name_of(f);
        name.strip_suffix("::f").unwrap()
    }}
}

Note that this gives a full pathname, so my::path::my_func instead of just my_func. A demo is available.

Upvotes: 55

qalisander
qalisander

Reputation: 31

Adding to Alexis's answer there is a more idiomatic way to write this macro that also works inside rust async functions. Otherwise you will get {{closure}} in async function instead of real function name.

macro_rules! function {
    () => {{
        fn f() {}
        fn type_name_of<T>(_: T) -> &'static str {
            std::any::type_name::<T>()
        }
        type_name_of(f)
            .rsplit("::")
            .find(|&part| part != "f" && part != "{{closure}}")
            .expect("Short function name")
    }};
}

Upvotes: 3

Leśny Rumcajs
Leśny Rumcajs

Reputation: 2516

While there's a lack of official support, there's the stdext crate (also mentioned in the RFC issue) that makes it easy to use.

use stdext::function_name;

fn foo() {
  println!("{}", function_name!());
}

This includes module/trait names, like ::module::Trait::function if any.

If you only care about the name and not its entire path, you could do something like this for trait methods (keep in mind that there is runtime overhead for this, you may want to limit it with, e.g. OnceCell):

let fn_name = function_name!()
              .rsplit_once(':')
              .expect("could not parse function name")
              .1;

Upvotes: 0

Troy Daniels
Troy Daniels

Reputation: 3598

It appears that function_name crate will do this.

https://docs.rs/function_name/latest/function_name/

The example from the docs is

use ::function_name::named;

#[named]
fn my_super_duper_function ()
{
    assert_eq!(
        function_name!(),
        "my_super_duper_function",
    );
}

I am not involved with the project and have not actually tried it yet.

Upvotes: 10

Alexis
Alexis

Reputation: 165

Adding to Veedrac's answer, you can get the function's name without its full path by adding this:

macro_rules! function {
    () => {{
        fn f() {}
        fn type_name_of<T>(_: T) -> &'static str {
            std::any::type_name::<T>()
        }
        let name = type_name_of(f);

        // Find and cut the rest of the path
        match &name[..name.len() - 3].rfind(':') {
            Some(pos) => &name[pos + 1..name.len() - 3],
            None => &name[..name.len() - 3],
        }
    }};
}

You will get my_func instead of my::path::my_func for example.

Upvotes: 12

Trevor Hickey
Trevor Hickey

Reputation: 37836

There was an RFC about this, but it was never agreed upon or implemented.

The rationale for its absence:

"In general I don't think any of us have given an inordinate amount of thought to these "debugging related" macros in terms of long term stability. Most of them seem fairly harmless, but committing to provide all of them for all Rust programs forever is a strong commitment to make. We may want to briefly consider the story of these macros in conjunction with considering adding this new macro."

Maybe Rust will have something comparable in the future,
but for now you will need to rely on your own tagging.

side note: __FUNCTION__ is non standard, __func__ exists in C99 / C++11.

Upvotes: 32

Related Questions