I've made a small example in the Playground of my situation: Rust Playground
Defining a trait called Engine with methods set_msg and set_num doesn't help either, because one runs into various Size related issues (there area a bunch of other things that don't work in the following example; I've not bothered to get it working for now)?
How do I go about implementing this pattern of having a Framework, and then at compile time (through a macro) have it use specific Engines from which it takes some functions whose names are standardized across Engines?
Yes, that's probably what I'll have to do in the end, but I'm wondering if I can avoid that by making it more "programmatic"? That is, the user can set the library within their code, rather than within Cargo.toml?
Why not just make the Engine implementations public and let the user construct a Framework with their particular engine (e.g. Framework::new_with_engine(EngineA::default()))? That's the easiest way for a user to choose which implementation they use.
If you don't want end users to be able to construct an engine, one way to encapsulate this is to have various constructors functions which create a Framework with the desired engine.
You can't really make your Framework generic over some engine type, E, and keep the concrete engine type private though, because you'll still be exposing it in the constructor function's return type.
Hi steffahn: wow! Why is providing a marker: PhantomData<fn() -> E enough to make things work? (you can give me the name of the relevant concept and I can read up on it)
The usage of PhantomData<fn() -> E> instead of PhantomData<E> is to communicate to the compiler that the Framework<E> does not actually or even logically actually contain a value of type E, otherwise you’ll get auto-traits bound on E, e.g. you’ll get an impl<E> Send for Framework<E> where E: Send with this unnecessary extra where bound E: Send if you don’t use e.g. fn() -> … to avoid it.