How to impl type match in a macro?

macro_rules! func {
    ($type:ty) => {
        // here do something if type is i64 do A function, otherwise do B function
    }
}

You can't. This is a job for generics, not for macros.

okay, is there any flow control in macro?

Macros can generate code that creates new types, so macros have run before any types are known.

Yes, but is it able to do sth like

    (@handle_float $e:expr) => {
        match $e {
            32 | 64 => {
                 // some code here
            },
            _ => {}
        }
    };

What kind of flow control are you looking for? If you need to run different functions based on types, then you can do this:

trait DoThing {
    fn do_thing();
}

struct A;
impl DoThing for A {
    fn do_thing() {
        println!("I'm A");
    }
}

struct B;
impl DoThing for B {
    fn do_thing() {
        println!("I'm B");
    }
}

fn do_thing<T: DoThing>() {
    T::do_thing();
}

do_thing::<A>();
do_thing::<B>();

This is just regular match code that will evaluate at run time.

The macro isn't doing anything here. It doesn't even know what type $e has. It's like copy-paste of variable names.

That doesn't seem like it handles different types; it handles an expression, which only has a single, specific type, and maybe different values. And yes, you can put that code inside a macro, although there's no benefit in doing so.

Thanks, but what I want is a bit more complicated than that, I want to use macro to reduce code lines.

Yes, I am using paste crate to join the code, so what I receive is a literal number, and I want to add some functions depending on whether the number bigger than 16.

"Reducing lines of code" is a very vague goal. Again, if you need to dispatch on a type, then generics is also an abstraction that will allow you to remove duplication. Macros won't help there. If you don't need to handle more types, then generics (or macros) aren't what you need, either. You'll have to describe what goal are you trying to achieve exactly if you hope to get any reasonably actionable feedback.

1 Like

If multiple patterns match, then macro_rules will always pick the first one, so you can do something like this. But it will be matching only on the token i64: If the user specifies it some other way (like referring to a generic parameter, for instance), it'll fall through to the default case:

macro_rules! func {
    (i64) => {
        // Call A()
    };
    ($type:ty) => {
        // Call B::<$type>()
    };
}

I know that macro will expand, but these are very duplicate impl functions of a trait, it involves i8-i128, u8-u128, f32, f64, most code are duplicated, my goal is using macro generating the functions.

And I already did for int and uint, but I don't know if there is any control flow in macro so I can determine should I impl the function for floats.

What makes you think that a macro is better suited for this than a single generic impl? If you want to implement methods for primitive numeric types, check out num-traits. It has a rich set of traits implemented for diverse groups of types. You can, for example, implement a set of methods only for Float types, which will then be exclusive to floating-point numbers, and you can implement a different set of methods for types implementing Num, which will then also apply to integers.

1 Like

Hi, I get your point but It's not a trait from my code, anyway I gave up this try, thanks for replying.

That doesn't matter. You can use 3rd-party traits as bounds in your own code, too (otherwise they would be pretty useless). My suggestion was something like:

use num_traits::{Num, Float};

trait MyTraitForFloatsOnly {
    fn do_stuff_on_float(self) -> Self;
}

impl<T: Float> MyTraitForFloatsOnly {
    fn do_stuff_on_float(self) -> Self {
        ...
    }
}

trait MyTraitForAllNumbers {
    fn do_stuff_on_any_number(self) -> Self;
}

impl<T: Num> MyTraitForAllNumbers {
    fn do_stuff_on_any_number(self) -> Self {
        ...
    }
}

Actually I am implementing required method in serde::ser::Serialize, so your option would be great if it's something only related to the numbers, by the way, I am using David Tolnay's crate ryu to convert float to str, but there's been a slight problem, is that 3.0 would convert to 3.0, that's correct but what I want is just 3, do you have any suggestions on this?

So which methods are you implementing, and what is the problem you are encountering there? Normally, implementing Serialize doesn't require the kind of excessive boilerplate that would warrant a macro.

You can either chop off the part after the decimal point in string format, or you can check if your floating-point value is an integer, and if so, cast it to an integer and convert the integer to a string.

Ha ha there's no problem, I am just tired of scrolling up and down.

Unfortunately neither is possible, that would lose the meaning of using ryu crate, for performance, or judging performance on this kind of thing is stupid?