Macros generating method body


#1

I’d like to write a macro that allows optional generation of a method body. Specifically, I’m trying to make newtypes easier (for me) to use (so if there’s a workaround to solve that problem, that would be helpful as well).

Here’s what I’ve got so far:

macro_rules! alias_basic {
	($alias:ident, $t:ty) => {
		pub struct $alias($t);
		impl Display for $alias {
			 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
	 			let $alias(ref v) = *self;
	 			v.fmt(f)
	 		}
		}
		impl Into<$t> for $alias {
			fn into(self) -> $t {
				let $alias(v) = self;
				v
			}
		}
		impl Deref for $alias {
			type Target = $t;
			fn deref<'a>(&'a self) -> &'a $t {
				let $alias(ref v) = *self;
				v
			}
		}		
	}
}

macro_rules! alias {
	($alias:ident, $t:ty) => {
		alias_basic!($alias,$t);
		impl From<$t> for $alias {
			fn from(v: $t) -> Self {
				$alias(v)
			}
		}
	}
}

So far, so good. But what I’d like to do is optionally plug in a TryFrom implementation instead of From, and, if I want a TryFrom, have the macro invocation define the method body.

e.g., I’d want

alias!(Foo,Bar,try_from -> {err -> Quux, body ->  /* baz */});

to expand to (among other things):

impl TryFrom for Foo {
    type Error = Quux; 
    fn try_from (v: Bar) -> Result<Self,Quux> {
        /* baz */
    }
}

I’ve got as far as defining body content as $($body:tt)*, but when the expansion gets to the method body, I get unexpected token errors.


#2

Unfortunately, rust currently needs a little bit of help parsing the tokens:

macro_rules! block_identity {
    ($b:block) => {$b}
}

// And then in your macro:
block_identity!({$($body)*});

#3

Also it will need to know the variable name if you want to do match/check on v. This worked on my machine:

macro_rules! alias {
	($alias:ident, $t:ty, $er_type:ty, $body: block, $v: ident) => {
		alias_basic!($alias,$t);
		impl From<$t> for $alias {
			fn from(v: $t) -> Self {
				$alias(v)
			}
		}
		
	impl TryFrom<$t> for $alias{
            type Error = $er_type; 
            fn try_from ($v: $t) -> Result<Self,$er_type> 
                $body
        }
}
}

And as an example:

alias!(MyS, i32, String, {
    match v {
        0 => Err("This is zero".to_string()),
        _ => Ok(MyS(v))
    }
},v);

Has there been a (rejected?) RFC on derive attributes for newtypes?
#4

Thanks – now running into problems with methods that take self.

Simple example:

macro_rules! foo {
	($name:ident, $body:block) => {
		struct $name { value: u32}
		impl $name {
			fn fooify(&self) -> u32 {
				$body
			}
		}
	}
}

foo!(Abc,{4});
foo!(Bcd,{self.value});

First invocation works fine, second fails:

error: `self` is not available in a static method. Maybe a `self` argument is missing`

This would seem to be a problem with macro hygiene rules?

(Googles)
Ah: