Overview
LibJuno implements dependency injection through modules and API traits. This is very similar to the Rust paradigm. There are 3 components to modules within LibJuno:
- The module
- The module root
- The module derivations
The Module Root
Before talking about the module itself we need to go over the module root.
- The module root is a common set of member variables shared across all module derivations and implementations.
- When a module is derived there is a compile-time gurantee that the module can be safely up-cast to the module root.
- All derivations of the module can up-cast to the module root.
- The module root always provides the following as defined by the macros:
ptApi
– A pointer to the API traits
_pfcnFailureHandler
– A failure handler callback
_pvFailurUserData
– User defined data pointer to provide to the failure handler callback
- Members within the module root should be freestanding
- The real power within DI is to isolate dependencies
- The module root should not contain any dependencies. Ideally the module root should only contain types supported by your freestanding C standard, like C99 or C11. This enables highly portable modules.
- Implementation details and dependencies belong in the module derivations
Implementing a Module: Derivations
- Concrete implementations for a module are created through deriving the module.
- A derivation is guranteed to have the module root as the the first member. Module derivations can always be safely up-cast to the module root.
- The module derivations can contain implementation specific details, dependencies, and other private memebers.
- You can think of the members placed within the derivation as "private" in C++ terms
The Module
Now with a background on the module root and module derivations, we can talk about the module.
- The module is a union of all possible derivations, including the root.
- The module is forward-declared. Module implementations will provide a default implementation of the module that can be overridden when
..._CUSTOM
is defined.
- The user of the module would define
..._CUSTOM
if they want polymorphic behavior.
- API traits are provided a pointer to the module.
How to Define The Module Union
Below is an example of defining a module union:
union MY_MODULE_T
JUNO_MODULE(MY_MODULE_API_T, MY_MODULE_ROOT_T,
MY_MODULE_DERIVATION_1_T;
MY_MODULE_DERIVATION_2_T;
MY_MODULE_DERIVATION_3_T;
);
#define JUNO_MODULE(API_T, ROOT_T, derived)
Definition module.h:154