Tuple variant returns
Closed this issue · 6 comments
As mentioned near the end of #4, it would be a good idea to allow for returning of tuples for tuple variants. For example (courtesy of @TheDan64),
enum Foo {
Bar(bool, u32, f32),
}
fn into_bar(self) -> (bool, u32, f32);
fn as_bar(&self) -> &(bool, u32, f32);
// Or this one, but I think this may be equivalent to the one above
fn as_bar(&self) -> (&bool, &u32, &f32);For as_* methods, the second variant should be returned, since we're referring to the values contained and not an actual tuple.
This also should not add a tuple return for single-item tuples. e.g.
enum Foo {
Bar(bool, u32, f32),
Baz(String)
}
fn as_baz(&self) -> &String { ... } // yes
fn as_baz(&self) -> (&String) { ... } // noI'd be interested in taking a look at this one - any pointers on where I should start?
Yes! I've recently split up the generation methods into files for is_* and the getters (is_a.rs and getters.rs, respectively). You'll be adding stuff to the getters.rs file. If you feel like things start getting too big in that file, feel free to split it up more. Here's some jumping off points:
- If you haven't messed with procedural macros before, I'd heavily recommend reading the tutorial. It's pretty helpful.
- Check out the quote crate and its documentation.
- NB: If you're familiar with writing your own macros, writing things with
quoteis very similar.
- NB: If you're familiar with writing your own macros, writing things with
- Also check out the syn crate and its documentation. This is the most useful because it lays out the AST and the stuff you do to mess with it.
- If you look through the
is_*implementors, they are split up by unit enum, tuple enum, and struct. You may want to do something similar (e.g. tuple enum with 1 element vs. tuple enum with many elements).
I think that's about it. If you've got questions I really don't mind answering them, so do not hesitate to ask (especially if you get stuck). Sorry I haven't commented or documented very much... I should really fix that.
Thanks! So I'm having trouble expanding the tuple in the if let portion:
let variant_types_multiple = getter_filter!()
.filter(|v| v.data.fields().len() > 1)
.map(|v| Ty::Tup(v.data.fields().iter().map(|field| Ty::Rptr(None, Box::new(MutTy { ty: field.ty.clone(), mutability: Mutability::Immutable }))).collect::<Vec<Ty>>()))
.collect::<Vec<Ty>>();
...
#(pub fn #function_names(&self) -> #variant_types_multiple {
if let &#getter_names::#variant_names(ref v) = self {
v
}
}ref v and v, respectively match only a single item. Any idea how I could map to a variable amount of variables? IE ref a, ref b, ref c and (a, b, c)?
You should take a look at is_a.rs around L28 and L38. The former fills a list of _ identifiers, whose length matches the number of items in the tuple for that variant. The latter is where it gets used, in the #(#variant_counts),*) block. That block becomes, for example, _, _, _ for a tuple variant with 3 types. You can probably get away with copy-pasting what's on L28 and instead of generating a _ identifier, generate the identifier for that tuple and put ref in front of it during quoting, e.g. #(ref #variant_counts),*).
You're definitely going to want two different methods to generate this code; one for generating enums with a single tuple item, and one for generating enums with many tuple items.
I hope that helps. I can clarify anything that wasn't clear to you.
That helped a lot, thanks!