Calling a function within a macro

Hello fellow rusters.

I am writing a macro, that uses a set of helper functions.

fn eq<T: PartialEq>(l: T, r: T) -> bool {l == r}
fn ne<T: PartialEq>(l: T, r: T) -> bool {l != r}
fn gt<T: PartialOrd>(l: T, r: T) -> bool {l > r}
fn lt<T: PartialOrd>(l: T, r: T) -> bool {l < r}
fn ge<T: PartialOrd>(l: T, r: T) -> bool {l >= r}
fn le<T: PartialOrd>(l: T, r: T) -> bool {l <= r}

macro_rules! test_member_op {
    ($val:expr, $var:path, $member_name:tt == $member_val:expr) => {
        test_member_op!($val, $var, $member_name, eq, $member_val)
    };
    ($val:expr, $var:path, $member_name:tt != $member_val:expr) => {
        test_member_op!($val, $var, $member_name, ne, $member_val)
    };
   // more options removed for brevity 

    ($val:expr, $var:path, $member_name:tt, $op:tt, $member_val:expr) => {
        if let $var { $member_name, .. } = &$val {
            $op(*$member_name, $member_val)
        } else {
            false
        }
    };
}

It all works well when testing within the file that holds the macro. But when I try to use it, in the use site (in another file), I get an error saying eq is not found in this scope.

I understand why (the macro gets expanded "in place"), but not sure how to solve this in a generic way. Can someone help out?

Thanks!

You could either just import the helper functions before using them, or spell out the fully-qualified path:


    ($val:expr, $var:path, $member_name:tt, $op:tt, $member_val:expr) => {
        if let $var { $member_name, .. } = &$val {
            use $crate::helpers::$op;
            $op(*$member_name, $member_val)

            // or:
            $crate::helpers::$op(*member_name, $member_val)
        } else {
            false
        }
    }

However, is there any reason you don't want to use the standard functions PartialEq::eq etc.?

2 Likes

Thanks for the quick answer. That did the trick.

The reason I did not use PartialEq::eq (I am guessing that is what you meant), is not knowing they were there :frowning: . It works great, and I no longer need the functions.

Thanks again.

No problem. In general, almost all Rust operators are implemented in terms of traits and functions, e.g. & is Deref::deref(), [] is Index::index(), etc. This means that whenever you need to call an operator generically, you can use the corresponding function.

(There are a few exceptions: e.g. foo.bar member access and logical && and || don't have semantics describable by a single function, so those are not available as such.)

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.