libGimbal 0.2.0
C17-Based Extended Standard Library and Cross-Language Runtime Framework
Loading...
Searching...
No Matches
gimbal_module.h
Go to the documentation of this file.
1/*! \file
2 * \brief Dynamic module and plugin system.
3 * \ingroup core
4 *
5 * This file contains the type declarations of GblModule
6 * and its associated API, providing the functionality of
7 * a static registry of lazily loaded "services" or C++
8 * singleton types and their associated type registry.
9 *
10 * \todo
11 * - advanced unit testing
12 * - plan out type registration/management
13 * - rig up option group parsery
14 * - stop inheriting GblContext
15 *
16 * \author 2023, 2025 Falco Girgis
17 * \author 2025 Agustín Bellagamba
18 * \copyright MIT License
19 */
20#ifndef GIMBAL_MODULE_H
21#define GIMBAL_MODULE_H
22
23#include "../meta/instances/gimbal_context.h"
24#include "../meta/ifaces/gimbal_iplugin.h"
25#include "../strings/gimbal_string_ref.h"
26#include "../utils/gimbal_version.h"
27#include "../utils/gimbal_option_group.h"
28
29/*! \name Type System
30 * \brief Type UUID and cast operators.
31 * @{
32 */
33#define GBL_MODULE_TYPE GBL_TYPEID(GblModule) //!< Type UUID for GblModule
34#define GBL_MODULE(self) GBL_CAST(GblModule, self) //!< Function-style GblInstance cast
35#define GBL_MODULE_CLASS(klass) GBL_CLASS_CAST(GblModule, klass) //!< Function-style GblClass cast
36#define GBL_MODULE_CLASSOF(self) GBL_CLASSOF(GblModule, self) //!< Gets a GblModuleClass from GblInstance
37//! @}
38
39/*! Macro directive for importing a module.
40 *
41 * Used to "import" a GblModule whose type has been registered with the type system,
42 * lazily loading it the fist time and returning references to it subsequently.
43 *
44 * \note
45 * If the supplied pointer is non-NULL, the module is considered cached and is not going
46 * to be reloaded. This allows you to avoid dynamic lookups for subsequent calls when using
47 * the same pointer.
48 *
49 * \code {.c}
50 * static MyModule* pModule = NULL;
51 * if(!GBL_REQUIRE(MyModule, &pModule, "MyModule", "1.1.0"))
52 * GBL_LOG_ERROR("MyModule", "Failed to import module!");
53 * \endcode
54 *
55 * \param instanceStruct Struct name for desired GblModule instance structure.
56 * \param selfAddr The address of a pointer to the instance to store the reference in.
57 * \param name Name of the module to import.
58 * \param version [optional] Major.minor.patch string for specific version.
59 *
60 * \returns A pointer to the imported module, or NULL if the import failed.
61 */
62#define GBL_REQUIRE(/*instanceStruct, selfAddr, name, versionMin=NULL*/ ...) GBL_REQUIRE_(__VA_ARGS__)
63
64/*! Macro directive for releasing a module.
65 *
66 * Used to optionally "release" a module which has been previously
67 * imported, decrementing is "useCount" property, which causes the
68 * module to be dynamically unloaded upon hitting zero uses.
69 *
70 * \note
71 * This does not necessarily need to be called if you do not wish for
72 * your module to be dynamically unloaded at run-time.
73 *
74 * \param selfAddr The address of a pointer pointing to a module.
75 * \returns GBL_RESULT status code.
76 */
77#define GBL_RELEASE(selfAddr) GBL_RELEASE_(selfAddr)
78
79/*! Scoped macro directive for using a module.
80 *
81 * Used to define a local scope in which a module will be imported upon
82 * entry and released upon exit.
83 *
84 * \code {.c}
85 * TestModule* pModule = NULL;
86 * GBL_REQUIRE_SCOPE(TestModule, &pModule) {
87 * TestModule_doStuff(pModule);
88 * }
89 * \endcode
90 *
91 * \warning
92 * GBL_SCOPE_EXIT must be used to early-break from the scope without
93 * causing unwanted side-effects.
94 *
95 * \param instanceStruct Struct name for desired GblModule instance structure.
96 * \param selfAddr Address of a pointer to the GblModule struct, which holds the reference.
97 * \param name Name of the module to import.
98 * \param version [optional] Major.minor.patch string for specific version.
99 */
100#define GBL_REQUIRE_SCOPE(/*instanceStruct, selfAddr, name, versionMin=NULL*/ ...) GBL_REQUIRE_SCOPE_(__VA_ARGS__)
101
102#define GBL_SELF_TYPE GblModule
103
105
106GBL_FORWARD_DECLARE_STRUCT(GblOptionGroup);
108
109//! Function callback used with GblModule_foreach() for iterating over active modules, returning GBL_TRUE to end iteration early.
110typedef GblBool (*GblModuleIterFn)(GblModule* pIt, void* pClosure);
111
112/*! \struct GblModuleClass
113 * \extends GblContextClass
114 * \implements GblIPluginClass
115 * \brief GblClass structure for GblModule
116 *
117 * Virtual method table for GblModule
118 * - inherits from GblContext
119 * - has to implement GblIPlugin's VTable
120 * - adds pure virtaul methods load/unload
121 *
122 * \sa GblModule, GblIPluginClass
123 */
124GBL_CLASS_DERIVE(GblModule, GblContext, GblIPlugin)
125 GBL_RESULT (*pFnLoad) (GBL_SELF); //!< Called when a GblModule is first loaded
126 GBL_RESULT (*pFnUnload)(GBL_SELF); //!< Called after the GblModule is done being referenced
128
129/*! \struct GblModule
130 * \ingroup core
131 * \extends GblContext
132 * \implements GblIPlugin
133 * \brief Dynamically loadable service and associated meta types.
134 *
135 * A Module is a lazily-loaded object which is registered then later
136 * can be queried for by anywhere else in the application. This
137 * behavior lets you implement "services" as global singletons which
138 * can be accessed from anywhere. Modules also maintain their own inner
139 * registry of associated meta types, which is managed through the
140 * implemented GblIPlugin interface.
141 *
142 * \sa GbModuleClass, GblIPlugin
143 */
145 GblVersion version; //!< Version of a module
146 GblStringRef* pPrefix; //!< Namespace prefix of a module
147 GblStringRef* pAuthor; //!< Author(s) of a module
148 GblStringRef* pDescription; //!< Description of a module
149 GblOptionGroup* pOptionGroup; //!< Command-line option handler of a module
151
152//! \cond
153GBL_PROPERTIES(GblModule,
154 (prefix, GBL_GENERIC, (READ, WRITE, LOAD, SAVE), GBL_STRING_TYPE),
155 (version, GBL_GENERIC, (READ, WRITE, LOAD, SAVE), GBL_UINT32_TYPE),
156 (author, GBL_GENERIC, (READ, WRITE, LOAD, SAVE), GBL_STRING_TYPE),
157 (description, GBL_GENERIC, (READ, WRITE, LOAD, SAVE), GBL_STRING_TYPE),
158 (optionGroup, GBL_GENERIC, (READ, WRITE, LOAD, SAVE, ACQUIRE), GBL_OPTION_GROUP_TYPE),
159 (useCount, GBL_GENERIC, (READ), GBL_INT16_TYPE)
160)
161
162GBL_SIGNALS(GblModule,
163 (loaded),
164 (unloaded)
165)
166//! \endcond
167
168//! Returns the GblType UUID associated with GblModule.
170
171/*! \name Registry
172 * \brief Static routines for querying the module registry.
173 * @{
174 */
175//! Returns a pointer to the module with the gibven name, if present, gracefully returning NULL otherwise.
176GBL_EXPORT GblModule* GblModule_find (const char* pName) GBL_NOEXCEPT;
177//! Equivalent to GblModule_find(), except doing a faster search using a GblQuark for the name.
179//! Returns a pointer to the GblModule which has been loaded at the given index, or NULL if there isn't one.
180GBL_EXPORT GblModule* GblModule_at (size_t index) GBL_NOEXCEPT;
181//! Returns the total number of modules which have been registered.
183//! Iterates over every registered module, invoking the provided iterator callback, optionally passing back an arbitrary userdata closure pointer.
184GBL_EXPORT GblBool GblModule_iterate (GblModuleIterFn pFnIter,
185 void* pCl/*=NULL*/) GBL_NOEXCEPT;
186//! @}
187
188/*! \name Opening and Closing
189 * \brief Routines for acquiring and releasing a module.
190 * @{
191 */
192//! Underlying method backing GBL_REQUIRE() macro, which should be used instead of calling this directly.
193GBL_EXPORT GblModule* GblModule_require (GblModule** ppSelf,
194 const char* pName,
195 const char* pVersion/*=NULL*/,
196 const char* pFile/*=__FILE__*/,
197 const char* pFunc/*=__func__*/,
198 size_t line/*=__LINE__*/) GBL_NOEXCEPT;
199//! Equivalent to GblModule_require(), except using a faster quark for the name identifier.
200GBL_EXPORT GblModule* GblModule_requireQuark (GblModule** ppSelf,
201 GblQuark name,
202 const char* pVersion/*=NULL*/,
203 const char* pFile/*=__FILE__*/,
204 const char* pFunc/*=__func__*/,
205 size_t line/*=__LINE__*/) GBL_NOEXCEPT;
206//! Manually decrements the given module's usage count, and points the passed \param ppModule to NULL.
207GBL_EXPORT GBL_RESULT GblModule_release (GblModule** ppModule) GBL_NOEXCEPT;
208//! @}
209
210/*! \name Lifetime
211 * \brief Methods for creating and destroying modules.
212 * @{
213 */
214//! Creates and returns a reference to a new GblModule-compatible instance type, but does not add it to the registry.
215GBL_EXPORT GblModule* GblModule_create (GblType derivedType,
216 const char* pName,
217 GblVersion version,
218 const char* pAuthor,
219 const char* pDescription,
220 const char* pPrefix) GBL_NOEXCEPT;
221//! Releases a reference to a previously created GblModule instance, destructing and freeing it if there are no references left.
223//! @}
224
225/*! \name Registration
226 * \brief Methods for adding and removing from the registry.
227 * @{
228 */
229//! Attempts to register a previously instantiated GblModule instance as a globally importable module within the internal registry.
231//! Attempts to unregister a previously registered GblModule instance, removing it from the internal registry.
233//! @}
234
235/*! \name Loading/Unloading
236 * \brief Routines for controlling when a module is loaded and unloaded.
237 * @{
238 */
239//! Manually increments the given module's usage count, loading it on first usage. You can manually control its lifetimeto prevent being dynamically unloaded like this.
241//! Manually decrements the given module's usage count, unloading it when the last user is done. You can manually control unloading it like this.
243//! Retrieves the current usage counter for the given module.
245//! Returns true if the given module is currently loaded and has active uses, return false otherwise.
247//! @}
248
250
251// ====== IMPLEMENTATION =====
252///\cond
253#define GBL_REQUIRE_(...)
254 GBL_REQUIRE_DEFAULT_(__VA_ARGS__)
255#define GBL_REQUIRE_DEFAULT_(...)
256 GBL_REQUIRE_DEFAULT__(__VA_ARGS__, NULL)
257#define GBL_REQUIRE_DEFAULT__(type, pPtr, name, version, ...)
258 GBL_AS(type, (GblModule_require(
259 (GblModule**)pPtr, name, version,
260 __FILE__, __func__, __LINE__)))
261
262#define GBL_RELEASE_(pPtr)
263 (GblModule_release((GblModule**)pPtr))
264
265#define GBL_REQUIRE_SCOPE_(...)
266 GBL_REQUIRE_SCOPE_DEFAULT_(__VA_ARGS__)
267#define GBL_REQUIRE_SCOPE_DEFAULT_(...)
268 GBL_REQUIRE_SCOPE_DEFAULT__(__VA_ARGS__, NULL)
269#define GBL_REQUIRE_SCOPE_DEFAULT__(type, pPtr, name, version, ...)
270 GBL_SCOPE(GBL_REQUIRE_DEFAULT__(type, pPtr, name, version), GBL_RELEASE_(pPtr))
271
272#define GblModule_iterate(...)
273 GblModule_iterateDefault_(__VA_ARGS__)
274#define GblModule_iterateDefault_(...)
275 GblModule_iterateDefault__(__VA_ARGS__, NULL)
276#define GblModule_iterateDefault__(iter, cl, ...)
277 (GblModule_iterate)(iter, cl)
278
279///\endcond
280
281#undef GBL_SELF_TYPE
282
283#endif // GIMBAL_MODULE_H
#define GBL_NOEXCEPT
#define GBL_DECLS_BEGIN
#define GBL_FORWARD_DECLARE_STRUCT(S)
#define GBL_TYPEID(instanceStruct)
#define GBL_INSTANCE_DERIVE(derivedInstance, baseInstance)
#define GBL_CLASS_DERIVE(...)
#define GBL_INSTANCE_END
#define GBL_EXPORT
#define GBL_CLASS_END
#define GBL_SCOPE(begin, end)
GBL_RESULT GblModule_unregister(GblModule *pSelf)
Attempts to unregister a previously registered GblModule instance, removing it from the internal regi...
GblModule * GblModule_at(size_t index)
Returns a pointer to the GblModule which has been loaded at the given index, or NULL if there isn't o...
GblModule * GblModule_require(GblModule **ppSelf, const char *pName, const char *pVersion, const char *pFile, const char *pFunc, size_t line)
Underlying method backing GBL_REQUIRE() macro, which should be used instead of calling this directly.
size_t GblModule_count(void)
Returns the total number of modules which have been registered.
GBL_RESULT GblModule_unuse(GblModule *pSelf)
Manually decrements the given module's usage count, unloading it when the last user is done....
GblRefCount GblModule_unref(GblModule *pSelf)
Releases a reference to a previously created GblModule instance, destructing and freeing it if there ...
GblModule * GblModule_create(GblType derivedType, const char *pName, GblVersion version, const char *pAuthor, const char *pDescription, const char *pPrefix)
Creates and returns a reference to a new GblModule-compatible instance type, but does not add it to t...
GBL_RESULT GblModule_release(GblModule **ppModule)
Manually decrements the given module's usage count, and points the passed.
GblModule * GblModule_find(const char *pName)
Returns a pointer to the module with the gibven name, if present, gracefully returning NULL otherwise...
GblRefCount GblModule_useCount(const GblModule *pSelf)
Retrieves the current usage counter for the given module.
GblBool GblModule_isLoaded(const GblModule *pSelf)
Returns true if the given module is currently loaded and has active uses, return false otherwise.
GblModule * GblModule_findQuark(GblQuark name)
Equivalent to GblModule_find(), except doing a faster search using a GblQuark for the name.
GBL_RESULT GblModule_register(GblModule *pSelf)
Attempts to register a previously instantiated GblModule instance as a globally importable module wit...
GblBool GblModule_iterate(GblModuleIterFn pFnIter, void *pCl)
Iterates over every registered module, invoking the provided iterator callback, optionally passing ba...
GblModule * GblModule_requireQuark(GblModule **ppSelf, GblQuark name, const char *pVersion, const char *pFile, const char *pFunc, size_t line)
Equivalent to GblModule_require(), except using a faster quark for the name identifier.
GblType GblModule_type(void)
Returns the GblType UUID associated with GblModule.
GBL_RESULT GblModule_use(GblModule *pSelf)
Manually increments the given module's usage count, loading it on first usage. You can manually contr...
#define GBL_OPTION_GROUP_TYPE
Type UUID for GblOptionGroup.
#define GBL_INT16_TYPE
Builtin ID for int16_t GblVariant type.
#define GBL_STRING_TYPE
Builtin ID for string GblVariant type.
#define GBL_UINT32_TYPE
Builtin ID for uint32_t GblVariant type.
#define GBL_PROPERTIES(object,...)
Declares a list of properties for the given object/instance structure.
#define GBL_SIGNALS(instanceStruct,...)
Declares a list of signals to be associated with the given instanceStruct.
uint8_t GblBool
Basic boolean type, standardized to sizeof(char)
uint16_t GblRefCount
Type able to hold a reference counter across the codebase.
uintptr_t GblType
Meta Type UUID.
Definition gimbal_type.h:52
uintptr_t GblQuark
Uniquely identifiable interned string type.
const char GblStringRef
Reference-counted, const char*-compatible string type.
uint32_t GblVersion
32-bit unsigned integer representing a packed version in the form (MAJOR.MINOR.PATCH)
Dynamically loadable service and associated meta types.
GblStringRef * pDescription
Description of a module.
GblStringRef * pAuthor
Author(s) of a module.
GblStringRef * pPrefix
Namespace prefix of a module.
GblOptionGroup * pOptionGroup
Command-line option handler of a module.
GblVersion version
Version of a module.