[SOLVED] Macros: &mut self vs. &self

Hello people!

tldr: How can I unify these two macros, adding one more parameter? The only difference is the &self in one and the &mut self in the other.

macro_rules! get_function_nomut {
	( $name:ident, $ref_function:ident, $return_type:ty ) => {
		pub fn $name (&self) -> $return_type {
			$ref_function!(self.data)
		}
	}
}

macro_rules! get_function_mut {
	( $name:ident, $ref_function:ident, $return_type:ty ) => {
		pub fn $name (&mut self) -> $return_type {
			$ref_function!(self.data)
		}
	}
}

Can macros have boolean parameters on which I can check to generate either &self or &mut self in the code?

The above code with some context to make it run can be found here: Rust Playground

Why: The code above is of course simplified. In the actual usage scenario, there is quite some code duplication to avoid. This thread is a follow-up to [SOLVED] Avoid duplication for &mut vs & access

1 Like

One option might be:

macro_rules! get_function {
	($name:ident, $ref_function:ident, $return_type:ty, $typ:ty) => {
		pub fn $name (self: $typ) -> $return_type {
			$ref_function!(self.data)
		}
	};
}

get_function!(get_ref, ref_function_nomut, &i32, &Self);
get_function!(get_ref_mut, ref_function_mut, &mut i32, &mut Self);

So the user of the macro specifies the type of self as the last macro arg.

Another option might be to do something like:

macro_rules! get_function {
	($name:ident, $ref_function:ident, $return_type:ty, immut) => {
		pub fn $name (&self) -> $return_type {
			$ref_function!(self.data)
		}
	};
	($name:ident, $ref_function:ident, $return_type:ty, mut) => {
		pub fn $name (&mut self) -> $return_type {
			$ref_function!(self.data)
		}
	};
}

get_function!(get_ref, ref_function_nomut, &i32, immut);
get_function!(get_ref_mut, ref_function_mut, &mut i32, mut);

Here you have 2 rules that expect either the token "immut" or "mut" - anything else will barf at macro expansion time.

There're likely better/more elegant ways - my macro-fu isn't all that strong :slight_smile:.

2 Likes

Thank you very much, the first method works!

(The second one would lead to the same code duplication as not using macros at all, so I haven't tried it.)