I am trying to implement a generic structure with a bunch of fields, where each of the field types should know about the exact type of the whole structure. It's a sort of strategy pattern.
pub struct Example<S: Strategy<Example<S, D>>, D> {
pub s: S,
pub a: S::Associated,
pub data: D,
}
pub trait Strategy<T> {
type Associated;
fn run(&self, &T);
}
pub trait HasData {
type Data;
fn data(&self) -> &Self::Data;
}
impl<S: Strategy<Self>, D> Example<S, D> {
// ^^^^
// the complex code in this impl is the actual meat of the library:
pub fn do_it(&self) {
self.s.run(self); // using the Strategy trait
}
}
impl<S: Strategy<Self>, D> HasData for Example<S, D> {
type Data = D;
fn data(&self) -> &D {
&self.data
}
}
I was planning to then instantiate the generics from the above "library":
pub struct ExampleStrat;
pub struct ExampleData;
impl<E: HasData<Data = ExampleData>> Strategy<E> for ExampleStrat {
type Associated = ();
fn run(&self, e: &E) {
let _ = e.data();
// uses ExampleData here
}
}
let example = Example {
s: ExampleStrat,
a: (),
data: ExampleData,
};
example.do_it();
In my actual code I've got quite a few different "strategies" and also multiple data fields, so the Example type has an impressive list of generics, and I'm happy if the library user doesn't need to be explicit about them (or not often at least) and instead can just use the HasData trait (with its associated types, not generic type parameters).
If there was no type bound in struct Example<S, D>, this would actually work (surprisingly) fine, much better than I has initially expected (after fighting with Self in the struct bounds). However it is recommended to duplicate the impl trait bounds on the struct when the struct is only supposed to be used with the constrained types, and in my case I actually need them to be able to use the Associated type for the a field.
Now the compiler is complaining
error[E0275]: overflow evaluating the requirement `main::ExampleStrat: Strategy<Example<main::ExampleStrat, main::ExampleData>>`
--> src/main.rs:42:9
|
42 | a: (),
| ^^^^^
|
= note: required because of the requirements on the impl of `HasData` for `Example<main::ExampleStrat, main::ExampleData>`
= note: required because of the requirements on the impl of `Strategy<Example<main::ExampleStrat, main::ExampleData>>` for `main::ExampleStrat`
How can I solve this? Am I trying to do something that is not possible, am I doing it wrong, or is it supposed to be possible but I am falling prey to a compiler bug? Is my complete design flawed?