I'm looking to create a macro to generate thin wrappers for some basic types, for example, the syntax:
wrapper!(String => Email);
would expand to something roughly like:
struct Email {
inner: String,
}
impl Email {
// some boilerplate-y stuff
}
However, I'd like these types to implement some stdlib traits where appropriate (e.g. Eq, Clone, Copy, etc. In particular, Copy is causing problems here.
I'd like the wrapper type to be Copy if the inner type is Copy (similar to how #[derive] works), however if I put a derive implementation on the generated trait, I get an error if incompatible:
macro_rules! wrapper {
($inner:ty => $name:ident) => {
#[derive(Copy)]
struct $name {
inner: $inner
}
}
}
wrapper!(i64 => Version); // works fine
wrapper!(String => Email); // Error, String is not Copy
Instead of a compile-time error when using a non-copy type, I'd rather it just "didn't try to implement Copy", but I'm not sure how to express that in macros.
Another unsuccessful attempt looked like:
// inside macro
impl Copy for $name where $inner: Copy {}
But this gave me the same String is not Copy error. I would have hoped that, during expansion, when it hits: impl Copy for Email where String: Copy it would realise: "String: Copy is not satisfied, so this implementation is not valid" and move on, but instead it just errors.
Is there any way to have a macro expand into different code based on trait implementations?