Conditional trait bounds

TLDR:
for the trait:

trait FieldTypeMap {
    type MappedFieldType<OriginalFieldType>;
}
trait MatchableValue {
    /// type with a field for each field of each variant of `Self`,
    /// but all field types are mapped through `FTM`
    type Template<FTM: FieldTypeMap>;
}

I want to have a bound that guarantees Template<FTM>: Copy but only when MappedFieldType<Field>: Copy for all Field but Template needs to still be usable when MappedFieldType<Field>: !Copy for some Field.

Can anyone think of a way to do that?

Long version:

I'm implementing a proc-macro for some sort of reflection-kinda thing, the proc-macro implements the MatchableValue trait:

// simplified somewhat
trait FieldTypeMap {
    type MappedFieldType<OriginalFieldType>;
}
struct FTMUnit;
impl FieldTypeMap for FTMUnit {
    type MappedFieldType<OriginalFieldType> = ();
}
trait MapFn<MV: MatchableValue> {
    type InputFTM: FieldTypeMap;
    type OutputFTM: FieldTypeMap;
    fn map_fn<OriginalFieldType>(
        &mut self,
        field: InputFTM::MappedFieldType<OriginalFieldType>,
    ) -> OutputFTM::MappedFieldType<OriginalFieldType>;
}
trait MatchableValue {
    /// enum type with the same shape as `Self`,
    /// but all field types are mapped through `FTM`
    type Template<FTM: FieldTypeMap>: Copy if for<T> FTM::MappedFieldType<T>: Copy;
    const VARIANTS: &'static [Self::Template<FTMUnit>];
    fn map<F: MapFn<Self>>(
        input: Self::Template<F::InputFTM>,
        f: &mut F,
    ) -> Self::Template<F::OutputFTM>;
}
// example use:
fn dump_field_types<MV: MatchableValue>() {
    struct F;
    impl<MV: MatchableValue> MapFn<MV> for F {
        type InputFTM = FTMUnit;
        type OutputFTM = FTMUnit;
        fn map_fn<OriginalFieldType>(
            &mut self,
            field: InputFTM::MappedFieldType<OriginalFieldType>,
        ) -> OutputFTM::MappedFieldType<OriginalFieldType> {
            println!("{}", std::any::type_name::<OriginalFieldType>());
        }
    }
    for &variant in MV::VARIANTS { // copy Template<FTMUnit> here
        MV::map(variant, &mut F);
    }
}
// example implementation:
enum MyType<T> {
    A {
        a: u8,
        b: String,
    },
    B {
        x: T,
    },
}
enum MyTypeTemplate<FTM: FieldTypeMap, T> {
    A {
        a: FTM::MappedFieldType<u8>,
        b: FTM::MappedFieldType<String>,
    },
    B {
        x: FTM::MappedFieldType<T>,
    },
}
impl<FTM: FieldTypeMap, T> Copy for MyTypeTemplate<FTM, T>
where
    FTM::MappedFieldType<u8>: Copy,
    FTM::MappedFieldType<String>: Copy,
    FTM::MappedFieldType<T>: Copy,
{}
impl<FTM: FieldTypeMap, T> Clone for MyTypeTemplate<FTM, T>
where
    FTM::MappedFieldType<u8>: Copy,
    FTM::MappedFieldType<String>: Copy,
    FTM::MappedFieldType<T>: Copy,
{
    fn clone(&self) -> Self {
        *self
    }
}
impl<T> MatchableValue for MyType<T> {
    type Template<FTM: FieldTypeMap> = MyTypeTemplate<FTM, T>;
    const VARIANTS: &'static [Self::Template<FTMUnit>] = &[
        MyTypeTemplate::A {a: (), b: ()},
        MyTypeTemplate::B { x: () },
    ];
    fn map<F: MapFn<Self>>(
        input: Self::Template<F::InputFTM>,
        f: &mut F,
    ) -> Self::Template<F::OutputFTM> {
        match input {
            MyTemplate::A { a, b } => {
                let a = f.map_fn(a);
                let b = f.map_fn(b);
                MyTemplate::A { a, b }
            },
            MyTemplate::B { x } => {
                let x = f.map_fn(x);
                MyTemplate::B { x }
            }
        }
    }
}

my current workaround is to have:

trait MatchableValue
where
    Self::Template<FTMUnit>: Copy,
{
   // ...
}

but that's very annoying to use, because I have to repeat the where bound everywhere I use MatchableValue and it doesn't work for any other FieldTypeMap types...

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.