57

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.

6 Answers 6

58

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.

Sign up to request clarification or add additional context in comments.

6 Comments

Please note that this implementation also has the limitation that it cannot currently be used to build static values, e.g: static name : &'static str = function!();
&name[..name.len() - 3].trim_end_matches("::{{closure}}") would do the trick for async fn
@TeohHanHui That would hide normal closures too, not just the implicit async ones.
Please don't do this. From the documentation for type_name: "The exact contents and format of the string returned are not specified, other than being a best-effort description of the type ... amongst the strings that type_name::<Option<String>>() might return are Option<String> and std::option::Option<std::string::String> ... the output may change between versions of the compiler."
@Shelvacu I think this poor advice to apply to debugging macros. Yes, you should be wary if general program correctness depends on the exact form given here, but for debugging? For something that's been basically stable for 7 years now and at most ends up in your logs? Go for it.
|
32

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.

Comments

12

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.

Comments

10

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.

2 Comments

I just tried this and it appears to work as advertised.
Seems to use a similar approach as seen here: stackoverflow.com/a/56723429/2441655
3

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")
    }};
}

Comments

1

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;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.