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?