Negative tuple indexes

I have several types like this:

struct A(Vec<i32>);
struct B(String, Vec<i32>);
struct C(String, String, Vec<i32>);
// ... more

What all the types have in common is that the last field is always a Vec<i32>. I want to write a macro that will define a method push back onto the Vec:

macro_rules! impl_append {
    ($type:ident) => {{
        impl $type {
            fn append(&mut self, i: i32) {
                self.-1.push(i); // illegal! -1 isn't a valid tuple index
            }
        }
    }}
}

But it looks like I can't reverse index a tuple. Is there a way to do this?

Indeed, there’s no such thing as negative tuple-struct indices.

You can provide the index of the field as an argument to the macro. Or consider named fields.

4 Likes

Is it not possible to make the Vec the first field of every struct?

2 Likes

Unless there is a particular reason you cannot change your data structure, you might be better off with something like struct Data<const N: usize>([String; N], Vec<i32>).

1 Like

Ah in this case the Strings were just there to illustrate that the Vec wasn't always at the same forward index. There are other types in practice so I can't substitute an array.

I could, it's just not the natural order for arguments from a user perspective.

Yeah I think this is what I'm gonna do

In this case, also consider two level of structs:

struct A((), Vec<i32>);
struct B((String,), Vec<i32>);
struct C((String, String), Vec<i32>);

// ~~~ or ~~~

struct Data<Rest>(Rest, Vec<i32>);

Since you have mentioned "arguments", I suspect this would translate to an additional pair of parenthesis on your call sites, which isn't nothing but isn't that big of a deal either.

2 Likes

It's also possible to do with pattern matching:

macro_rules! impl_append {
    ($type:ident) => {
        impl $type {
            fn append(&mut self, i: i32) {
                let $type(.., v) = self;
                v.push(i);
            }
        }
    }
}
17 Likes

That's neat, had no idea I could do that :smiley:

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.