I'm using a macro to implement a trait as part of my library. This implementation requires the struct to have at least one additional field.
pub trait Trait {
fn access_var(&mut self, var: bool);
}
macro_rules! impl_trait {
(for $struct:ident) => {
impl Trait for $struct {
pub fn access_var(&mut self, var: bool) {
self.var = var; // requires self to have a field 'var'
}
}
}
}
I want to prevent the user from having to add those additional fields every time. Due to the fact that the Rust compiler does not allow macros in field definitions (I have no source for this, so please correct me if I'm wrong), something like this does not work.
macro_rules! variables_for_trait {
() => {
var: bool,
}
};
struct Foo {
variables_for_trait!(); // error: expected ':' found '!'
additional_var: i64,
}
I guess that I could create a macro which enables something like this
bar!(Foo with additional_var: i64, other_var: u64);
to look like that after resolving the macro:
pub struct Foo {
var: bool,
additional_var: i64,
other_var: u64,
}
impl Trait for Foo {
pub fn access_var(&mut self, var: bool) {
self.var = var;
}
}
Is there a better way to solve this, and if not, can you give me an example syntax for bar!
?
P.S: What would be a good name for something like bar!
?
I ended up solving the problem with 2 different macros:
// I simply copied it from my project and changed some names,
// But due to the fact that I couldn't think of better names for my macros,
// I just ended up using the original names, even though they don't quite fit
macro_rules! new_object_type {
($struct:ident {$( $field:ident:$type:ty ),*}) =>{
pub struct $struct {
var: bool,
$(
$field: $type,
)*
}
impl Trait for $struct {
pub fn access_var(&mut self, var: bool) {
self.var = var;
}
}
};
}
macro_rules! construct_object {
($struct:ident {$( $field:ident:$value:expr ),*}) => {
$struct {
var: false,
$(
$field: $value,
)*
}
};
}
To create a new struct implementing Trait
you now write:
new_object_type!(Foo {
additional_var: i64,
other_var: u64,
});
And to create a new instance of Foo
you write:
construct_object!(Foo {
additional_var: 42,
other_var: 82000,
})
Now it is possible to use Trait
without ever having to interact with var
.
It is not as clean as I hoped it would be and without proper documentation it is hard to use, especially if the user is fairly new to Rust.
There might be some problem with having two identical fields, as the user does not see all implemented variables (This could be solved by changing the name of var to something like T7dkD3S3O8
which would most certainly make it quite unlikely that this ever happens)
As the definition and the construction of the struct are both inside a macro, error messages could be harder to understand
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With