LibJuno 0.42.0
LibJuno is a lightweight C99 library designed specifically for embedded systems.
Loading...
Searching...
No Matches
module.h File Reference
#include "status.h"
#include <stdint.h>
Include dependency graph for module.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Macros

The name of the module type

DOC

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,...)
Definition module.h:161

Declare a juno module implemented as a union

#define JUNO_MODULE_DECLARE(NAME_T)   typedef union NAME_T NAME_T
 
#define JUNO_MODULE_ROOT_DECLARE(NAME_T)   typedef struct NAME_T NAME_T
 
#define JUNO_MODULE_DERIVE_DECLARE(NAME_T)   JUNO_MODULE_ROOT_DECLARE(NAME_T)
 
#define JUNO_FAILURE_HANDLER   _pfcnFailureHandler
 
#define JUNO_FAILURE_USER_DATA   _pvFailureUserData
 
#define JUNO_MODULE_EMPTY
 
#define JUNO_MODULE_ARG(...)   __VA_ARGS__
 
#define JUNO_MODULE_SUPER   tRoot
 
#define JUNO_MODULE(API_T, ROOT_T, ...)
 
#define JUNO_MODULE_ROOT(API_T, ...)
 
#define JUNO_MODULE_DERIVE(ROOT_T, ...)
 
#define JUNO_MODULE_GET_API(ptModule, ROOT_T)   ((const ROOT_T *)ptModule)->ptApi
 
#define JUNO_MODULE_RESULT(NAME_T, SUCCESS_T)
 Defines a result type combining a status and a success payload.
 
#define JUNO_RESULT(SUCCESS_T)
 
#define JUNO_MODULE_OPTION(NAME_T, SOME_T)
 Defines an option type combining a flag to indicate some and a success payload.
 
#define JUNO_OPTION(SOME_T)
 

Macro Definition Documentation

◆ JUNO_FAILURE_HANDLER

#define JUNO_FAILURE_HANDLER   _pfcnFailureHandler

Alias for the failure handler for a module

◆ JUNO_FAILURE_USER_DATA

#define JUNO_FAILURE_USER_DATA   _pvFailureUserData

Alias for the failure handler user data for a module

◆ JUNO_MODULE

#define JUNO_MODULE (   API_T,
  ROOT_T,
  ... 
)
Value:
{ \
const API_T *ptApi; \
__VA_ARGS__ \
}
#define JUNO_MODULE_SUPER
Definition module.h:139

Define a juno module. This needs to be done in the composition root. This is where users define all possible module implementations for a module.

Example:

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;
);
Parameters
nameThe name of the module as declared
APIThe name of the API type for the module
rootThe name of the root implementation type for the module as declared
derivedThe derived modules seperated by ;

◆ JUNO_MODULE_ARG

#define JUNO_MODULE_ARG (   ...)    __VA_ARGS__

A macro to provide template types as arguments to Juno module macros

◆ JUNO_MODULE_DECLARE

#define JUNO_MODULE_DECLARE (   NAME_T)    typedef union NAME_T NAME_T

◆ JUNO_MODULE_DERIVE

#define JUNO_MODULE_DERIVE (   ROOT_T,
  ... 
)
Value:
{ \
__VA_ARGS__ \
}

Implement a derivation of a module Example:

struct MY_MODULE_DERIVED_T JUNO_MODULE(MY_MODULE_ROOT_T,
int iExampleSpecificMember;
SOME_DEPENEDENCY_T tSomeDep;
);
Parameters
nameThe name of the module derivation as declared
rootThe name of the root implementation for the module as declared
membersThe member components of the module derivation

◆ JUNO_MODULE_DERIVE_DECLARE

#define JUNO_MODULE_DERIVE_DECLARE (   NAME_T)    JUNO_MODULE_ROOT_DECLARE(NAME_T)

Declare a derivation of a juno module implemented as a struct

Parameters
nameThe name of the derived module type

◆ JUNO_MODULE_EMPTY

#define JUNO_MODULE_EMPTY

Empty macro that indicates a module implementation has no additional members

◆ JUNO_MODULE_GET_API

#define JUNO_MODULE_GET_API (   ptModule,
  ROOT_T 
)    ((const ROOT_T *)ptModule)->ptApi

Get the API pointer from the module

Parameters
ptModuleThe module pointer
MODULE_ROOT_NAMEThe root type of the module

◆ JUNO_MODULE_OPTION

#define JUNO_MODULE_OPTION (   NAME_T,
  SOME_T 
)
Value:
typedef struct NAME_T \
{ \
bool bIsSome; \
SOME_T tSome; \
} NAME_T

Defines an option type combining a flag to indicate some and a success payload.

Parameters
NAME_TName of the result struct to define.
SUCCESS_TType of the success payload contained in the result.

◆ JUNO_MODULE_RESULT

#define JUNO_MODULE_RESULT (   NAME_T,
  SUCCESS_T 
)
Value:
typedef struct NAME_T \
{ \
JUNO_STATUS_T tStatus; \
SUCCESS_T tSuccess; \
} NAME_T
enum JUNO_STATUS_TAG JUNO_STATUS_T

Defines a result type combining a status and a success payload.

Parameters
NAME_TName of the result struct to define.
SUCCESS_TType of the success payload contained in the result.

◆ JUNO_MODULE_ROOT

#define JUNO_MODULE_ROOT (   API_T,
  ... 
)
Value:
{ \
const API_T *ptApi; \
__VA_ARGS__ \
JUNO_FAILURE_HANDLER_T JUNO_FAILURE_HANDLER; \
}
#define JUNO_FAILURE_USER_DATA
Definition module.h:121
#define JUNO_FAILURE_HANDLER
Definition module.h:117
void JUNO_USER_DATA_T
Definition status.h:43

Implement a root for a module Example:

struct MY_MODULE_ROOT_T JUNO_MODULE(MY_MODULE_API_T,
uint32_t iExampleRoot1Member;
uint32_t iExampleRoot2Member;
uint32_t iExampleRoot3Member;
);
Parameters
nameThe name of the module root implementation as declared
APIThe API type for the module
membersThe member components of the module root implementation

◆ JUNO_MODULE_ROOT_DECLARE

#define JUNO_MODULE_ROOT_DECLARE (   NAME_T)    typedef struct NAME_T NAME_T

Declare a root implementation for the module implemented as a struct

Parameters
nameThe name of the root implementation type

◆ JUNO_MODULE_SUPER

#define JUNO_MODULE_SUPER   tRoot

Alias for the module root implementation. All modules can call .tRoot to access the module root.

◆ JUNO_OPTION

#define JUNO_OPTION (   SOME_T)
Value:
{ \
bool bIsSome; \
SOME_T tSome; \
}

◆ JUNO_RESULT

#define JUNO_RESULT (   SUCCESS_T)
Value:
{ \
JUNO_STATUS_T tStatus; \
SUCCESS_T tSuccess; \
}