I'm trying to write a declarative macro for generating trait implementations that differ only in type, a literal, and the expression used to retrieve a value from an argument. My code at the moment is:
use bytes::{Buf, Bytes};
use std::net::Ipv4Addr;
pub trait TryFromBuf: Sized {
fn try_from_buf(buf: &mut Bytes) -> Result<Self, PacketError>;
}
macro_rules! impl_tryfrombuf {
($t:ty, $len:literal, $get:expr) => {
impl TryFromBuf for $t {
fn try_from_buf(buf: &mut Bytes) -> Result<Self, PacketError> {
if buf.remaining() >= $len {
Ok($get)
} else {
Err(PacketError)
}
}
}
};
}
impl_tryfrombuf!(u32, 4, buf.get_u32());
impl_tryfrombuf!(Ipv4Addr, 4, buf.get_u32().into());
pub struct PacketError;
However, this fails to compile, apparently because buf
is not defined at the point where the macro is invoked:
error[E0425]: cannot find value `buf` in this scope
--> src/lib.rs:22:26
|
22 | impl_tryfrombuf!(u32, 4, buf.get_u32());
| ^^^ not found in this scope
error[E0425]: cannot find value `buf` in this scope
--> src/lib.rs:23:31
|
23 | impl_tryfrombuf!(Ipv4Addr, 4, buf.get_u32().into());
| ^^^ not found in this scope
For more information about this error, try `rustc --explain E0425`.
I've tried changing :expr
to :stmnt
, changing :expr
to :block
and adding braces around the expressions, and changing $get:expr
& Ok($get)
to $($get:tt)+
& Ok($( $get )+)
, but none have compiled. How can I make this work?