My library uses some traits named Vertex
, UniformBlock
and BufferContent
.
These traits are unsafe and dangerous to implement (because for example some methods return the offsets of each member in the struct), so it shouldn’t be left to the user.
The ideal solution would be to have the #[derive_Vertex]
, #[derive_UniformBlock]
and #[derive_BufferContent]
attributes.
But since plugins aren’t stable, I wrote the implement_vertex!
, implement_uniform_block!
and implement_buffer_content!
macros.
They work like this:
unsafe trait Foo {
// some very dangerous methods in there
}
struct Bar { a: u32 }
// obviously the macro is in reality in my library
macro_rules! implement_foo(
($s:ident) => (
unsafe impl Foo for $s {}
);
);
implement_foo!(Bar);
My problem is that recently I had the need for implementing this trait for structs that have lifetimes. And that’s problematic.
The macros don’t need to know there is a lifetime, but they generate impl Foo for Bar
, while it should be impl<'a> Foo for Bar<'a>
.
I tried various tricks with token trees and such, but I can’t manage to write a macro that would work in both situations.
For the moment my work-around is to duplicate the whole macro rule, so that I have two definitions: one for structs with a lifetime and one for structs without a lifetime, like this:
unsafe trait Foo {
// some very dangerous methods in there
}
struct Bar1 { a: u32 }
struct Bar2<'a> { a: &'a u32 }
macro_rules! implement_foo(
($s:ident) => (
unsafe impl Foo for $s {}
);
($s:ident <$l:tt>) => (
unsafe impl<'a> Foo for $s<'a> {}
);
);
implement_foo!(Bar1);
implement_foo!(Bar2<'a>);
But it’s obviously not ideal (especially because the definitions are a hundred lines long each), so is there a better solution?