# api_registry.h ## Index
`struct tm_api_registry_listener_i`
`ud`
`add_implementation()`

`TM_API_REGISTRY_API_NAME`

`struct tm_api_registry_api`
`set()`
`remove()`
`get()`
`get_optional()`
`add_implementation()`
`remove_implementation()`
`implementations()`
`add_listener()`
`static_variable()`
`log_missing_apis()`

`tm_set_or_remove_api()`
`tm_add_or_remove_implementation()`
`tm_load_function`
`tm_global_api_registry`
`tm_init_global_api_registry()`
`tm_shutdown_global_api_registry()`
`tm_register_all_foundation_apis()`
## API
### `struct tm_api_registry_listener_i`
Listener for receiving information about changes to the API registry. Use `add_listener()` to add a listener to the API registry. #### `ud` ~~~c void *ud; ~~~ #### `add_implementation()` ~~~c void (*add_implementation)(void *ud, const char *name, void *implementation); ~~~ Called when an implementation was added for the interface `name`.
### `TM_API_REGISTRY_API_NAME`
~~~c #define TM_API_REGISTRY_API_NAME "tm_api_registry_api" ~~~
### `struct tm_api_registry_api`
Global registry that keeps track of loaded APIs and interface implementations. The difference between an API and an interface is that APIs only have a single implementation, whereas interfaces can have many implementations. For example the OS API `tm_os_api` provides the implementation of OS functions to access files, memory, etc. It only has a single implementation for each supported platform, and it is this implementation you call upon to perform OS functions. In contrast, each module that supports unit tests implements the `tm_unit_test_i` interface. By querying for the `tm_unit_test_i` interface, you can enumerate all these implementations and run all the unit tests. #### `set()` ~~~c void (*set)(const char *name, void *api, uint32_t bytes); ~~~ Sets an API in the registry. `name` is the name of the API that is implemented and `api` is a pointer to the struct of function pointers defining the API. `bytes` is the size of this struct. APIs can be implemented only once. If you call `set()` again, it replaces the previous API pointers. This can be used to implement hot-reload of APIs. #### `remove()` ~~~c void (*remove)(void *api); ~~~ Removes `API` if it is in use. #### `get()` ~~~c void *(*get)(const char *name); ~~~ Gets a pointer to the API implementing the API `name`. `get(name)` is guaranteed to always return the same pointer, throughout the lifetime of an application (whether `set(name)` has been called zero, one or multiple times). It returns a pointer to internal API registry memory and the actual API pointers are copied to this memory by `set()`. On hot-reload these function pointers will be overwritten, but this is transparent to users of the API. They can continue to use the same interface pointer and will call the new methods automatically. (If they have cached the function pointers in the API locally, they will keep calling the old methods.) Calling `get()` on an API that hasn't been loaded yet will return a struct full of NULL function pointers. When the API is loaded (and calls `set()`), these NULL pointers will be replaced by the real function pointers of the API. To test whether an API has been loaded, you can test if it contains NULL function pointers or not. #### `get_optional()` ~~~c void *(*get_optional)(const char *name); ~~~ As `get()`, but indicates that this is an optional API, i.e. we will be able to continue to run even if this API is not available. #### `add_implementation()` ~~~c void (*add_implementation)(const char *name, void *implementation); ~~~ Adds an implementation of the interface named `name`. #### `remove_implementation()` ~~~c void (*remove_implementation)(const char *name, void *implementation); ~~~ Removes the specified implementation of the interface `name`. #### `implementations()` ~~~c void **(*implementations)(const char *name, uint32_t *count); ~~~ Returns an array of all the implementations implementing the interface `name`. The size of the array is returned in `count`. !!! TODO: API-REVIEW This function is kind of annoying to call, either improve this interface or provide an alternative one. #### `add_listener()` ~~~c void (*add_listener)(const tm_api_registry_listener_i *listener); ~~~ Adds a listener that will be called with changes to the api_registry. Currently, only an `add_implementation` callback is provided. #### `static_variable()` ~~~c void *(*static_variable)(tm_strhash_t id, uint32_t size, const char *file, uint32_t line); ~~~ Returns a pointer to a static variable that survives plugin reloads. `id` is a unique identifier for the variable and `size` its size in bytes. The first time this function is called, the variable will be zero-initialized. Use of static variables in DLLs can be problematic, because when the DLL is reloaded, the new instance of the DLL will get a new freshly initialized static variable, losing whatever content the variable had before reload. By using `static_variable()` instead, the variable data is saved in permanent memory. Instead of this: ~~~c dont uint64_t count; void f() { ++count; } ~~~ You would do this: ~~~c uint64_t *count_ptr; void load(struct tm_api_registry_api *reg) { count_ptr = (uint64_t *)reg->static_variable(TM_STATIC_HASH("my_count", 0xa287d4b3ec9c2109ULL), sizeof(uint64_t), __FILE__, __LINE__); } void f() { ++*count_ptr; } ~~~ #### `log_missing_apis()` ~~~c void (*log_missing_apis)(void); ~~~ Print a log message about APIs that were requested with `get()` but were never found.
### `tm_set_or_remove_api()`
~~~c #define tm_set_or_remove_api(reg, load, name, ptr) ~~~ Convenience macro that either sets or remove an api based on value of `load` flag.
### `tm_add_or_remove_implementation()`
~~~c #define tm_add_or_remove_implementation(reg, load, name, ptr) ~~~ Convenience macro that either adds or removes an implementation based on value of `load` flag.
### `tm_load_function`
~~~c typedef void tm_load_function(struct tm_api_registry_api *reg, bool load); ~~~ Function type for loading plugins or subparts of plugins.
### `tm_global_api_registry`
Extern variable holding the global plugin registry. ~~~c extern struct tm_api_registry_api *tm_global_api_registry; ~~~
### `tm_init_global_api_registry()`
~~~c void tm_init_global_api_registry(struct tm_allocator_i *a); ~~~ Inits the global registry. You must call this before using the `tm_global_api_registry` variable.
### `tm_shutdown_global_api_registry()`
~~~c void tm_shutdown_global_api_registry(struct tm_allocator_i *a); ~~~ Shuts down the global registry. You must call this to free the resources allocated by `tm_init_global_api_registry()`.
### `tm_register_all_foundation_apis()`
~~~c void tm_register_all_foundation_apis(struct tm_api_registry_api *pr); ~~~ Convenience function to register all foundation APIs in the specified registry.