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 }
}
}
}
}