"Symmetric" generic type

I'm trying to implement some conversion between generics with different parameters. The "converter" can operate both ways at once, but I can't make Rust understand it. Consider the following code, with the Pair being the "converter":

use std::marker::PhantomData;

#[derive(Copy, Clone)]
struct Pair<T1: Copy, T2: Copy>(PhantomData<(T1, T2)>);

struct Data<T: Copy>(PhantomData<T>);

impl<T: Copy> Data<T> {
    fn remake<T2: Copy>(self, _: Pair<T, T2>) -> Data<T2> {
        Data(PhantomData)
    }
}

fn main() {
    let pair: Pair<u32, &str> = Pair(PhantomData);
    let data: Data<u32> = Data(PhantomData);
    
    let data2 = data.remake(pair);
    
    // let _ = data2.remake(pair); - error, type mismatch
}

(Playground)

It it possible somehow to make the last line compile, too? Of course, I can add something like this:

impl<T1: Copy, T2: Copy> Pair<T1, T2> {
    pub fn swap(self) -> Pair<T2, T1> {
        Pair(PhantomData)
    }
}

And use data2.remake(pair.swap()). But is it possible without an additional explicit call?

I'd prefer something that works on stable (since on nightly, it seems, I can work this around playing with Fn traits somehow, but this looks like something too complex).

No, you can't get rid of the extra call. What would you do in the case of Pair<u32, u32> when applied to Data<u32>? Both pair and pair.swap() could work, so which should Rust pick?

Well, for Pair<T, T> the conversion is effectively a no-op (no runtime logic at all), but I've got the idea: since we can't special-case it, we must account for its existence. Thanks, this makes sense.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.