Howdy Rustaceans!
I've just released boilermates – a wondrous (read experimental) proc macro that would allow you to "share" fields between structs, easily convert between them (using from
and such), and define common functionality based on the fields they have in common.
It's very much 0.1, and has some hygiene issues, but, you can already do some cool stuff.
For example, you want to have structs A
, B
and AB
. All "related", but not quite identical. You can do something like:
#[boilermates("A", "B")]
struct AB {
// this field should be in all structs
field_1: usize,
// this field should be only in A and AB
#[boilermates(only_in("A", "AB"))]
field_2: usize,
// this field should be only in B and AB
#[boilermates(not_in("A"))]
field_3: usize,
// this field should be in all structs
field_4: usize,
// this field should be in all structs
field_5: usize,
}
This will result in the generation of:
struct A {
field_1: usize,
field_2: usize,
field_4: usize,
field_5: usize,
}
struct B {
field_1: usize,
field_3: usize,
field_4: usize,
field_5: usize,
}
struct AB {
field_1: usize,
field_2: usize,
field_3: usize,
field_4: usize,
field_5: usize,
}
But you also would get the following implementations for conversion, where you need only to supply what's missing in order to convert between the types, or just do a from
/into
if the target struct contains all the fields of the source struct:
impl From<AB> for A
impl From<AB> for B
-
A::into_b
:fn (field_3: usize) -> B
-
A::into_a_b
:fn (field_3: usize) -> AB
-
B::into_a
:fn (field_2: usize) -> A
-
B::into_a_b
:fn (field_2: usize) -> AB
You can also define common functionality with the generated Has{Field}
traits that have getters like so:
trait ABCommon: HasField1 + HasField4 + HasField5 {
fn sum_common_fields(&self) -> usize {
self.field_1() + self.field_4() + self.field_5()
}
}
impl<T: HasField1 + HasField4 + HasField5> ABCommon for T {}
And now all three structs have the sum_common_fields()
method. You can of course create more specialized traits that would apply only to a subset of the structs, for example HasField2
is only implemented for A
and AB
.
Of course you can pass attributes to the generated structs and to the fields as well.
I find this thing to be useful in APIs where the user input struct doesn't contain the ID of the object, and the output value doesn't need to contain some internal information.
Suggestions and pull requests are welcome. I'll of course continue improving it in the meantime.